pax_global_header00006660000000000000000000000064144731173250014521gustar00rootroot0000000000000052 comment=f612e2f0830f459fc5d2a2fa6004e7c8d2ebf03f commons-dbcp-rel-commons-dbcp-2.10.0/000077500000000000000000000000001447311732500173215ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/.asf.yaml000066400000000000000000000025301447311732500210340ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. github: description: "Apache Commons DBCP" homepage: https://commons.apache.org/dbcp/ notifications: commits: commits@commons.apache.org issues: issues@commons.apache.org pullrequests: issues@commons.apache.org jira_options: link label jobs: notifications@commons.apache.org issues_bot_dependabot: notifications@commons.apache.org pullrequests_bot_dependabot: notifications@commons.apache.org issues_bot_codecov-commenter: notifications@commons.apache.org pullrequests_bot_codecov-commenter: notifications@commons.apache.org commons-dbcp-rel-commons-dbcp-2.10.0/.github/000077500000000000000000000000001447311732500206615ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/.github/GH-ROBOTS.txt000066400000000000000000000016331447311732500227310ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Keeps on creating FUD PRs in test code # Does not follow Apache disclosure policies User-agent: JLLeitschuh/security-research Disallow: * commons-dbcp-rel-commons-dbcp-2.10.0/.github/dependabot.yml000066400000000000000000000020061447311732500235070ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT 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: 2 updates: - package-ecosystem: "maven" directory: "/" schedule: interval: "weekly" day: "friday" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" day: "friday" commons-dbcp-rel-commons-dbcp-2.10.0/.github/workflows/000077500000000000000000000000001447311732500227165ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/.github/workflows/codeql-analysis.yml000066400000000000000000000062701447311732500265360ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: "CodeQL" on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '33 9 * * 4' permissions: contents: read jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'java' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support steps: - name: Checkout repository uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4 commons-dbcp-rel-commons-dbcp-2.10.0/.github/workflows/coverage.yml000066400000000000000000000034421447311732500252370ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: Coverage on: [push, pull_request] permissions: contents: read jobs: build: runs-on: ubuntu-latest strategy: matrix: java: [ 8 ] steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Set up JDK ${{ matrix.java }} uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Build with Maven run: mvn -V test jacoco:report --file pom.xml --no-transfer-progress - name: Upload coverage to Codecov uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 with: files: ./target/site/jacoco/jacoco.xml commons-dbcp-rel-commons-dbcp-2.10.0/.github/workflows/maven.yml000066400000000000000000000034611447311732500245530ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: Java CI on: [push, pull_request] permissions: contents: read jobs: build: runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental }} strategy: matrix: java: [ 8, 11, 17 ] experimental: [false] # include: # - java: 18-ea # experimental: true steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Set up JDK ${{ matrix.java }} uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Build with Maven run: mvn -V --file pom.xml --no-transfer-progress commons-dbcp-rel-commons-dbcp-2.10.0/.github/workflows/scorecards-analysis.yml000066400000000000000000000047451447311732500274240ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache license, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the license for the specific language governing permissions and # limitations under the license. name: "Scorecards supply-chain security" on: branch_protection_rule: schedule: - cron: "30 1 * * 6" # Weekly on Saturdays push: branches: [ "master" ] permissions: read-all jobs: analysis: name: "Scorecards analysis" runs-on: ubuntu-latest permissions: # Needed to upload the results to the code-scanning dashboard. security-events: write actions: read id-token: write # This is required for requesting the JWT contents: read # This is required for actions/checkout steps: - name: "Checkout code" uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # 2.2.0 with: results_file: results.sarif results_format: sarif # A read-only PAT token, which is sufficient for the action to function. # The relevant discussion: https://github.com/ossf/scorecard-action/issues/188 repo_token: ${{ secrets.GITHUB_TOKEN }} # Publish the results for public repositories to enable scorecard badges. # For more details: https://github.com/ossf/scorecard-action#publishing-results publish_results: true - name: "Upload artifact" uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # 3.1.0 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@a09933a12a80f87b87005513f0abb1494c27a716 # 2.21.4 with: sarif_file: results.sarif commons-dbcp-rel-commons-dbcp-2.10.0/.gitignore000066400000000000000000000003771447311732500213200ustar00rootroot00000000000000target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next release.properties site-content /.checkstyle /.classpath /.pmd /.project /.settings /ObjectStore/ /bin/ # no IDE stuff in our SCM .classpath .settings .idea *.iml .nbproject commons-dbcp-rel-commons-dbcp-2.10.0/CODE_OF_CONDUCT.md000066400000000000000000000016411447311732500221220ustar00rootroot00000000000000 The Apache code of conduct page is [https://www.apache.org/foundation/policies/conduct.html](https://www.apache.org/foundation/policies/conduct.html). commons-dbcp-rel-commons-dbcp-2.10.0/CONTRIBUTING.md000066400000000000000000000145661447311732500215660ustar00rootroot00000000000000 Contributing to Apache Commons DBCP ====================== You have found a bug or you have an idea for a cool new feature? Contributing code is a great way to give something back to the open source community. Before you dig right into the code there are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. Getting Started --------------- + Make sure you have a [JIRA account](https://issues.apache.org/jira/). + Make sure you have a [GitHub account](https://github.com/signup/free). + If you're planning to implement a new feature it makes sense to discuss your changes on the [dev list](https://commons.apache.org/mail-lists.html) first. This way you can make sure you're not wasting your time on something that isn't considered to be in Apache Commons DBCP's scope. + Submit a [Jira Ticket][jira] for your issue, assuming one does not already exist. + Clearly describe the issue including steps to reproduce when it is a bug. + Make sure you fill in the earliest version that you know has the issue. + Find the corresponding [repository on GitHub](https://github.com/apache/?query=commons-), [fork](https://help.github.com/articles/fork-a-repo/) and check out your forked repository. Making Changes -------------- + Create a _topic branch_ for your isolated work. * Usually you should base your branch on the `master` branch. * A good topic branch name can be the JIRA bug id plus a keyword, e.g. `DBCP-123-InputStream`. * If you have submitted multiple JIRA issues, try to maintain separate branches and pull requests. + Make commits of logical units. * Make sure your commit messages are meaningful and in the proper format. Your commit message should contain the key of the JIRA issue. * e.g. `DBCP-123: Close input stream earlier` + Respect the original code style: + Only use spaces for indentation. + Create minimal diffs - disable _On Save_ actions like _Reformat Source Code_ or _Organize Imports_. If you feel the source code should be reformatted create a separate PR for this change first. + Check for unnecessary whitespace with `git diff` -- check before committing. + Make sure you have added the necessary tests for your changes, typically in `src/test/java`. + Run all the tests with `mvn clean verify` to assure nothing else was accidentally broken. Making Trivial Changes ---------------------- The JIRA tickets are used to generate the changelog for the next release. For changes of a trivial nature to comments and documentation, it is not always necessary to create a new ticket in JIRA. In this case, it is appropriate to start the first line of a commit with '(doc)' instead of a ticket number. Submitting Changes ------------------ + Sign and submit the Apache [Contributor License Agreement][cla] if you haven't already. * Note that small patches & typical bug fixes do not require a CLA as clause 5 of the [Apache License](https://www.apache.org/licenses/LICENSE-2.0.html#contributions) covers them. + Push your changes to a topic branch in your fork of the repository. + Submit a _Pull Request_ to the corresponding repository in the `apache` organization. * Verify _Files Changed_ shows only your intended changes and does not include additional files like `target/*.class` + Update your JIRA ticket and include a link to the pull request in the ticket. If you prefer to not use GitHub, then you can instead use `git format-patch` (or `svn diff`) and attach the patch file to the JIRA issue. Additional Resources -------------------- + [Contributing patches](https://commons.apache.org/patches.html) + [Apache Commons DBCP JIRA project page][jira] + [Contributor License Agreement][cla] + [General GitHub documentation](https://help.github.com/) + [GitHub pull request documentation](https://help.github.com/articles/creating-a-pull-request/) + [Apache Commons Twitter Account](https://twitter.com/ApacheCommons) + `#apache-commons` IRC channel on `irc.freenode.net` [cla]:https://www.apache.org/licenses/#clas [jira]:https://issues.apache.org/jira/browse/DBCP commons-dbcp-rel-commons-dbcp-2.10.0/LICENSE.txt000066400000000000000000000261361447311732500211540ustar00rootroot00000000000000 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. commons-dbcp-rel-commons-dbcp-2.10.0/NOTICE.txt000066400000000000000000000002561447311732500210460ustar00rootroot00000000000000Apache Commons DBCP Copyright 2001-2023 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (https://www.apache.org/). commons-dbcp-rel-commons-dbcp-2.10.0/README.md000066400000000000000000000327771447311732500206200ustar00rootroot00000000000000 Apache Commons DBCP =================== [![GitHub Actions Status](https://github.com/apache/commons-dbcp/workflows/Java%20CI/badge.svg)](https://github.com/apache/commons-dbcp/actions) [![Coverage Status](https://codecov.io/gh/apache/commons-dbcp/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/commons-dbcp) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.commons/commons-dbcp2/badge.svg?gav=true)](https://maven-badges.herokuapp.com/maven-central/org.apache.commons/commons-dbcp2/?gav=true) [![Javadocs](https://javadoc.io/badge/org.apache.commons/commons-dbcp2/2.10.0.svg)](https://javadoc.io/doc/org.apache.commons/commons-dbcp2/2.10.0) [![CodeQL](https://github.com/apache/commons-dbcp/workflows/CodeQL/badge.svg)](https://github.com/apache/commons-dbcp/actions/workflows/codeql-analysis.yml?query=workflow%3ACodeQL) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/apache/commons-dbcp/badge)](https://api.securityscorecards.dev/projects/github.com/apache/commons-dbcp) Apache Commons DBCP software implements Database Connection Pooling Documentation ------------- More information can be found on the [Apache Commons DBCP homepage](https://commons.apache.org/proper/commons-dbcp). The [Javadoc](https://commons.apache.org/proper/commons-dbcp/apidocs) can be browsed. Questions related to the usage of Apache Commons DBCP should be posted to the [user mailing list][ml]. Where can I get the latest release? ----------------------------------- You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi). Alternatively, you can pull it from the central Maven repositories: ```xml org.apache.commons commons-dbcp2 2.10.0 ``` Contributing ------------ We accept Pull Requests via GitHub. The [developer mailing list](https://commons.apache.org/mail-lists.html) is the main channel of communication for contributors. There are some guidelines which will make applying PRs easier for us: + No tabs! Please use spaces for indentation. + Respect the code style. + Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change. + Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running ```mvn```. If you plan to contribute on a regular basis, please consider filing a [contributor license agreement](https://www.apache.org/licenses/#clas). You can learn more about contributing via GitHub in our [contribution guidelines](CONTRIBUTING.md). License ------- This code is under the [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0). See the `NOTICE.txt` file for required notices and attributions. Donations --------- You like Apache Commons DBCP? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support the development. Additional Resources -------------------- + [Apache Commons Homepage](https://commons.apache.org/) + [Apache Issue Tracker (JIRA)](https://issues.apache.org/jira/browse/DBCP) + [Apache Commons Slack Channel](https://the-asf.slack.com/archives/C60NVB8AD) + [Apache Commons Twitter Account](https://twitter.com/ApacheCommons) + `#apache-commons` IRC channel on `irc.freenode.org` Apache Commons Components ------------------------- | Component | GitHub Repository | Apache Homepage | | --------- | ----------------- | ----------------| | Apache Commons BCEL | [commons-bcel](https://github.com/apache/commons-bcel) | [commons-bcel](https://commons.apache.org/proper/commons-bcel) | | Apache Commons Beanutils | [commons-beanutils](https://github.com/apache/commons-beanutils) | [commons-beanutils](https://commons.apache.org/proper/commons-beanutils) | | Apache Commons BSF | [commons-bsf](https://github.com/apache/commons-bsf) | [commons-bsf](https://commons.apache.org/proper/commons-bsf) | | Apache Commons Build-plugin | [commons-build-plugin](https://github.com/apache/commons-build-plugin) | [commons-build-plugin](https://commons.apache.org/proper/commons-build-plugin) | | Apache Commons Chain | [commons-chain](https://github.com/apache/commons-chain) | [commons-chain](https://commons.apache.org/proper/commons-chain) | | Apache Commons CLI | [commons-cli](https://github.com/apache/commons-cli) | [commons-cli](https://commons.apache.org/proper/commons-cli) | | Apache Commons Codec | [commons-codec](https://github.com/apache/commons-codec) | [commons-codec](https://commons.apache.org/proper/commons-codec) | | Apache Commons Collections | [commons-collections](https://github.com/apache/commons-collections) | [commons-collections](https://commons.apache.org/proper/commons-collections) | | Apache Commons Compress | [commons-compress](https://github.com/apache/commons-compress) | [commons-compress](https://commons.apache.org/proper/commons-compress) | | Apache Commons Configuration | [commons-configuration](https://github.com/apache/commons-configuration) | [commons-configuration](https://commons.apache.org/proper/commons-configuration) | | Apache Commons Crypto | [commons-crypto](https://github.com/apache/commons-crypto) | [commons-crypto](https://commons.apache.org/proper/commons-crypto) | | Apache Commons CSV | [commons-csv](https://github.com/apache/commons-csv) | [commons-csv](https://commons.apache.org/proper/commons-csv) | | Apache Commons Daemon | [commons-daemon](https://github.com/apache/commons-daemon) | [commons-daemon](https://commons.apache.org/proper/commons-daemon) | | Apache Commons DBCP | [commons-dbcp](https://github.com/apache/commons-dbcp) | [commons-dbcp](https://commons.apache.org/proper/commons-dbcp) | | Apache Commons Dbutils | [commons-dbutils](https://github.com/apache/commons-dbutils) | [commons-dbutils](https://commons.apache.org/proper/commons-dbutils) | | Apache Commons Digester | [commons-digester](https://github.com/apache/commons-digester) | [commons-digester](https://commons.apache.org/proper/commons-digester) | | Apache Commons Email | [commons-email](https://github.com/apache/commons-email) | [commons-email](https://commons.apache.org/proper/commons-email) | | Apache Commons Exec | [commons-exec](https://github.com/apache/commons-exec) | [commons-exec](https://commons.apache.org/proper/commons-exec) | | Apache Commons Fileupload | [commons-fileupload](https://github.com/apache/commons-fileupload) | [commons-fileupload](https://commons.apache.org/proper/commons-fileupload) | | Apache Commons Functor | [commons-functor](https://github.com/apache/commons-functor) | [commons-functor](https://commons.apache.org/proper/commons-functor) | | Apache Commons Geometry | [commons-geometry](https://github.com/apache/commons-geometry) | [commons-geometry](https://commons.apache.org/proper/commons-geometry) | | Apache Commons Graph | [commons-graph](https://github.com/apache/commons-graph) | [commons-graph](https://commons.apache.org/proper/commons-graph) | | Apache Commons Imaging | [commons-imaging](https://github.com/apache/commons-imaging) | [commons-imaging](https://commons.apache.org/proper/commons-imaging) | | Apache Commons IO | [commons-io](https://github.com/apache/commons-io) | [commons-io](https://commons.apache.org/proper/commons-io) | | Apache Commons JCI | [commons-jci](https://github.com/apache/commons-jci) | [commons-jci](https://commons.apache.org/proper/commons-jci) | | Apache Commons JCS | [commons-jcs](https://github.com/apache/commons-jcs) | [commons-jcs](https://commons.apache.org/proper/commons-jcs) | | Apache Commons Jelly | [commons-jelly](https://github.com/apache/commons-jelly) | [commons-jelly](https://commons.apache.org/proper/commons-jelly) | | Apache Commons Jexl | [commons-jexl](https://github.com/apache/commons-jexl) | [commons-jexl](https://commons.apache.org/proper/commons-jexl) | | Apache Commons Jxpath | [commons-jxpath](https://github.com/apache/commons-jxpath) | [commons-jxpath](https://commons.apache.org/proper/commons-jxpath) | | Apache Commons Lang | [commons-lang](https://github.com/apache/commons-lang) | [commons-lang](https://commons.apache.org/proper/commons-lang) | | Apache Commons Logging | [commons-logging](https://github.com/apache/commons-logging) | [commons-logging](https://commons.apache.org/proper/commons-logging) | | Apache Commons Math | [commons-math](https://github.com/apache/commons-math) | [commons-math](https://commons.apache.org/proper/commons-math) | | Apache Commons Net | [commons-net](https://github.com/apache/commons-net) | [commons-net](https://commons.apache.org/proper/commons-net) | | Apache Commons Numbers | [commons-numbers](https://github.com/apache/commons-numbers) | [commons-numbers](https://commons.apache.org/proper/commons-numbers) | | Apache Commons Parent | [commons-parent](https://github.com/apache/commons-parent) | [commons-parent](https://commons.apache.org/proper/commons-parent) | | Apache Commons Pool | [commons-pool](https://github.com/apache/commons-pool) | [commons-pool](https://commons.apache.org/proper/commons-pool) | | Apache Commons Proxy | [commons-proxy](https://github.com/apache/commons-proxy) | [commons-proxy](https://commons.apache.org/proper/commons-proxy) | | Apache Commons RDF | [commons-rdf](https://github.com/apache/commons-rdf) | [commons-rdf](https://commons.apache.org/proper/commons-rdf) | | Apache Commons Release-plugin | [commons-release-plugin](https://github.com/apache/commons-release-plugin) | [commons-release-plugin](https://commons.apache.org/proper/commons-release-plugin) | | Apache Commons Rng | [commons-rng](https://github.com/apache/commons-rng) | [commons-rng](https://commons.apache.org/proper/commons-rng) | | Apache Commons Scxml | [commons-scxml](https://github.com/apache/commons-scxml) | [commons-scxml](https://commons.apache.org/proper/commons-scxml) | | Apache Commons Signing | [commons-signing](https://github.com/apache/commons-signing) | [commons-signing](https://commons.apache.org/proper/commons-signing) | | Apache Commons Skin | [commons-skin](https://github.com/apache/commons-skin) | [commons-skin](https://commons.apache.org/proper/commons-skin) | | Apache Commons Statistics | [commons-statistics](https://github.com/apache/commons-statistics) | [commons-statistics](https://commons.apache.org/proper/commons-statistics) | | Apache Commons Testing | [commons-testing](https://github.com/apache/commons-testing) | [commons-testing](https://commons.apache.org/proper/commons-testing) | | Apache Commons Text | [commons-text](https://github.com/apache/commons-text) | [commons-text](https://commons.apache.org/proper/commons-text) | | Apache Commons Validator | [commons-validator](https://github.com/apache/commons-validator) | [commons-validator](https://commons.apache.org/proper/commons-validator) | | Apache Commons VFS | [commons-vfs](https://github.com/apache/commons-vfs) | [commons-vfs](https://commons.apache.org/proper/commons-vfs) | | Apache Commons Weaver | [commons-weaver](https://github.com/apache/commons-weaver) | [commons-weaver](https://commons.apache.org/proper/commons-weaver) | commons-dbcp-rel-commons-dbcp-2.10.0/RELEASE-NOTES.txt000066400000000000000000001012421447311732500220300ustar00rootroot00000000000000 Apache Commons DBCP Version 2.10.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.10.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements. Changes in this version include: New features: o Add and use AbandonedTrace#setLastUsed(Instant). Thanks to Gary Gregory. o - Add and use Duration versions of now deprecated APIs that use ints and longs. - Internally track durations with Duration objects instead of ints and longs. - See the JApiCmp report for the complete list. Thanks to Gary Gregory. o Add PMD check to default Maven goal. Thanks to Gary Gregory. o Add Utils.getDisconnectionSqlCodes() and Utils.DISCONNECTION_SQL_CODES. Thanks to Gary Gregory. o Make BasicDataSource.getConnectionPool() public. Thanks to Gary Gregory. o Add github/codeql-action. Thanks to Gary Gregory. Fixed Bugs: o Fix StackOverflowError in PoolableConnection.isDisconnectionSqlException #123. Thanks to newnewcoder, Gary Gregory. o PerUserPoolDataSourceFactory.getNewInstance(Reference) parsed defaultMaxWaitMillis as an int instead of a long. Thanks to Gary Gregory. o Reimplement time tracking in AbandonedTrace with an Instant instead of a long. Thanks to Gary Gregory. o Migrate away from deprecated APIs in Apache Commons Pool. Thanks to Gary Gregory. o Fix possible NullPointerException in BasicDataSourceFactory.validatePropertyNames(). Thanks to Gary Gregory. o Fix possible NullPointerException in BasicDataSourceFactory.getObjectInstance(). Thanks to Gary Gregory. o DBCP-585: Connection level JMX queries result in concurrent access to connection objects, causing errors #179. Thanks to Kurtcebe Eroglu, Gary Gregory, Phil Steitz. o UserPassKey should be Serializable. Thanks to Gary Gregory. o LifetimeExceededException should extend SQLException. Thanks to Gary Gregory. o Replace Exception with SQLException in some method signatures (preserves binary compatibility, not source). Thanks to Gary Gregory. o Don't leak Connections when PoolableConnectionFactory.makeObject() fails to create a JMX ObjectName. Thanks to Gary Gregory. o Performance: No need for map lookups if we traverse map entries instead of keys. Thanks to SpotBugs, Gary Gregory. o Performance: Refactor to use a static inner class in DataSourceXAConnectionFactory. Thanks to SpotBugs, Gary Gregory. o Reuse pattern of throwing XAException instead of NullPointerException in LocalXAConnectionFactory.LocalXAResource. Thanks to SpotBugs, Gary Gregory. o SpotBugs: An overridable method is called from constructors in PoolableCallableStatement. Thanks to SpotBugs, Gary Gregory. o SpotBugs: An overridable method is called from constructors in PoolablePreparedStatement. Thanks to SpotBugs, Gary Gregory. o Wrong property name logged in ConnectionFactoryFactory.createConnectionFactory(BasicDataSource, Driver). Thanks to Gary Gregory. o Throw SQLException instead of NullPointerException when the connection is already closed. Thanks to Gary Gregory. o CPDSConnectionFactory.makeObject() does not need to wrap and rethrow SQLException. Thanks to Gary Gregory. o PoolingDataSource.close() now always throws SQLException. Thanks to Gary Gregory. o [StepSecurity] ci: Harden GitHub Actions #282. Thanks to step-security-bot, Gary Gregory. o Fixes typos, missing or misplaced characters, and grammar issues #299. Thanks to Martin Wiesner. Changes: o Bump actions/cache from 2.1.6 to 3.0.8 #147, #176. Thanks to Dependabot, Gary Gregory. o Bump actions/checkout from 2.3.4 to 3.0.2 #139, #143, #173. Thanks to Dependabot, Gary Gregory. o Bump actions/setup-java from 2 to 3.6.0 #229. Thanks to Gary Gregory, Dependabot. o Bump actions/upload-artifact from 3.1.0 to 3.1.1 #231. Thanks to Dependabot. o Bump checkstyle from 8.44 to 9.3 #121, #130, #149, #158, #190. Thanks to Dependabot. o Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0 #210. Thanks to Dependabot. o Bump commons-pool2 2.10.0 to 2.11.1. Thanks to Gary Gregory, Dependabot. o Bump junit-jupiter from 5.8.0-M1 to 5.9.1 #125, #136, #157, #203, #218. Thanks to Dependabot. o Bump spotbugs-maven-plugin from 4.3.0 to 4.7.3.0 #140, #154, #161, #178, #192, #200, #204, #213, #234. Thanks to Dependabot. o Bump spotbugs from 4.3.0 to 4.7.3 #124, #133, #151, #164, #177, #189, #214, #230. Thanks to Dependabot, Gary Gregory. o Bump org.mockito:mockito-core from 3.11.2 to 4.11.0, #128, #138, #152, #175, #188. #193, #208, #215, #232, #235, #246, #252. Thanks to Gary Gregory, Dependabot. o Bump maven-javadoc-plugin from 3.3.0 to 3.4.1 #131, #184. Thanks to Dependabot. o Bump maven-pmd-plugin from 3.14.0 to 3.19.0 #132, #172, #195. Thanks to Dependabot, Gary Gregory. o Bump pmd from 6.44.0 to 6.52.0. Thanks to Dependabot, Gary Gregory. o Bump narayana-jta from 5.12.0.Final to 5.12.7.Final #134, #156, #163, #185, #197. Thanks to Dependabot. o Bump japicmp-maven-plugin from 0.15.3 to 0.17.1 #137, #166, #174, #211, #238. Thanks to Dependabot. o Bump h2 from 1.4.200 to 2.2.220 #153, #183, #196, #287. Update SQL for migration from H2 1.4.200 to 2.0.204 where "KEY" and "VALUE" are now reserved keywords. Thanks to Gary Gregory, Dependabot. o Bump jboss-logging from 3.4.2.Final to 3.4.3.Final #162. Thanks to Dependabot. o Bump slf4j-simple from 1.7.30 to 1.7.36 #169. Thanks to Dependabot. o Bump commons-parent from 52 to 60 #180, #219, #254, #278. Thanks to Dependabot, Gary Gregory. o Bump JaCoCo from 0.8.7 to 0.8.8. Thanks to Gary Gregory. o Bump maven-surefire-plugin 2.22.2 to 3.0.0-M7. Thanks to Gary Gregory. o Bump apache-rat-plugin 0.13 to 0.14. Thanks to Gary Gregory. o Bump commons-lang3 from 3.12 to 3.13.0. Thanks to Gary Gregory. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download page: https://commons.apache.org/dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.9.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.9.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements. Changes in this version include: New features: o Add and reuse Constants.KEY_USER and Constants.KEY_PASSWORD. Thanks to Gary Gregory. o Add and reuse DataSourceMXBean. Thanks to Frank Gasdorf, Gary Gregory. o Add and reuse DriverAdapterCPDS.{get|set}DurationBetweenEvictionRuns(), deprecate {get|set}TimeBetweenEvictionRunsMillis(long). Thanks to Gary Gregory. o Add and reuse DriverAdapterCPDS.{get|set}MinEvictableIdleDuration(), deprecate {get|set}MinEvictableIdleTimeMillis(int). Thanks to Gary Gregory. o Add and reuse CPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long). Thanks to Gary Gregory. o Add and reuse KeyedCPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long). Thanks to Gary Gregory. o Add and reuse KeyedCPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long). Thanks to Gary Gregory. o Add and reuse InstanceKeyDataSource.{get|set}DefaultMaxWait(Duration), deprecate {get|set}DefaultMaxWaitMillis(long). Thanks to Gary Gregory. Fixed Bugs: o DBCP-569: Fix test random failure on TestSynchronizationOrder.testInterposedSynchronization, #84. Thanks to Florent Guillaume. o DBCP-568: ManagedConnection must clear its cached state after transaction completes, #75. Thanks to Florent Guillaume. o Minor Improvements #78. Thanks to Arturo Bernal. o DBCP-567: Use abort rather than close to clean up abandoned connections. Thanks to Phil Steitz, Gary Gregory, Phil Steitz, Romain Manni-Bucau. o Performance Enhancement: Call toArray with Zero Array Size #20. Thanks to Gary Gregory, DaGeRe. o DBCP-562: Avoid exposing password via JMX #38. Thanks to Frank Gasdorf, Gary Gregory. o DBCP-575: Remove redundant initializers #98. Thanks to Arturo Bernal. o DBCP-577: Simplify test assertions #100, #113. Thanks to Arturo Bernal. o DBCP-573: DataSource implementations do not implement Wrapper interface correctly #93. Thanks to RÊda Housni Alaoui, Gary Gregory. o Replace FindBugs with SpotBugs. o DataSourceConnectionFactory.getUserPassword() may expose internal representation by returning DataSourceConnectionFactory.userPassword. o DataSourceXAConnectionFactory.getUserPassword() may expose internal representation by returning DataSourceXAConnectionFactory.userPassword. o DriverAdapterCPDS.getPasswordCharArray() may expose internal representation by returning DriverAdapterCPDS.userPassword. o new org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory(TransactionManager, XADataSource, String, char[], TransactionSynchronizationRegistry) may expose internal representation by storing an externally mutable object into DataSourceXAConnectionFactory.userPassword. o org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory.setPassword(char[]) may expose internal representation by storing an externally mutable object into DataSourceXAConnectionFactory.userPassword. o org.apache.commons.dbcp2.PStmtKey.getColumnIndexes() may expose internal representation by returning PStmtKey.columnIndexes. o org.apache.commons.dbcp2.PStmtKey.getColumnNames() may expose internal representation by returning PStmtKey.columnNames. o DBCP-578: Use Collections.synchronizedList() Instead Of Vector #101. Thanks to Arturo Bernal. o DBCP-576: Simplify and inline variables #99. Thanks to Arturo Bernal. o Update PoolKey#toString() to avoid revealing a user name is here. Thanks to Gary Gregory. o Internal package private UserPassKey class stores its user name as a char[] as it already does the password. Thanks to Gary Gregory. o DBCP-579: Performance of DelegatingConnection.prepareStatement(String) regressed enormously in 2.8.0 compared to 1.4. DelegatingConnection should also cache connection schema string to avoid calling the Connection#getSchema() for each key creation. DelegatingConnection should also cache connection catalog string to avoid calling the Connection#getCatalog() for each key creation. Thanks to Shaktisinh Jhala, Gary Gregory. o BasicDataSource should test for the presence of a security manager dynamically, not once on initialization. Thanks to Gary Gregory. Changes: o Bump mockito-core from 3.5.11 to 3.11.2 #66, #72, #77, #85, #91, #105, #110, #116. Thanks to Dependabot. o Bump actions/checkout from v2.3.2 to v2.3.4 #65, #74. Thanks to Dependabot. o Bump actions/cache from v2 to v2.1.6 #90, #108. Thanks to Dependabot. o Bump commons-pool2 from 2.8.1 to 2.9.0. Thanks to Gary Gregory. o Bump actions/setup-java from v1.4.2 to v2 #69. Thanks to Dependabot, Gary Gregory. o Bump japicmp-maven-plugin from 0.14.3 to 0.15.2 #71, #82. Thanks to Dependabot, Gary Gregory. o Bump maven-pmd-plugin from 3.13.0 to 3.14.0 #76. Thanks to Dependabot. o Bump japicmp-maven-plugin from 0.14.4 to 0.15.3, #83. Thanks to Dependabot, Gary Gregory. o Bump Hamcrest 1.3 -> 2.2 #70. Thanks to John Patrick. o Bump maven-checkstyle-plugin from 3.1.1 to 3.1.2 #88. Thanks to Gary Gregory. o Bump junit-jupiter from 5.7.0 to 5.8.0-M1, #89, #106. Thanks to Gary Gregory. o Bump narayana-jta from 5.10.6.Final to 5.12.0.Final #103, #111. Thanks to Dependabot. o Bump maven-javadoc-plugin from 3.2.0 to 3.3.0 #107. Thanks to Dependabot. o Bump commons.jacoco.version 0.8.6 -> 0.8.7. Thanks to Gary Gregory. o Bump jboss-logging from 3.4.1.Final to 3.4.2.Final #109. Thanks to Dependabot. o Bump org.jboss:jboss-transaction-spi from 7.6.0.Final to 7.6.1.Final. Thanks to Gary Gregory. o Bump commons-pool2 from 2.9.0 to 2.10.0. Thanks to Gary Gregory. o Bump checkstyle to 8.44. Thanks to Gary Gregory. o Bump spotbugs from 4.2.3 to 4.3.0 #117. Thanks to Dependabot. o Bump spotbugs-maven-plugin from 4.2.3 to 4.3.0 #118. Thanks to Dependabot. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download page: https://commons.apache.org/dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.8.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.8.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements. Changes in this version include: New features: o DBCP-564: Fix BasicManagedDataSource leak of connections opened after transaction is rollback-only #39. Thanks to Florent Guillaume. o DBCP-566: Add clearStatementPoolOnReturn #42. Thanks to Robert Paschek, Gary Gregory, Phil Steitz. o DBCP-559: Add start, restart methods to BasicDataSource. #50. Thanks to Phil Steitz. Fixed Bugs: o DBCP-555: NPE when creating a SQLExceptionList with a null list. Thanks to Gary Gregory. o DBCP-558: Fix DelegatingConnection readOnly and autoCommit caching mechanism #35. Thanks to louislatreille. o Fix regression introduced by unreleased code clean-up #63. Thanks to Sebastian Haas. Changes: o Update to PR#36 - PrepareStatement and prepareCall methods are extracted #37. Thanks to DoiMasayuki, Alexander Norz, Gary Gregory. o Mask out user name and password from DriverAdapterCPDS.toString(). Thanks to Gary Gregory. o DBCP-650: Update Apache Commons Pool from 2.7.0 to 2.8.1, #48. Thanks to Gary Gregory, Dependabot. o Update tests from H2 1.4.199 to 1.4.200. Thanks to Gary Gregory. o Update tests from Mockito 3.0.0 to 3.5.11 #47, #60, #64. Thanks to Gary Gregory, Dependabot. o Update tests from jboss-logging 3.4.0.Final to 3.4.1.Final. Thanks to Gary Gregory. o Update tests from narayana-jta 5.9.5.Final to 5.10.6.Final, #61. Thanks to Gary Gregory. o Update tests from junit-jupiter 5.5.1 to 5.7.0 #62. Thanks to Gary Gregory. o Update tests from org.slf4j:slf4j-simple 1.7.26 to 1.7.30. Thanks to Gary Gregory. o Update build from com.github.siom79.japicmp:japicmp-maven-plugin 0.13.1 to 0.14.3. Thanks to Gary Gregory. o Update build from maven-javadoc-plugin 3.1.1 to 3.2.0. Thanks to Gary Gregory. o Update build from maven-pmd-plugin 3.12.0 to 3.13.0. Thanks to Gary Gregory. o Update org.apache.commons:commons-parent from 48 to 51. Thanks to Gary Gregory. o Update jacoco-maven-plugin from 0.8.4 to 0.8.6. Thanks to Gary Gregory. o Update maven-checkstyle-plugin from 3.0.0 to 3.1.1. Thanks to Gary Gregory. o Update actions/checkout from v1 to v2.3.2, #44, #51. Thanks to Dependabot. o Update actions/setup-java from v1.4.0 to v1.4.2 #58. Thanks to Dependabot. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download page: https://commons.apache.org/dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.7.0 RELEASE NOTES 7 July 2019 The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.7.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements. Changes in this version include: New features: o DBCP-539: ManagedDataSource#close() should declare used exceptions. Thanks to Jacques Le Roux. o DBCP-547: Add a ConnectionFactory class name setting for BasicDataSource.createConnectionFactory() #33. Thanks to leechoongyon, Gary Gregory. o Add missing Javadocs. Thanks to Gary Gregory. Fixed Bugs: o DBCP-538: Wrong JMX base name derived in BasicDataSource#updateJmxName. Thanks to Ragnar Haugan, Gary Gregory. o DBCP-546: Avoid NPE when calling DriverAdapterCPDS.toString(). Thanks to Sergey Chupov. o DBCP-550: java.util.IllegalFormatException while building a message for a SQLFeatureNotSupportedException in Jdbc41Bridge.getObject(ResultSet,String,Class). Thanks to Gary Gregory. o Fix Javadoc link in README.md #21. Thanks to LichKing-lee. Changes: o DBCP-540: Close ObjectOutputStream before calling toByteArray() on underlying ByteArrayOutputStream #28. Thanks to emopers. o DBCP-541: Upgrade to JUnit Jupiter #19. Thanks to Allon Murienik. o DBCP-542: Fix tests on Java 11. Thanks to Zheng Feng, Gary Gregory. o DBCP-543: Update Apache Commons Pool from 2.6.1 to 2.6.2. Thanks to Gary Gregory. o DBCP-529: Add 'jmxName' property to web configuration parameters listing. Thanks to Yuri. o DBCP-548: Update Apache Commons Pool from 2.6.2 to 2.7.0. Thanks to Gary Gregory. o DBCP-549: Make org.apache.commons.dbcp2.AbandonedTrace.removeTrace(AbandonedTrace) null-safe. Thanks to Gary Gregory. o DBCP-551: org.apache.commons.dbcp2.DelegatingStatement.close() should try to close ALL of its result sets even when an exception occurs. Thanks to Gary Gregory. o DBCP-552: org.apache.commons.dbcp2.DelegatingConnection.passivate() should close ALL of its resources even when an exception occurs. Thanks to Gary Gregory. o DBCP-553: org.apache.commons.dbcp2.PoolablePreparedStatement.passivate() should close ALL of its resources even when an exception occurs. Thanks to Gary Gregory. o DBCP-554: org.apache.commons.dbcp2.PoolableCallableStatement.passivate() should close ALL of its resources even when an exception occurs. Thanks to Gary Gregory. o Update tests from org.mockito:mockito-core 2.28.2 to 3.0.0. Thanks to Gary Gregory. o Update tests from H2 1.4.198 to 1.4.199. Thanks to Gary Gregory. o Update tests from com.h2database:h2 1.4.197 to 1.4.199. Thanks to Gary Gregory. o Update tests from org.jboss.narayana.jta:narayana-jta 5.9.2.Final to 5.9.5.Final. Thanks to Gary Gregory. o Update tests from org.jboss.logging:jboss-logging 3.3.2.Final to 3.4.0.Final. Thanks to Gary Gregory. o Update tests from org.mockito:mockito-core 2.24.0 to 2.28.2. Thanks to Gary Gregory. o Update tests from org.mockito:mockito-core 2.28.2 to 3.0.0. Thanks to Gary Gregory. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download page: https://commons.apache.org/dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.6.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.6.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements. Changes in this version include: New features: o DBCP-534: Allow for manual connection eviction. Thanks to Peter Wicks. o DBCP-514: Allow DBCP to register with a TransactionSynchronizationRegistry for XA cases. Thanks to Tom Jenkinson, Gary Gregory. o DBCP-519: Add some toString() methods for debugging (never printing passwords.) Thanks to Gary Gregory. o DBCP-527: Add getters to some classes. Thanks to Gary Gregory. o DBCP-528: org.apache.commons.dbcp2.DriverManagerConnectionFactory should use a char[] instead of a String to store passwords. Thanks to Gary Gregory. Fixed Bugs: o DBCP-518: Allow DBCP to work with old Java 6/JDBC drivers without throwing AbstractMethodError. Thanks to Gary Gregory. Changes: o DBCP-517: Make defensive copies of char[] passwords. Thanks to Gary Gregory. o DBCP-515: Do not try to register synchronization when the transaction is no longer active. Thanks to Tom Jenkinson, Gary Gregory. o DBCP-516: Do not double returnObject back to the pool if there is a transaction context with a shared connection. Thanks to Tom Jenkinson, Gary Gregory. o DBCP-520: BasicManagedDataSource needs to pass the TSR with creating DataSourceXAConnectionFactory. Thanks to Zheng Feng. o DBCP-537: Update Apache Commons Pool from 2.6.0 to 2.6.1. Thanks to Gary Gregory. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download page: https://commons.apache.org/dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.5.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.5.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements and requires Java 8 to support JDBC 4.2. Changes in this version include: New features: o DBCP-506: Support JDBC 4.2. Thanks to Gary Gregory. o DBCP-479: Support default schema in configuration. Thanks to Guillaume Husta, Gary Gregory. Fixed Bugs: o DBCP-508: Prepared statement keys should take a Connection's schema into account. Thanks to Gary Gregory. o DBCP-512: Avoid exceptions when closing a connection in mutli-threaded use case. Thanks to Gary Gregory. Changes: o DBCP-505: Update Java requirement from version 7 to 8. Thanks to Gary Gregory. o DBCP-427: Examines 'SQLException's thrown by underlying connections or statements for fatal (disconnection) errors. Thanks to Vladimir Konkov, Phil Steitz, Gary Gregory. o DBCP-507: Change default for fail-fast connections from false to true. Thanks to Vladimir Konkov, Phil Steitz, Gary Gregory. o DBCP-504: Increase test coverage. Thanks to Bruno P. Kinoshita. o DBCP-510: Update Apache Commons Pool from 2.5.0 to 2.6.0. Thanks to Gary Gregory. Note that Clirr incorrectly reports one binary incompatible change because it is not aware of Java 8 and default methods: [ERROR] 7012: org.apache.commons.dbcp2.BasicDataSourceMXBean: Method 'public java.lang.String getDefaultSchema()' has been added to an interface For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download from https://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Download page: https://commons.apache.org/dbcp/download_dbcp.cgi Apache Commons DBCP Version 2.4.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.4.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements, which you can download from https://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi Changes in this version include: Fixed Bugs: o DBCP-484: Connection leak during XATransaction in high load. Thanks to Emanuel Freitas. o DBCP-496: Add support for pooling CallableStatements to the org.apache.commons.dbcp2.cpdsadapter package. Thanks to Gary Gregory. Changes: o DBCP-492: Drop Ant build. Thanks to Gary Gregory. o DBCP-491: Ensure DBCP ConnectionListener can deal with transaction managers which invoke rollback in a separate thread. Thanks to Zheng Feng, Gary Gregory. o DBCP-494: org.apache.commons.dbcp2.PStmtKey should make copies of given arrays in constructors. Thanks to Gary Gregory. o DBCP-495: Remove duplicate code in org.apache.commons.dbcp2.cpdsadapter.PStmtKeyCPDS. Thanks to Gary Gregory. o DBCP-497: Deprecate use of PStmtKeyCPDS in favor of PStmtKey. Thanks to Gary Gregory. o DBCP-498: org.apache.commons.dbcp2.DataSourceConnectionFactory should use a char[] instead of a String to store passwords. Thanks to Gary Gregory. o DBCP-499: org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory should use a char[] instead of a String to store passwords. Thanks to Gary Gregory. o DBCP-500: org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS should use a char[] instead of a String to store passwords. Thanks to Gary Gregory. o DBCP-501: org.apache.commons.dbcp2.datasources.CPDSConnectionFactory should use a char[] instead of a String to store passwords. Thanks to Gary Gregory. o DBCP-502: org.apache.commons.dbcp2.datasources internals should use a char[] instead of a String to store passwords. Thanks to Gary Gregory. o DBCP-503: org.apache.commons.dbcp2.datasources.InstanceKeyDataSourceFactory.closeAll() does not close all. Thanks to Gary Gregory. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download from https://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.3.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.3.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements. Changes in this version include: Fixed Bugs: o DBCP-476: AbandonedTrace.getTrace() contains race condition Thanks to Gary Evesson, Richard Cordova. o DBCP-482: Avoid javax.management.InstanceNotFoundException on shutdown when a bean is not registered. Thanks to Dennis Lloyd, Gary Gregory. Changes: o DBCP-483: Make constant public: org.apache.commons.dbcp2.PoolingDriver.URL_PREFIX. Thanks to Gary Gregory. o DBCP-486: DriverAdapterCPDS.setUser(), setPassword(), and getPooledConnection() with null arguments throw NullPointerExceptions when connection properties are set. Thanks to Gary Gregory. o DBCP-487: Add API org.apache.commons.dbcp2.datasources.PerUserPoolDataSource.clear(). Thanks to Gary Gregory. o DBCP-488: NPE for org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS.setConnectionProperties(null). Thanks to Gary Gregory. o DBCP-490: The method org.apache.commons.dbcp2.PoolingDriver.getConnectionPool(String) does not tell you which pool name is not registered when it throws an exception. Thanks to Gary Gregory. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download from https://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.2.0 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.2.0. Apache Commons DBCP software implements Database Connection Pooling. This is a minor release, including bug fixes and enhancements. Changes in this version include: New features: o DBCP-451: Add constructor DriverManagerConnectionFactory(String). o DBCP-462: Refactoring to prepare for a future patch to enable pooling of all prepared and callable statements in PoolingConnection. Thanks to Keiichi Fujino. o DBCP-458: Make it simpler to extend BasicDataSource to allow sub-classes to provide custom GenericObjectPool implementations. Thanks to Adrian Tarau. o DBCP-474: Enable pooling of all prepared and callable statements inPoolingConnection. Thanks to Keiichi Fujino. Fixed Bugs: o DBCP-481: Update Apache Commons Pool from 2.4.2 to 2.5.0. Thanks to Gary Gregory. o DBCP-454: OSGi declarations contain multiple import headers for javax.transaction. Thanks to Philipp Marx, Matt Sicker. o DBCP-478: Wrong parameter name in site documentation for BasicDataSource Configuration Parameters. Thanks to nicola mele. o DBCP-452: Add jmxName to properties set by BasicDataSourceFactory. This enables container-managed pools created from JNDI Resource definitions to enable JMX by supplying a valid root JMX name. o DBCP-446: NullPointerException thrown when calling ManagedConnection.isClosed(). Thanks to Gary Gregory, feng yang, Euclides M, Phil Steitz. o DBCP-444: InvalidateConnection can result in closed connection returned by getConnection. o DBCP-449: Complete the fix for DBCP-418, enabling PoolableConnection class to load in environments (such as GAE) where the JMX ManagementFactory is not available. Thanks to Grzegorz D.. o DBCP-455: Ensure that the cacheState setting is used when statement pooling is disabled. Thanks to Kyohei Nakamura. o DBCP-453: Ensure that setSoftMinEvictableIdleTimeMillis is used when working with BasicDataSource. Thanks to Philipp Marx. o DBCP-456: Correct the name of the configuration attribute softMinEvictableIdleTimeMillis. Thanks to Kyohei Nakamura. o DBCP-472: Avoid potential infinite loops when checking if an SQLException is fatal for a connection or not. o DBCP-468: Expand the fail-fast for fatal connection errors feature to include managed connections. o DBCP-463: Correct a typo in the method name PoolableConnectionFactory#setMaxOpenPreparedStatements. The old method remains but is deprecated so not to break clients currently using the incorrect name. o DBCP-459: Ensure that a thread's interrupt status is visible to the caller if the thread is interrupted during a call to PoolingDataSource.getConnection(). o DBCP-457: When using a BasicDataSource, pass changes related to the handling of abandoned connections to the underlying pool so that the pool configuration may be updated dynamically. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download from https://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi ----------------------------------------------------------------------------- Apache Commons DBCP Version 2.1.1 RELEASE NOTES The Apache Commons DBCP team is pleased to announce the release of Apache Commons DBCP 2.1.1. Apache Commons DBCP software implements Database Connection Pooling. This is a patch release, including bug fixes only. Changes in this version include: Fixed Bugs: o DBCP-441: Added BasicDataSource abandonedUsageTracking property missing from BasicDataSourceFactory. o DBCP-442: SharedPoolDataSource getConnection fails when testOnBorrow is set with a null validation query. o DBCP-438: Nested connections in a transaction (local) throws null pointer. Thanks to Raihan Kibria. o DBCP-437: BasicDataSource does not set disconnectionSql properties on its PoolableConnectionFactory. Changes: o Updated pool version to 2.4.2. The fix for POOL-300 may cause DBCP users to see more reports of abandoned connections (if removal and logging are configured). Prior to the fix for POOL-300, the PrintWriter used to log abandoned connection stack traces was not being flushed on each log event. For complete information on Apache Commons DBCP, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons DBCP website: https://commons.apache.org/dbcp/ Download from https://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi commons-dbcp-rel-commons-dbcp-2.10.0/SECURITY.md000066400000000000000000000016041447311732500211130ustar00rootroot00000000000000 The Apache Commons security page is [https://commons.apache.org/security.html](https://commons.apache.org/security.html). commons-dbcp-rel-commons-dbcp-2.10.0/dbcp-RC.sh000077500000000000000000000044621447311732500211000ustar00rootroot00000000000000#!/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. # ----------------------------------------------------------------------------- # Generates a dbcp RC and publishes (a superset of) maven artifacts to Nexus. # Should be run from top-level directory of a fresh checkout of the RC tag. # # Preconditions: # 0) dbcp-pre-RC has been run to update the download page and release notes # and these have been checked in and included in the RC tag. # 1) Release artifacts from previous runs have been svn deleted from local # svn pub/sub dev checkout. # 2) Nexus repo from previous RC has been dropped. # # ----------------------------------------------------------------------------- # Set script variables version=2.4.0 repo_path=~/.m2/repository/org/apache/commons/commons-dbcp2/${version} release_path=~/dbcp-rc #checkout of https://dist.apache.org/repos/dist/dev/commons/dbcp # # Delete any locally installed artifacts from previous runs rm -rf ${repo_path} echo "Cleaned maven repo." # # Generate site and release artifacts, deploy locally and upload to Nexus mvn clean site mvn deploy -Prelease # # Copy the zips/tarballs and release notes to the local svn pub path cp ${repo_path}/*bin.zip* ${release_path}/binaries cp ${repo_path}/*bin.tar.gz* ${release_path}/binaries cp ${repo_path}/*src.zip* ${release_path}/source cp ${repo_path}/*src.tar.gz* ${release_path}/source cp RELEASE-NOTES.txt ${release_path} echo "Release candidate complete." echo "svn add the generated artifacts and commit after inspection." echo "log in to repository.apache.org, manually (sic) drop the cruft and close the repo." commons-dbcp-rel-commons-dbcp-2.10.0/dbcp-pre-RC.sh000077500000000000000000000026201447311732500216560ustar00rootroot00000000000000#!/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. # ----------------------------------------------------------------------------- # # Shell script to update download page and release notes prior # to preparing a commons dbcp release candidate. # # Note: RELEASE-NOTES.txt may need a little reformatting prior # to checkin. Both RELEASE-NOTES.txt and the generated download # page need to be checked in after review. # # ---------------------------------------------------------------------------- version=2.4.0 mvn changes:announcement-generate -Prelease-notes -Dchanges.version=${version} mvn commons:download-page -Dcommons.componentid=dbcp -Dcommons.release.version=${version} commons-dbcp-rel-commons-dbcp-2.10.0/dbcp-release.sh000077500000000000000000000050721447311732500222120ustar00rootroot00000000000000#!/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. # ----------------------------------------------------------------------------- # Performs the local svn steps necessary to publish a dbcp release. # # Preconditions: # 0) Successful release VOTE has completed, based on artifacts in rc_path # (checkout of https://dist.apache.org/repos/dist/dev/commons/dbcp) # 1) release_path points to a local checkout of # https://dist.apache.org/repos/dist/release/commons/dbcp # 2) RELEASE-NOTES.txt for the new release is in top level of rc_path # # NOTE: This script does not do any of the following: # 0) Commit the local changes to actually publish the artifacts # 1) Cleanup old versions in dist # # ----------------------------------------------------------------------------- # Set script variables version=2.4.0 # version being released last_version=2.3.0 # previous version, will be replaced in README.html rc_path=~/dbcp-rc # checkout of https://dist.apache.org/repos/dist/dev/commons/dbcp release_path=~/dbcp-release #https://dist.apache.org/repos/dist/release/commons/dbcp # # Move release notes cp $rc_path/RELEASE-NOTES.txt $release_path svn rm $rc_path/RELEASE-NOTES.txt # # Update README.html sed -i "" "s/$last_version/$version/g" $release_path/README.html # OSX ^^ required suffix # # DBCP uses symlinks, so below not needed unless this changes. #cp $release_path/README.html $release_path/source #cp $release_path/README.html $release_path/binaries # ^^^^^^^^^^ Maybe we can toss these? ^^^^^^^ # # Move release artifacts svn mv $rc_path/source/* $release_path/source svn mv $rc_path/binaries/* $release_path/binaries # echo "Local svn changes complete." echo "Inspect the files in $release_path and commit to publish the release." echo "Also remember to commit $rc_path to drop RC artifacts and svn rm" echo "obsolete artifacts from $release_path." commons-dbcp-rel-commons-dbcp-2.10.0/doc/000077500000000000000000000000001447311732500200665ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/doc/BasicDataSourceExample.java000066400000000000000000000106621447311732500252460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT 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.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; // // Here are the dbcp-specific classes. // Note that they are only used in the setupDataSource // method. In normal use, your classes interact // only with the standard JDBC API // import org.apache.commons.dbcp2.BasicDataSource; // // Here's a simple example of how to use the BasicDataSource. // // // Note that this example is very similar to the PoolingDriver // example. // // To compile this example, you'll want: // * commons-pool-2.3.jar // * commons-dbcp-2.1.jar // in your classpath. // // To run this example, you'll want: // * commons-pool-2.3.jar // * commons-dbcp-2.1.jar // * commons-logging-1.2.jar // in your classpath. // // // Invoke the class using two arguments: // * the connect string for your underlying JDBC driver // * the query you'd like to execute // You'll also want to ensure your underlying JDBC driver // is registered. You can use the "jdbc.drivers" // property to do this. // // For example: // java -Djdbc.drivers=org.h2.Driver \ // -classpath commons-pool2-2.3.jar:commons-dbcp2-2.1.jar:commons-logging-1.2.jar:h2-1.3.152.jar:. \ // BasicDataSourceExample \ // "jdbc:h2:~/test" \ // "SELECT 1" // public class BasicDataSourceExample { public static void main(String[] args) { // First we set up the BasicDataSource. // Normally this would be handled auto-magically by // an external configuration, but in this example we'll // do it manually. // System.out.println("Setting up data source."); DataSource dataSource = setupDataSource(args[0]); System.out.println("Done."); // // Now, we can use JDBC DataSource as we normally would. // Connection conn = null; Statement stmt = null; ResultSet rset = null; try { System.out.println("Creating connection."); conn = dataSource.getConnection(); System.out.println("Creating statement."); stmt = conn.createStatement(); System.out.println("Executing statement."); rset = stmt.executeQuery(args[1]); System.out.println("Results:"); int numcols = rset.getMetaData().getColumnCount(); while(rset.next()) { for(int i=1;i<=numcols;i++) { System.out.print("\t" + rset.getString(i)); } System.out.println(""); } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (rset != null) rset.close(); } catch (Exception e) { } try { if (stmt != null) stmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } } public static DataSource setupDataSource(String connectURI) { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("org.h2.Driver"); ds.setUrl(connectURI); return ds; } public static void printDataSourceStats(DataSource ds) { BasicDataSource bds = (BasicDataSource) ds; System.out.println("NumActive: " + bds.getNumActive()); System.out.println("NumIdle: " + bds.getNumIdle()); } public static void shutdownDataSource(DataSource ds) throws SQLException { BasicDataSource bds = (BasicDataSource) ds; bds.close(); } } commons-dbcp-rel-commons-dbcp-2.10.0/doc/PoolingDataSourceExample.java000066400000000000000000000143701447311732500256340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT 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.sql.DataSource; import java.sql.Connection; import java.sql.Statement; import java.sql.ResultSet; import java.sql.SQLException; // // Here are the dbcp-specific classes. // Note that they are only used in the setupDataSource // method. In normal use, your classes interact // only with the standard JDBC API // import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolingDataSource; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.DriverManagerConnectionFactory; // // Here's a simple example of how to use the PoolingDataSource. // // // Note that this example is very similar to the PoolingDriver // example. In fact, you could use the same pool in both a // PoolingDriver and a PoolingDataSource // // // To compile this example, you'll want: // * commons-pool2-2.3.jar // * commons-dbcp2-2.1.jar // in your classpath. // // To run this example, you'll want: // * commons-pool2-2.3.jar // * commons-dbcp2-2.1.jar // * commons-logging-1.2.jar // * the classes for your (underlying) JDBC driver // in your classpath. // // Invoke the class using two arguments: // * the connect string for your underlying JDBC driver // * the query you'd like to execute // You'll also want to ensure your underlying JDBC driver // is registered. You can use the "jdbc.drivers" // property to do this. // // For example: // java -Djdbc.drivers=org.h2.Driver \ // -classpath commons-pool2-2.3.jar:commons-dbcp2-2.1.jar:commons-logging-1.2.jar:h2-1.3.152.jar:. \ // PoolingDataSourceExample \ // "jdbc:h2:~/test" \ // "SELECT 1" // public class PoolingDataSourceExample { public static void main(String[] args) { // // First we load the underlying JDBC driver. // You need this if you don't use the jdbc.drivers // system property. // System.out.println("Loading underlying JDBC driver."); try { Class.forName("org.h2.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("Done."); // // Then, we set up the PoolingDataSource. // Normally this would be handled auto-magically by // an external configuration, but in this example we'll // do it manually. // System.out.println("Setting up data source."); DataSource dataSource = setupDataSource(args[0]); System.out.println("Done."); // // Now, we can use JDBC DataSource as we normally would. // Connection conn = null; Statement stmt = null; ResultSet rset = null; try { System.out.println("Creating connection."); conn = dataSource.getConnection(); System.out.println("Creating statement."); stmt = conn.createStatement(); System.out.println("Executing statement."); rset = stmt.executeQuery(args[1]); System.out.println("Results:"); int numcols = rset.getMetaData().getColumnCount(); while(rset.next()) { for(int i=1;i<=numcols;i++) { System.out.print("\t" + rset.getString(i)); } System.out.println(""); } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (rset != null) rset.close(); } catch (Exception e) { } try { if (stmt != null) stmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } } public static DataSource setupDataSource(String connectURI) { // // First, we'll create a ConnectionFactory that the // pool will use to create Connections. // We'll use the DriverManagerConnectionFactory, // using the connect string passed in the command line // arguments. // ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(connectURI, null); // // Next we'll create the PoolableConnectionFactory, which wraps // the "real" Connections created by the ConnectionFactory with // the classes that implement the pooling functionality. // PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null); // // Now we'll need a ObjectPool that serves as the // actual pool of connections. // // We'll use a GenericObjectPool instance, although // any ObjectPool implementation will suffice. // ObjectPool connectionPool = new GenericObjectPool<>(poolableConnectionFactory); // Set the factory's pool property to the owning pool poolableConnectionFactory.setPool(connectionPool); // // Finally, we create the PoolingDriver itself, // passing in the object pool we created. // PoolingDataSource dataSource = new PoolingDataSource<>(connectionPool); return dataSource; } } commons-dbcp-rel-commons-dbcp-2.10.0/doc/PoolingDriverExample.java000066400000000000000000000166451447311732500250440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT 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.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.DriverManagerConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingDriver; // // Here are the dbcp-specific classes. // Note that they are only used in the setupDriver // method. In normal use, your classes interact // only with the standard JDBC API // import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; // // Here's a simple example of how to use the PoolingDriver. // // To compile this example, you'll want: // * commons-pool-2.3.jar // * commons-dbcp-2.1.jar // in your classpath. // // To run this example, you'll want: // * commons-pool-2.3.jar // * commons-dbcp-2.1.jar // * commons-logging-1.2.jar // in your classpath. // // Invoke the class using two arguments: // * the connect string for your underlying JDBC driver // * the query you'd like to execute // You'll also want to ensure your underlying JDBC driver // is registered. You can use the "jdbc.drivers" // property to do this. // // For example: // java -Djdbc.drivers=org.h2.Driver \ // -classpath commons-pool2-2.3.jar:commons-dbcp2-2.1.jar:commons-logging-1.2.jar:h2-1.3.152.jar:. \ // PoolingDriverExample \ // "jdbc:h2:~/test" \ // "SELECT 1" // public class PoolingDriverExample { public static void main(String[] args) { // // First we load the underlying JDBC driver. // You need this if you don't use the jdbc.drivers // system property. // System.out.println("Loading underlying JDBC driver."); try { Class.forName("org.h2.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("Done."); // // Then we set up and register the PoolingDriver. // Normally this would be handled auto-magically by // an external configuration, but in this example we'll // do it manually. // System.out.println("Setting up driver."); try { setupDriver(args[0]); } catch (Exception e) { e.printStackTrace(); } System.out.println("Done."); // // Now, we can use JDBC as we normally would. // Using the connect string // jdbc:apache:commons:dbcp:example // The general form being: // jdbc:apache:commons:dbcp: // Connection conn = null; Statement stmt = null; ResultSet rset = null; try { System.out.println("Creating connection."); conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:example"); System.out.println("Creating statement."); stmt = conn.createStatement(); System.out.println("Executing statement."); rset = stmt.executeQuery(args[1]); System.out.println("Results:"); int numcols = rset.getMetaData().getColumnCount(); while(rset.next()) { for(int i=1;i<=numcols;i++) { System.out.print("\t" + rset.getString(i)); } System.out.println(""); } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (rset != null) rset.close(); } catch (Exception e) { } try { if (stmt != null) stmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } // Display some pool statistics try { printDriverStats(); } catch (Exception e) { e.printStackTrace(); } // closes the pool try { shutdownDriver(); } catch (Exception e) { e.printStackTrace(); } } public static void setupDriver(String connectURI) throws Exception { // // First, we'll create a ConnectionFactory that the // pool will use to create Connections. // We'll use the DriverManagerConnectionFactory, // using the connect string passed in the command line // arguments. // ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(connectURI, null); // // Next, we'll create the PoolableConnectionFactory, which wraps // the "real" Connections created by the ConnectionFactory with // the classes that implement the pooling functionality. // PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null); // // Now we'll need a ObjectPool that serves as the // actual pool of connections. // // We'll use a GenericObjectPool instance, although // any ObjectPool implementation will suffice. // ObjectPool connectionPool = new GenericObjectPool<>(poolableConnectionFactory); // Set the factory's pool property to the owning pool poolableConnectionFactory.setPool(connectionPool); // // Finally, we create the PoolingDriver itself... // Class.forName("org.apache.commons.dbcp2.PoolingDriver"); PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:"); // // ...and register our pool with it. // driver.registerPool("example", connectionPool); // // Now we can just use the connect string "jdbc:apache:commons:dbcp:example" // to access our pool of Connections. // } public static void printDriverStats() throws Exception { PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:"); ObjectPool connectionPool = driver.getConnectionPool("example"); System.out.println("NumActive: " + connectionPool.getNumActive()); System.out.println("NumIdle: " + connectionPool.getNumIdle()); } public static void shutdownDriver() throws Exception { PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:"); driver.closePool("example"); } } commons-dbcp-rel-commons-dbcp-2.10.0/doc/README.txt000066400000000000000000000027071447311732500215720ustar00rootroot00000000000000=================================================================================== Before running these examples make sure you have registered the database driver you want to use. If you don't you will get the following error: "org.apache.commons.dbcp2.DbcpException: java.sql.SQLException: No suitable driver" The DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property. For example you might specify -Djdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver as command line argument to the java VM. A program can also explicitly load JDBC drivers at any time. For example, the my.sql.Driver is loaded with the following statement: Class.forName("my.sql.Driver"); =================================================================================== PoolingDriverExample.java Provides a simple example of how to use the DBCP package with a PoolingDriver. Look at the comments with that file for instructions on how to build and run it. PoolingDataSource.java Provides a simple example of how to use the DBCP package with a PoolingDataSource. Look at the comments with that file for instructions on how to build and run it. See also the Javadoc documentation (use "ant doc" to generate it), especially the package documentation for org.apache.commons.dbcp for an overview of how it all works. The test cases (the source files whose names start with "Test") provide some additional examples. commons-dbcp-rel-commons-dbcp-2.10.0/doc/abandon.jsp000066400000000000000000000111201447311732500222010ustar00rootroot00000000000000 Couldn't build an initial context : " + e); return null; } try { Object value = ctx.lookup("java:/comp/env/jdbc/abandoned"); out.println("
DataSource lookup"); out.println("
jdbc value : " + value); out.println("
jdbc class : " + value.getClass().getName()); out.println("
"); if (value instanceof DataSource) { return (DataSource) value; } else { return null; } } catch (NamingException e) { out.println("
JNDI lookup failed : " + e); return null; } } private void getConnection1(DataSource ds, JspWriter out) throws Exception { System.err.println("BEGIN getConnection1()"); out.println("
BEGIN getConnection1()"); Connection conn = ds.getConnection(); System.err.println("conn: " + conn); out.println("
conn: " + conn); System.err.println("END getConnection1()"); out.println("
END getConnection1()"); } private void getConnection2(DataSource ds, JspWriter out) throws Exception { System.err.println("BEGIN getConnection2()"); out.println("
BEGIN getConnection2()"); Connection conn = ds.getConnection(); System.err.println("conn: " + conn); out.println("
conn: " + conn); System.err.println("END getConnection2()"); out.println("
END getConnection2()"); } private void getConnection3(DataSource ds, JspWriter out) throws Exception { System.err.println("BEGIN getConnection3()"); out.println("
BEGIN getConnection3()"); Connection conn = ds.getConnection(); System.err.println("conn: " + conn); out.println("
conn: " + conn); System.err.println("END getConnection3()"); out.println("
END getConnection3()"); } ]]>
DBCP Abandoned Connection Test

DBCP Abandoned Connection Test


DataSource ds = getDataSource(out); if (ds != null) { getConnection1(ds, out); getConnection2(ds, out); getConnection3(ds, out); }

OK
commons-dbcp-rel-commons-dbcp-2.10.0/doc/static_structure_dia.gif000066400000000000000000000236431447311732500250110ustar00rootroot00000000000000GIF89a#÷ũ€€€€€€€€€ĀĀĀĀÜĀĻĘđ@ ` €   Ā ā @ @@@`@€@ @Ā@ā@` `@```€` `Ā`ā`€ €@€`€€€ €Ā€ā€   @ ` €   Ā ā Ā Ā@Ā`€ ĀĀĀāĀā ā@ā`ā€ā āĀāāā@ @@@`@€@ @Ā@ā@ @ @@ @` @€ @  @Ā @ā @@@ @@@@@`@@€@@ @@Ā@@ā@@`@ `@@`@``@€`@ `@Ā`@ā`@€@ €@@€@`€@€€@ €@Ā€@ā€@ @  @@ @` @€ @  @Ā @ā @Ā@ Ā@@Ā@`Ā@€Ā@ Ā@ĀĀ@āĀ@ā@ ā@@ā@`ā@€ā@ ā@Āā@āā@€ €@€`€€€ €Ā€ā€ € €@ €` €€ €  €Ā €ā €@€ @€@@€`@€€@€ @€Ā@€ā@€`€ `€@`€``€€`€ `€Ā`€ā`€€€ €€@€€`€€€€€ €€Ā€€ā€€ €  €@ €` €€ €  €Ā €ā €Ā€ Ā€@Ā€`Ā€€Ā€ Ā€ĀĀ€ā۠ā€@ā€` †ā€Āā€āā€Ā Ā@Ā`€ ĀĀĀāĀ Ā Ā@ Ā` Ā€ Ā  ĀĀ Āā Ā@Ā @Ā@@Ā`@Ā€@Ā @ĀĀ@Āā@Ā`Ā `Ā@`Ā``Ā€`Ā `ĀĀ`Āā`€ €Ā@€Ā`€Ā€€Ā €ĀĀ€Āā€Ā Ā  Ā@ Ā` Ā€ Ā  ĀĀ Āā ĀĀĀ ĀĀ@ĀĀ`ĀĀ€ĀĀ ĀĀ˙ûđ  ¤€€€˙˙˙˙˙˙˙˙˙˙˙˙!ųũ,#@ūû H° Áƒ*\ȰĄÃ‡#JœHąĸŋ3jÜČąŖĮ CŠI˛¤É“(SĒ\ɲĨ˗ƌ)pæAš q>´YRį˟@oÄéŗbQ„Gwæ:0éE§FûA JĩĒÕĢXŗjŨ:5b׏>ŋ6@VėÖŗ ÍĒT‹%ÛļpãʝKˇŽŌĻ2ĨâĨY–Ŧ^ŧ5ËūmÚ7°ĐÁ< œˇ&âĮ};ÖKô1ãĘ˙úĩ{w0åəgæë82dÂ~IWŽ|y2ãŌ{ĨŽVxķęØymĒöü™įm܃ Nŧ8ČŽo+î4ųōįĐŖKŸN­ķęØé^ĪÎŊģ÷īāÃūŋO^{ųķčĶĢ_v;û÷#ŨßOŋž}ōōīëēŋŋ˙˙B—_€"Uā&¨āJ.x`ƒF(á„ũAHá^¨á†včĄx~(âˆvđΉ(ύâŠ,ļčâ‹0Æ(ãŒ4ÖhŖŒ!’hŪ‚&Ūčã@)ä7æ¨ãO=9d’=–…ĸ“˙˜(%”QJeŠVfųä‰PZФ’|MĩŲ‘Áy^’_â¨b—d=Ųæ•Wĸg•\rųf•Sz '•]ĻY$™ĪÉéį „jčŠfލ‚‰2$襐F*韋VjéxkMĒéϜļØčR—†*ę¨m}šV§5ĘŲd“uîŲ*ĢūpÖ ëŦ¨Â¨Ķ˜EęŽŧö꒩ =Zë°Ä. “¯ČN(ląĖ6;#°vmJ’U7íPÎfĢ-ŽÉÆĩlšLÆĒ§–áŽ뜲ļē'šånųfģęFfN^{ŦrÍY ͤÂ‹nœŦú+kĀâ ëŋãž+oˇp}ģíÃÍڋ_t¤‰č0Ä×*1ÃwL›t{,ōČ$“2I'—ŦōĘ,#˜˛H/ˇ,ķĖ4ŗíÅįŧiĖķņ\ķĪŧŪL(ģŽM+FŋēĻJ'mt_M=Ģ—8ŋčķ{ˇžļÚlŽÕļ›×ŸÉ–ZlĻ1Q\{VąÚ‹m›`a ôÜ- ­ķŨÅ^m3ūŨ|÷ ‘ŪUë7xļåĒގŽ9vm{U,ˇØ†õ¸ÜYŗFųŧ™AÎøæ„q^Ú w=øčŽ h6éøvĻõæĸĄ›æ˛…í:ä—Ģ6ųÛŠáŽúîO8ī jô;đÄ?č{ņAáŠüō˧uzęÍG/ũôɡ =õØg}ÕxwīįđqīũøÆ–Iūų‚¯}°6ú›đû Ŧîûî֟.Â÷y?ēå,ū“Ā –Ūūįĸ;)Mj‹×ēĸÆĀĸŨxzWĨF5ą%ķ3X™¤‚IUd ąÄ4§Ah'ä×ú´ƒž9.Œá—.)‰xP†8ÄŌ E%¸úđ‡ū@ÄNž‚HÄ"ą8=<ĸ—ČD­¨¯‰PŒ"Ÿ(Å*Z{T|PˇhÁ+zŅAYü΀ž57ŒiĢēŸ´ä&&pū+žÚˆF;ÅQPmJc õˇ%Ģ}ņ.ëÕšHH…ˆŦĘ!Ĩ•ČF:r9‹äN$IÉJŠŽ‡–ˤ&mXČNÚJxÂķ¤(Y4ÉMzņ†@ĸŌMhÆVŌɍÄŌ[ÉG…ę(ˆ+]FPŲÆpeŽ ƒãû(ĖWÚq˜kĸÚģôL"•Ō”Väå(Ŋ7ÆPNķšĪ„Ļ6–Ímzķ›Ö '8ĮINe]Ĩ›åL§:­’˛AÚą_í[šŧ .znjļūęâ:÷IˇgJSS˙Ü"ģøIPŋ…1 ×Ė: ĘPũ,´Ą¨é$JҊ.ĒAĩ¨F7zū´æo^š$FÄ$Îēqô¤,3KF'‚œĮĄôĨĸkž˜ßœ.4¸qŪLySĶ`õ6Y{PtŗSĄâ4W•ÃL—jĐ×,F—Öãéė<˛6†#ÕZ)SˇĘ!­ęĘ"‰ō*WĮĘ(¤ž¨g]œYmzÔ°ĩ5sjŖiP Į˛ÚՑbŊĢ^÷j¸°ä”¨ąŖĢeØzVŲõ­ŧÁnl*Rž:Šy},E#+3ĘJö˛ĒSĖbûŋFõ0œũë` ÔÖ8N3FĩLy$gÚhÉ4ĸ-ū-be+:ÖĻ–ą‰Ŋ­SHšžZŗĘåķtŠÕ]*/pĨK ՑFK>’SÜgAëRâ.%‰ .é’ō[Ŧt׆Ãõ)#ĩ[Pĩ|7hÍ%¯zšĶõē—3įĨY|ߋŌųÖĖžôĩ(~ī›ßūžŗžū 0’`ē_øŠ>°‚!ģā "4ĄK°É”áQJŒŲáūČeŋ<ŗrü—ļЖ–zmôdN §ĻA_.pNîs 2EÜŠ ķ¨ÂĸDņ‰÷…ãNÚ¸Áņáq Šc y-BŽ0Ÿ&.všŅ–Ģ\eŠg(“ãéĮGN'Ї\Č"g™Â\æĸ—ŗ#VĪęëWasū§ė)DŠQ‚ 3&>ålŽ4ÂԌzО*Ā›`ŲĒH ī…Ølĩ7Žp]qŒ˛ž‘ÆL)įų˜&tלfNd&Ģt˙üåQ–Ķĩ>-ęR‘ÔĻNõíĻi‚Z‘ģí\O¤jæŽ*UšĒ–¤[Õ¯7O Î.Ļ'>§bCãŲÍoĻåĄĄL)A*×ČbuĢ]øjĒTŽŽŗmZŌÖ°i­¸ģļļÄéV¨ĐnOī’[Ņã˛;Ũ§ TdžēOw_u<؎[áęÉøFÛáwgo ī˛bzœöÆuÁYUHZ˛Ú OŠxņˆ[Ķ‘­øÅ7ŸiĮ°›’ö¸¤ūhx(NŠ}īØ˙đčëW‘ëײŧŗ].sKŲ~˛Dô—Ílnõy(tfą‰æJ›ÉOvĨ͓Ys{;éĩD% Ŗžlbë9á@— Ē‚Môî/‚îâzÎëˆl`†Q/=ûÉ ōĩŸ¯ín_ĘĩYkŽÛŊŧĶŊģŪ×9÷ŊûũR}˙ģāÉøÅ]A­ļâŗëđ›ņŖgŽŋlÃ`§|b´'ž’…w‹5ˇĐŪĶÎ>ŊęɜúÕģūāģ2ũëOĒvŌSy—ŖˇŊBgēړQ._` YiĖŸ‚2~!Ŋ įÚ§,iŗ¯üÁŠ­ųęG~‡Ļ;ū¯OŪÎ÷ēR5w~ÉŪûúEŋúžūölxįwŋü\=ō—?cņŸ?7æÎsÅY™NŌ.øvčt8‡}Kw@ hKPŖa3.ú§w‘~÷×}čwų—81øS‚"¸jÎ5‚&4oÁ\EÕZR•[ßļVãöQ˙FXøƒYõ1ˆUƒäV[w‚{‡Ė'^9„ī†\*hm>˜„ŸER%ˆ!y§„P¸‰S8į–6ē‘6,(pXˆZ4heUĻVpåmú@‡Õ‚Qx†Eˆ†jX2Gx;ģa9˜Ą8Tn°s9‡SnžsmA†žŗ†~d2(‡ŽCWƒØpŦS;ūĄÃ8psˆs8UpŖ;?•†8‰€F‰Ū´]e‰ä…‰‰šČ†Î‡ņ5[ŗ‚mļs[§ÕY´UŠŠ(WĒåH‹YøoįŲ&ƒKhƒŪ‹48Tĩø‰õÁ]8ØoŊ1/š3…%FbWø9ŗÃŒƒ•U‚[nu6xx&7USVÖoȸ8cŖ‡œĶ[_¨Tn¸Sp˜ˆŪ8‡qkĸ%‰Â"üä‰īČ0U%šŗŽĮˆu8ã˜Œ‰Ĩ<¸„;q“ˆ´“Žšm)ŽÕÕ;IĩYú†öˆŽ¸Ž‹˜Œ Y;Ė׌wč:š‘ŦcVhE[ֈVf8Īf=eˆnƒØ‹:ˆ[‡sŠ,yū‹3؎¸Č’uu’;¸Šo¸X2‰ZÕ“ē“)p< ƒčļ‚€’1i’°w—č”LŠQb!Áe]Q QT™‰WI`íĩ•Ö•^šc••a9"XĮwe™~햖“%•l –kų– E–—&—ņH{vy—x™—ęD—Gâ—|i\ĒPŗfę9†įp=(!dēuDVŠZē3u)o™6ĒÚŠŸPēĒŦ:™ĨŠ“ŌǞ:Ģ ¤Ŗv<ļšĢ÷ļnēÚĢĮĻžŦkJqÂZŦĘÆjŦ7CĢĖĘĒŅ–Ŧ"m¨ēuĪ ­¸k]:œÄš­o y?Ō§j2rÕ [o(‘ÛxŊ‘C ;BYŽg‘ŅEŠĶˆ‘)­pšĄ˙Wœ(ę€'úa*:§™~*~ãʃK9Wųö“ÆČmäøŽ‡5WėČo/yyi¯éųŠ^G°žŌžÅjąĶ P{“Ž,eŠŋēĢļ†\Ÿ¸ŦÍÚū˛J˛=ĩmûZDYw ×mŠŗ8ÛXžu“8‹]j˜q8*•u§(hƚõĘĢC‹wÁã6&q-![pe&hõ–‚_XnV6 Ã‡˛ÖĩwčŸĶ‘qh­_Ĩ´ņ]#kļ÷j2ĸlK!nKwŸ2ĩžZeâ™q[YÃ:vģˇ_iĩy ¸ŠK°J¸Œ)˛ÄЏ>貎K¤Ėņ¸’Ë ‘;š–K i÷ąCš[c)&ך¤Z_ņ¤­€ęĨÂŽ÷ Ļ*FКĨ›Ū5C-ÚĄū÷Ļ´Ë}_ēr‡Brß#ģZŖ“'§ĩkētĒēĀéē´Wē’Z?Ėų¯’Gy t}Đ;ŊwÔxū$¨O §āēyÔˇĸûęŧÛû§Ķ°ũŠy7´™+šžÜËtšŠ1ܡžr$° xēáËĸā÷ˇƒ&ēÂû­~vĻÖ6rlFO4Zϟ[Cͅą¤Ā .™Ģŋ k>\§đÁĖQ—{Á0Z&ŧÁØYšüÁĸé~ŠË¸$LOXÂ(|†›Â,lRîØÂ0|ļ1<ÃÔBÃ6,z7œÃ€¨Ã< ˇ|Â@š= F‹GÁ|6Ä ‚ŋØzŧŠ{ŧŗĢŧ„&>ēëLHŧФŌ¤dŊüĻzg¨ģ­]œžķۜøęŊÎŧTŁ„^ögÄŠdœjŧÆą—{nüBqŒzl|ĮĸĻÄéĨĮYÆĮūMëĮÜz‚<Čy\ČGČV‰ČúUĮģĢp`åČlĮČ,ÉŧÉFaÉvLÉuŅ›Æ+tĘËē>ęg Ú|‘,~ļÛēOʡ+ĘâĘɝŒžâ+BZ}NĶKŅûŧĩg' •§\ĻZ|y*ŠGKc˜e,ŋ{úOŠÜ˜ú+Žä(D8RšœĘ° Ë,TÍ Œ{mŦÍTŒÍq ΅ÜĖâjä\ÎZR蜖āsÎëܗŪõÎI‹„ŨėÍ+Ī+ô2XlĪŒĪ$čÂÔ<Ļ0ŋp†tĖôtOvĐ4ilŌrĮt€ =žW—'‘öœîėĪęœÍņÛŊļ,ĖÚgsK—gČLÆdÆøŅ:ūP]D“´Ā=zŅ+í-ráŌ Ķ1=Ķ7]Å6ĶũĩĶũĶîÔB­^D]ÔڕGÔc VL­Ŧ%‹)ęptx69kŽ‹…ŠēŊFI”=é‹4y°/ųÔģ™]ũ¨ŒÚ‰ėú“#ųē™cHŲŽĨėŽ]ȏpšŠˇŗ´dũ΁Ü×É æVÕc†‚u‹wØ^Í6՘”Céŗ¯Ķ:ŖčŒ^K# Øx•’}I^[]›M×ɕ°îēÖqíocXĢ ›ÖĻ}ؘũHGøÚqkÚmíūH…â¨YPûTåX‘ˆ8Uä&ŽûˆŽ”A‹˛ŨP*Z˜ŗ“Ô¸ØšØØŧūˆi5ØŅ­‘a˜ÜsŠŨŒ+’M\!âEû\ÜŊ`Ë-nŅŒ¸Õŗb¸ƒēČŪGYŪë5„ĩĪ},ßF6…SéË:„iX6ߍßĻßXŲd{ÜŠŪ“ā\ƒ¨qƒß´žW‹šÔŽ•­ŽÎžážŧŖ Ž2.F#Š9ĩF RĻbˆĄĸßžYŊlÖŊ\ß%(ĩ'žT*ɍÎH¯n×ÍßĒUâ‡ãHÖˇ•ĢN„Į˜ ęizâŖęēÆę*7´_abMŪŗF¨|-¸āâkÛŽQíÚ¤Îjčģ5p”퓊.˛xė¨ā_ ”5ÉÜĮŠŦl#ļ ÛãĪnkžéųØ1šéž’1“” čœ\k)këmĘČ.8 “;낏î/ŧ#9IŽdƒƒGiėŌ}ÕŖÕíˇaŗ3ÛVâ‰ųžė)žÎ+ŦŠy?Žå§ØˆÃ tƝŗtũãÍļ=9œZėøŽÛ¸ŨÖĨ¨°ūoŌEņSÛv¯Īįéļ퓮.`2e–XÃë8ļ°ŽÃ3ŽI‚žķ•2ëÛ$Ø@ô2Žx‹\ôĻNãHāJīžXųôWõRIT_õ–2ķ„ƒõ€×Ô\Q^˙õ„gŸb¯#Zīáeoöj™öKOöl­nųöpŋörõq_÷ƒ&–x/ˇŧ÷|¯÷~OÄ}ø‚ø„/Į†øUš—Š/˜ŒßøŠ9˜ŋø?ųˇ*ų–ų›ųûqö{Ãųķčų ŋDĸ?ú§fúīXú¨ī`Ģŋ˛XOĶøŠú2}cü\>Qûķ)ûĨ!¸˙šēßĻĩĪ™íŠÁ/üģYüũŒōk&ˇČŸJĸūZcÖLŧeŦf°[ũ,힠ڨ_ÚŊ”hų´ĨvJŸÅĖa$Ԍf}¸oãY‚Øīĸáé§ãkulTŌãŋʛ Y˙ 0°`A‚˙*4Č0!‡ "„˜pāEŒ5n䨑`?ú$Y˛dH“)UŽ)’åK˜1eΤYĶæMœ9uîäŠĶeOŸ…ēĐáDŒF+"¸ÔŠE‰LĨĨJô'PŦYĩnåÚįŌĒa‡‚ ąlS‰!'ž…jö"[°bå5‰˛îU­xŊîåÛ×ī_Ā1õn9×°A¸•Ēuh–ņZ‹l2VKö1ÜÙæÜŲķį•q5Î\V4iÔū‡ˇ\ôkØąegm øtjÜaoįæíąölāÁ…î]ÜøqŪŋũ*ŪÜųsׯw#§^ŨzRčŲĩsž~Ũû÷䰙o'_žüøŊŨÁ¯goŊyøņCˇ§_ôûŽøåīįĪ]ŧ}ŦJŋū 4đ@›#0/tPŖiKpB +´đB 3Ė)BŦÔ{đCī8JD K4ņDST‘'YņÅ[ÜIÆk´ņFs”Æ aœėąŖĸęČ1 }kP9ģōĶqI&›tōÉįxüęŧ kĢ"Ę*{ëGÄÜ:2Ĩ˛NJJ2Ë4ķL4}úÄ*Ŋ<Č´ 2Í(Š(rP¤0C3M>ūûôķĪ%ĨŧÉCđ°$ČÎÆ"S4ÎD%Ô:<“sO@+ĩôRL ÔĻG?ėÔGĢT’tĶ–25õTTSTš>õU͐d•UUkĩõVLi•ÉUX{•KWÁpvXb‹% X˜xõuŲPĨ3öYhŖ­Ų—”eöZލeI[iģEÕZlÃ}K<šíĖÜU×w]÷ŧŊ\vąEˇŽr1Ä3ÅyOŠw_ŨÜĩ^~}Í÷Øz˙%øÄ‰ xálũ­`ß$3˛;87:­âeW˓¯„=ëØ+ŧ>ļM]ę$v/Û˒ëĐ"ŗŊNd‡DÎÍË([ĢæŠ{Sg¨Ū˛-.Y~ų¤Á$Eū˜ŗÄŽ!6rË 1Æl1Dz3˛šw–ShŽĻ+æŊļŗˆĐrël¨á$ËĒét;)Œg6ēZ“yÂÖė™dãˆüQˇÔļZå-Ņž3NÛŪZė!ÁģdÂëD íÉļnLŠCƒ|[1Ë%¯.Ō™æūSīE}–q‹ĶŧlÉŨLËÎÍW¯˛õĄ?uČđ.0IßĪ÷žB†w6÷ŪvNuWģЎįĪų>}yę7C^Ķꗇūa{A’–øėéÛūúdÃ×}|ŧ3D˙qķ^Ÿ|QÛwŋÛ÷Ĩ_ū€ë‡ūõėžP€Œ’úx@&P”2Øø@FūĐt˙“`-xÁūé¯&Ä`=øAM„#$a ŋ%BĻP…+,CĮBÆP†+ráŽfxCæA5 –}øC ‚A$b&ëˆKdb;Dđáī;IDĄ­H?(J‘_TâŊh,nEQ‹ ŋxF脱7q{ZFȂ2 Ŋą(]j„>WFéŨ‹5Pœ ôöæĮ­˜™Rcn %Dv)pQIYÚ*w%Ÿ -.ˆäY"9Arī`z÷~ĸGīå1”ž$ØŊ> —˜Ĩ*Õ)]šĮMúŅ•Š,e-G™ÉAĻŠ¸9åĨ:Eqm ÜYfwąaZūQÖÂeúlIĘW.m”ˇl%+ĄIÍWūæ”ą”æUhiÍiRŗ›Ąlf.ų´KÔČq™‹âœŖˆų:vÆķ—Ā\§;+ °Å×˙FËÂĸ‘VĩP*įLWk›Úœöĩŗõ…KÛô0įŗČrl8W=ÜŽļ™x n^Ūŗ[†b“–ŗĖ+bGÕÜærŗ‹ũmqŅØŅÚZwCÛ¤k%ëŨUJˇŽŒ].[áę[í^ˇŠé)piĐåFŽ 5ė]÷˜Ô˛ 5ĢĖÍ*zŲÛÄŋū—S2ZlĖÄ8YR2°‚ûš`ķNIĻ0| a`5¸ÂŊ°€ĩĨá ›ŗÃÖ]ˆM|#Ά-Ŋ%>q‹iXŨ’ēXÆ3ļí¤4IcįØÂŲūŨĄŽ}üc!ō8Æ@&r‘ĶÕGYÉKæŖyÉd(GyÂ4M˛”­|eQšĘXær—C7b/‡ųŋkx\Zf–bÍ@2™×œN5ŋVđЎŧ͂ū\ģ‚ŽlᐙqXįĨŲih’ûHÉŲĸËÉîįmQúîTęļqJŊ÷ÁƒlüמWøĀķņü ŋx‹)ōâ“üäŲĶx >Ūōã:ķæëCgĪ^Ė;ÄüčModˇž^õĢw)ūLY˙zØÆą§}íĪ%dÛį^÷)­éî}˙û)ģøÃ'~{g_|ä'ŋļĨW~ķEė_įG?úĖ—~õŊH}ëgÁÚįžōąß}đûđûá'˙ Į_~ô¯đüég? ×ß~øĮڄšũûãī.ûW>ôĩģ˙†ķßųũ3ĩū ą˙;ŧGC41™tú4ÕđšES@VģŗİųÛ´Y‹\ ļ}ûļŽI@]ģ7^3ĻĒ˒ ÁĘ A ‰7ë™@ äŸ9yAŒÁO3”{[›vŗšg8˜[9’Ķ7bŖ¸€9k[6}ct°ôą@GÁœĘqļts8ĪÁAÚÂŦBxĸēžSÁ8ūB$Ė  ĀâØ$ôB\)C$ C1,3T04ŧ›āYC6lCÃ%”ÃĄÃ:tÁ‘A?üC@ DADB,DC<Ä@ÔÃ1ŗCElÄyÃŋ€DG ?IäŊIŧÄãCLÜD„aDNüÄwņDPÅ-#ŸJ$Åæ;EBEVüQlEX4UüŖXŦÅķxE[ĖÅ/CD^ėE_üE` Æ9yĸFcmŌĒƊTY5šA­*mU.ĻŧTuVpĨTķĘ&ŽĘ/zŊ/­ēq Īj‰Už:Ŧļū*VaE’auTJWUJŦBUX꒩d”V…Ē…ėWįD˛üĸ2)|-؜2Ve=ׅ…ĨĻĒWQĢø:Öf Y‹žÔRĸ,›–ĻlŲŧ-šŊŲŅWœŨY'ZE˛îZžāŖĶjU˛äYđë-•­%ūYÎ؈EU¨ÕËZŲŽ]ZD-¯ŸEÚîSURũڙZ›•Za Zč:VyõŲPEÖŖåÚęSUx-(‚úUøbĘWe×`Ũ¯MŠ×EŦŪĘ׸ÍÚsuÛōË?Ą0%ÜÁS\ÆM8ģz!ôŦčØTëĄÄmÜ\BŽĀ…&úJ1OĩŠw=+LŨ/ŧUیŊ%L\ĖeE¤øÚXĻeÖʍÚY]ÛģĩŲS%¯R•ÜÕE¯õX`=]ŲõØņ‚ŨÁ^{ÕŨ%Å ËŲwL^¯ŧ\įÕCčŪ6Ô\˜mJŠXû‘ÖĸĨ^ÕLÛĒuW†}Zá ßáũއÂÚĻÕ^ī=ÂŪ]Z°åĶō XÚ-ßŗíÕŋmßO„[ŧ,O’Ûēå*´íß>Žž%]f_ũeAܜŪÎ!~āû‹` †? Ļą€;commons-dbcp-rel-commons-dbcp-2.10.0/pom.xml000066400000000000000000000433371447311732500206500ustar00rootroot00000000000000 org.apache.commons commons-parent 60 4.0.0 commons-dbcp2 2.10.0 Apache Commons DBCP 2001 Apache Commons DBCP software implements Database Connection Pooling https://commons.apache.org/dbcp/ apache.website Apache Commons Site scm:svn:https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-dbcp/ jira https://issues.apache.org/jira/browse/DBCP scm:git:http://gitbox.apache.org/repos/asf/commons-dbcp.git scm:git:https://gitbox.apache.org/repos/asf/commons-dbcp.git https://gitbox.apache.org/repos/asf?p=commons-dbcp.git Morgan Delagrange morgand Geir Magnusson geirm Craig McClanahan craigmcc John McNally jmcnally Martin Poeschl mpoeschl mpoeschl@marmot.at tucana.at Rodney Waldhoff rwaldhoff David Weinrich dweinr1 Dirk Verbeeck dirkv Yoav Shapira yoavs yoavs@apache.org The Apache Software Foundation Jörg Schaible joehni joerg.schaible@gmx.de +1 Mark Thomas markt markt@apache.org The Apache Software Foundation ggregory Gary Gregory ggregory at apache.org https://www.garygregory.com The Apache Software Foundation https://www.apache.org/ PMC Member America/New_York https://people.apache.org/~ggregory/img/garydgregory80.png Ignacio J. Ortega nacho Sean C. Sullivan sullis Todd Carmichael toddc@concur.com Wayne Woodfield Dain Sundstrom dain@apache.org Philippe Mouawad Glenn L. Nielsen James House James Ring Peter Wicks pwicks@apache.org org.apache.commons commons-pool2 ${commons.pool.version} commons-logging commons-logging 1.2 org.junit.jupiter junit-jupiter test org.hamcrest hamcrest 2.2 test org.mockito mockito-core 4.11.0 test org.apache.commons commons-lang3 3.13.0 test jakarta.transaction jakarta.transaction-api 1.3.1 tomcat naming-common 5.0.28 test tomcat naming-java 5.0.28 test org.apache.geronimo.modules geronimo-transaction 2.2.1 test org.junit.jupiter junit-jupiter commons-logging commons-logging org.slf4j slf4j-simple 2.0.7 test com.h2database h2 2.2.220 test org.jboss.narayana.jta narayana-jta 5.12.7.Final test org.jboss jboss-transaction-spi 8.0.0.Final org.jboss.logging jboss-logging-spi test org.jboss.logging jboss-logging 3.4.3.Final test UTF-8 UTF-8 1.8 1.8 dbcp RC1 org.apache.commons.dbcp2 2.10.0 for JDBC 4.2 on Java 8 sha512 2.4.0 for JDBC 4.1 on Java 7 sha256 dbcp https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-dbcp site-content DBCP 12310469 2.11.1 javax.transaction;version="1.1.0",javax.transaction.xa;version="1.1.0";partial=true;mandatory:=partial,* true 2.9.0 true Gary Gregory 86fdc7e2a11262cb false false true 0.5.5 3.2.1 clean verify apache-rat:check japicmp:cmp checkstyle:check spotbugs:check pmd:check pmd:cpd-check javadoc:javadoc org.apache.maven.plugins maven-scm-publish-plugin ${commons.scm-publish.version} javadocs org.apache.maven.plugins maven-checkstyle-plugin ${commons.checkstyle-plugin.version} com.puppycrawl.tools checkstyle ${commons.checkstyle.version} ${basedir}/src/conf/checkstyle.xml false com.github.spotbugs spotbugs-maven-plugin ${basedir}/src/conf/findbugs-exclude-filter.xml org.apache.maven.plugins maven-javadoc-plugin ${commons.javadoc.version} http://docs.oracle.com/javase/8/docs/api https://commons.apache.org/proper/commons-pool/apidocs http://docs.oracle.com/javaee/7/api/ org.apache.maven.plugins maven-surefire-plugin ${surefire.argline} org.apache.commons.dbcp2.StackMessageLog **/Tester*.java **/Test*$*.java maven-assembly-plugin src/main/assembly/bin.xml src/main/assembly/src-tar-gz.xml src/main/assembly/src-zip.xml gnu org.apache.maven.plugins maven-scm-publish-plugin api-* org.apache.maven.plugins maven-javadoc-plugin com.github.siom79.japicmp japicmp-maven-plugin cmp-report true ${commons.japicmp.breakBuildOnBinaryIncompatibleModifications} true true true ${commons.japicmp.ignoreMissingClasses} ${commons.bc.version} jakarta.transaction jakarta.transaction-api 1.3.1 com.github.spotbugs spotbugs-maven-plugin org.apache.maven.plugins maven-javadoc-plugin org.apache.maven.plugins maven-changes-plugin ${commons.changes.version} src/changes 12313721,12326766,12328750 org.apache.maven.plugins maven-checkstyle-plugin ${basedir}/src/conf/checkstyle.xml false maven-pmd-plugin ${maven.compiler.target} pmd cpd jdk9-plus [1.9,) --add-exports=java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED commons-dbcp-rel-commons-dbcp-2.10.0/src/000077500000000000000000000000001447311732500201105ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/changes/000077500000000000000000000000001447311732500215205ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/changes/changes.xml000066400000000000000000002421371447311732500236630ustar00rootroot00000000000000 Apache Commons DBCP Release Notes Fix StackOverflowError in PoolableConnection.isDisconnectionSqlException #123. PerUserPoolDataSourceFactory.getNewInstance(Reference) parsed defaultMaxWaitMillis as an int instead of a long. Reimplement time tracking in AbandonedTrace with an Instant instead of a long. Migrate away from deprecated APIs in Apache Commons Pool. Fix possible NullPointerException in BasicDataSourceFactory.validatePropertyNames(). Fix possible NullPointerException in BasicDataSourceFactory.getObjectInstance(). Connection level JMX queries result in concurrent access to connection objects, causing errors #179. UserPassKey should be Serializable. LifetimeExceededException should extend SQLException. Replace Exception with SQLException in some method signatures (preserves binary compatibility, not source). Don't leak Connections when PoolableConnectionFactory.makeObject() fails to create a JMX ObjectName. Performance: No need for map lookups if we traverse map entries instead of keys. Performance: Refactor to use a static inner class in DataSourceXAConnectionFactory. Reuse pattern of throwing XAException instead of NullPointerException in LocalXAConnectionFactory.LocalXAResource. SpotBugs: An overridable method is called from constructors in PoolableCallableStatement. SpotBugs: An overridable method is called from constructors in PoolablePreparedStatement. Wrong property name logged in ConnectionFactoryFactory.createConnectionFactory(BasicDataSource, Driver). Throw SQLException instead of NullPointerException when the connection is already closed. CPDSConnectionFactory.makeObject() does not need to wrap and rethrow SQLException. PoolingDataSource.close() now always throws SQLException. [StepSecurity] ci: Harden GitHub Actions #282. Fixes typos, missing or misplaced characters, and grammar issues #299. Add and use AbandonedTrace#setLastUsed(Instant). - Add and use Duration versions of now deprecated APIs that use ints and longs. - Internally track durations with Duration objects instead of ints and longs. - See the JApiCmp report for the complete list. Add PMD check to default Maven goal. Add Utils.getDisconnectionSqlCodes() and Utils.DISCONNECTION_SQL_CODES. Make BasicDataSource.getConnectionPool() public. Add github/codeql-action. Bump actions/cache from 2.1.6 to 3.0.8 #147, #176. Bump actions/checkout from 2.3.4 to 3.0.2 #139, #143, #173. Bump actions/setup-java from 2 to 3.6.0 #229. Bump actions/upload-artifact from 3.1.0 to 3.1.1 #231. Bump checkstyle from 8.44 to 9.3 #121, #130, #149, #158, #190. Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0 #210. Bump commons-pool2 2.10.0 to 2.11.1. Bump junit-jupiter from 5.8.0-M1 to 5.9.1 #125, #136, #157, #203, #218. Bump spotbugs-maven-plugin from 4.3.0 to 4.7.3.0 #140, #154, #161, #178, #192, #200, #204, #213, #234. Bump spotbugs from 4.3.0 to 4.7.3 #124, #133, #151, #164, #177, #189, #214, #230. Bump org.mockito:mockito-core from 3.11.2 to 4.11.0, #128, #138, #152, #175, #188. #193, #208, #215, #232, #235, #246, #252. Bump maven-javadoc-plugin from 3.3.0 to 3.4.1 #131, #184. Bump maven-pmd-plugin from 3.14.0 to 3.19.0 #132, #172, #195. Bump pmd from 6.44.0 to 6.52.0. Bump narayana-jta from 5.12.0.Final to 5.12.7.Final #134, #156, #163, #185, #197. Bump japicmp-maven-plugin from 0.15.3 to 0.17.1 #137, #166, #174, #211, #238. Bump h2 from 1.4.200 to 2.2.220 #153, #183, #196, #287. Update SQL for migration from H2 1.4.200 to 2.0.204 where "KEY" and "VALUE" are now reserved keywords. Bump jboss-logging from 3.4.2.Final to 3.4.3.Final #162. Bump slf4j-simple from 1.7.30 to 1.7.36 #169. Bump commons-parent from 52 to 60 #180, #219, #254, #278. Bump JaCoCo from 0.8.7 to 0.8.8. Bump maven-surefire-plugin 2.22.2 to 3.0.0-M7. Bump apache-rat-plugin 0.13 to 0.14. Bump commons-lang3 from 3.12 to 3.13.0. Add and reuse Constants.KEY_USER and Constants.KEY_PASSWORD. Add and reuse DataSourceMXBean. Add and reuse DriverAdapterCPDS.{get|set}DurationBetweenEvictionRuns(), deprecate {get|set}TimeBetweenEvictionRunsMillis(long). Add and reuse DriverAdapterCPDS.{get|set}MinEvictableIdleDuration(), deprecate {get|set}MinEvictableIdleTimeMillis(int). Add and reuse CPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long). Add and reuse KeyedCPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long). Add and reuse KeyedCPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long). Add and reuse InstanceKeyDataSource.{get|set}DefaultMaxWait(Duration), deprecate {get|set}DefaultMaxWaitMillis(long). Fix test random failure on TestSynchronizationOrder.testInterposedSynchronization, #84. ManagedConnection must clear its cached state after transaction completes, #75. Minor Improvements #78. Use abort rather than close to clean up abandoned connections. Performance Enhancement: Call toArray with Zero Array Size #20. Avoid exposing password via JMX #38. Remove redundant initializers #98. Simplify test assertions #100, #113. DataSource implementations do not implement Wrapper interface correctly #93. Replace FindBugs with SpotBugs. DataSourceConnectionFactory.getUserPassword() may expose internal representation by returning DataSourceConnectionFactory.userPassword. DataSourceXAConnectionFactory.getUserPassword() may expose internal representation by returning DataSourceXAConnectionFactory.userPassword. DriverAdapterCPDS.getPasswordCharArray() may expose internal representation by returning DriverAdapterCPDS.userPassword. new org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory(TransactionManager, XADataSource, String, char[], TransactionSynchronizationRegistry) may expose internal representation by storing an externally mutable object into DataSourceXAConnectionFactory.userPassword. org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory.setPassword(char[]) may expose internal representation by storing an externally mutable object into DataSourceXAConnectionFactory.userPassword. org.apache.commons.dbcp2.PStmtKey.getColumnIndexes() may expose internal representation by returning PStmtKey.columnIndexes. org.apache.commons.dbcp2.PStmtKey.getColumnNames() may expose internal representation by returning PStmtKey.columnNames. Use Collections.synchronizedList() Instead Of Vector #101. Simplify and inline variables #99. Update PoolKey#toString() to avoid revealing a user name is here. Internal package private UserPassKey class stores its user name as a char[] as it already does the password. Performance of DelegatingConnection.prepareStatement(String) regressed enormously in 2.8.0 compared to 1.4. DelegatingConnection should also cache connection schema string to avoid calling the Connection#getSchema() for each key creation. DelegatingConnection should also cache connection catalog string to avoid calling the Connection#getCatalog() for each key creation. BasicDataSource should test for the presence of a security manager dynamically, not once on initialization. Bump mockito-core from 3.5.11 to 3.11.2 #66, #72, #77, #85, #91, #105, #110, #116. Bump actions/checkout from v2.3.2 to v2.3.4 #65, #74. Bump actions/cache from v2 to v2.1.6 #90, #108. Bump commons-pool2 from 2.8.1 to 2.9.0. Bump actions/setup-java from v1.4.2 to v2 #69. Bump japicmp-maven-plugin from 0.14.3 to 0.15.2 #71, #82. Bump maven-pmd-plugin from 3.13.0 to 3.14.0 #76. Bump japicmp-maven-plugin from 0.14.4 to 0.15.3, #83. Bump Hamcrest 1.3 -> 2.2 #70. Bump maven-checkstyle-plugin from 3.1.1 to 3.1.2 #88. Bump junit-jupiter from 5.7.0 to 5.8.0-M1, #89, #106. Bump narayana-jta from 5.10.6.Final to 5.12.0.Final #103, #111. Bump maven-javadoc-plugin from 3.2.0 to 3.3.0 #107. Bump commons.jacoco.version 0.8.6 -> 0.8.7. Bump jboss-logging from 3.4.1.Final to 3.4.2.Final #109. Bump org.jboss:jboss-transaction-spi from 7.6.0.Final to 7.6.1.Final. Bump commons-pool2 from 2.9.0 to 2.10.0. Bump checkstyle to 8.44. Bump spotbugs from 4.2.3 to 4.3.0 #117. Bump spotbugs-maven-plugin from 4.2.3 to 4.3.0 #118. Fix BasicManagedDataSource leak of connections opened after transaction is rollback-only #39. Add clearStatementPoolOnReturn #42. Add start, restart methods to BasicDataSource. #50. NPE when creating a SQLExceptionList with a null list. Fix DelegatingConnection readOnly and autoCommit caching mechanism #35. Fix regression introduced by unreleased code clean-up #63. Update to PR#36 - PrepareStatement and prepareCall methods are extracted #37. Do not display credentials in DriverAdapterCPDS.toString(). Do not display credentials in DelegatingConnection.toString(). Do not display credentials in DriverConnectionFactory.toString(). Do not display credentials in PoolKey.toString(). Do not display credentials in UserPassKey.toString(). Update Apache Commons Pool from 2.7.0 to 2.8.1, #48. Update tests from H2 1.4.199 to 1.4.200. Update tests from Mockito 3.0.0 to 3.5.11 #47, #60, #64. Update tests from jboss-logging 3.4.0.Final to 3.4.1.Final. Update tests from narayana-jta 5.9.5.Final to 5.10.6.Final, #61. Update tests from junit-jupiter 5.5.1 to 5.7.0 #62. Update tests from org.slf4j:slf4j-simple 1.7.26 to 1.7.30. Update build from com.github.siom79.japicmp:japicmp-maven-plugin 0.13.1 to 0.14.3. Update build from maven-javadoc-plugin 3.1.1 to 3.2.0. Update build from maven-pmd-plugin 3.12.0 to 3.13.0. Update org.apache.commons:commons-parent from 48 to 51. Update jacoco-maven-plugin from 0.8.4 to 0.8.6. Update maven-checkstyle-plugin from 3.0.0 to 3.1.1. Update actions/checkout from v1 to v2.3.2, #44, #51. Update actions/setup-java from v1.4.0 to v1.4.2 #58. ManagedDataSource#close() should declare used exceptions. Add a ConnectionFactory class name setting for BasicDataSource.createConnectionFactory() #33. Add missing Javadocs. Wrong JMX base name derived in BasicDataSource#updateJmxName. Avoid NPE when calling DriverAdapterCPDS.toString(). java.util.IllegalFormatException while building a message for a SQLFeatureNotSupportedException in Jdbc41Bridge.getObject(ResultSet,String,Class). Fix Javadoc link in README.md #21. Close ObjectOutputStream before calling toByteArray() on underlying ByteArrayOutputStream #28. Upgrade to JUnit Jupiter #19. Fix tests on Java 11. Update Apache Commons Pool from 2.6.1 to 2.6.2. Add 'jmxName' property to web configuration parameters listing. Update Apache Commons Pool from 2.6.2 to 2.7.0. Make org.apache.commons.dbcp2.AbandonedTrace.removeTrace(AbandonedTrace) null-safe. org.apache.commons.dbcp2.DelegatingStatement.close() should try to close ALL of its result sets even when an exception occurs. org.apache.commons.dbcp2.DelegatingConnection.passivate() should close ALL of its resources even when an exception occurs. org.apache.commons.dbcp2.PoolablePreparedStatement.passivate() should close ALL of its resources even when an exception occurs. org.apache.commons.dbcp2.PoolableCallableStatement.passivate() should close ALL of its resources even when an exception occurs. Update tests from org.mockito:mockito-core 2.28.2 to 3.0.0. Update tests from H2 1.4.198 to 1.4.199. Update tests from com.h2database:h2 1.4.197 to 1.4.199. Update tests from org.jboss.narayana.jta:narayana-jta 5.9.2.Final to 5.9.5.Final. Update tests from org.jboss.logging:jboss-logging 3.3.2.Final to 3.4.0.Final. Update tests from org.mockito:mockito-core 2.24.0 to 2.28.2. Update tests from org.mockito:mockito-core 2.28.2 to 3.0.0. Allow for manual connection eviction. Allow DBCP to register with a TransactionSynchronizationRegistry for XA cases. Make defensive copies of char[] passwords. Do not try to register synchronization when the transaction is no longer active. Do not double returnObject back to the pool if there is a transaction context with a shared connection. Allow DBCP to work with old Java 6/JDBC drivers without throwing AbstractMethodError. Add some toString() methods for debugging (never printing passwords.) BasicManagedDataSource needs to pass the TSR with creating DataSourceXAConnectionFactory. Add getters to some classes. org.apache.commons.dbcp2.DriverManagerConnectionFactory should use a char[] instead of a String to store passwords. Update Apache Commons Pool from 2.6.0 to 2.6.1. Update Java requirement from version 7 to 8. Support JDBC 4.2. Support default schema in configuration. Examines 'SQLException's thrown by underlying connections or statements for fatal (disconnection) errors. Change default for fail-fast connections from false to true. Prepared statement keys should take a Connection's schema into account. Increase test coverage. Update Apache Commons Pool from 2.5.0 to 2.6.0. Avoid exceptions when closing a connection in mutli-threaded use case. Connection leak during XATransaction in high load. Drop Ant build. Ensure DBCP ConnectionListener can deal with transaction managers which invoke rollback in a separate thread. org.apache.commons.dbcp2.PStmtKey should make copies of given arrays in constructors. Remove duplicate code in org.apache.commons.dbcp2.cpdsadapter.PStmtKeyCPDS. Add support for pooling CallableStatements to the org.apache.commons.dbcp2.cpdsadapter package. Deprecate use of PStmtKeyCPDS in favor of PStmtKey. org.apache.commons.dbcp2.DataSourceConnectionFactory should use a char[] instead of a String to store passwords. org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory should use a char[] instead of a String to store passwords. org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS should use a char[] instead of a String to store passwords. org.apache.commons.dbcp2.datasources.CPDSConnectionFactory should use a char[] instead of a String to store passwords. org.apache.commons.dbcp2.datasources internals should use a char[] instead of a String to store passwords. org.apache.commons.dbcp2.datasources.InstanceKeyDataSourceFactory.closeAll() does not close all. AbandonedTrace.getTrace() contains race condition. Avoid javax.management.InstanceNotFoundException on shutdown when a bean is not registered. Closes #9. Make constant public: org.apache.commons.dbcp2.PoolingDriver.URL_PREFIX. DriverAdapterCPDS.setUser(), setPassword(), and getPooledConnection() with null arguments throw NullPointerExceptions when connection properties are set. Add API org.apache.commons.dbcp2.datasources.PerUserPoolDataSource.clear(). NPE for org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS.setConnectionProperties(null). The method org.apache.commons.dbcp2.PoolingDriver.getConnectionPool(String) does not tell you which pool name is not registered when it throws an exception. Update Apache Commons Pool from 2.4.2 to 2.5.0. OSGi declarations contain multiple import headers for javax.transaction. Wrong parameter name in site documentation for BasicDataSource Configuration Parameters. Add jmxName to properties set by BasicDataSourceFactory. This enables container-managed pools created from JNDI Resource definitions to enable JMX by supplying a valid root JMX name. NullPointerException thrown when calling ManagedConnection.isClosed(). InvalidateConnection can result in closed connection returned by getConnection. Complete the fix for DBCP-418, enabling PoolableConnection class to load in environments (such as GAE) where the JMX ManagementFactory is not available. Add constructor DriverManagerConnectionFactory(String). Ensure that the cacheState setting is used when statement pooling is disabled. Ensure that setSoftMinEvictableIdleTimeMillis is used when working with BasicDataSource. Correct the name of the configuration attribute softMinEvictableIdleTimeMillis. Avoid potential infinite loops when checking if an SQLException is fatal for a connection or not. Expand the fail-fast for fatal connection errors feature to include managed connections. Correct a typo in the method name PoolableConnectionFactory#setMaxOpenPreparedStatements. The old method remains but is deprecated so not to break clients currently using the incorrect name. Refactoring to prepare for a future patch to enable pooling of all prepared and callable statements in PoolingConnection. Ensure that a thread's interrupt status is visible to the caller if the thread is interrupted during a call to PoolingDataSource.getConnection(). Make it simpler to extend BasicDataSource to allow sub-classes to provide custom GenericObjectPool implementations. When using a BasicDataSource, pass changes related to the handling of abandoned connections to the underlying pool so that the pool configuration may be updated dynamically. Enable pooling of all prepared and callable statements inPoolingConnection. Updated pool version to 2.4.2. The fix for POOL-300 may cause DBCP users to see more reports of abandoned connections (if removal and logging are configured). Prior to the fix for POOL-300, the PrintWriter used to log abandoned connection stack traces was not being flushed on each log event. Added BasicDataSource abandonedUsageTracking property missing from BasicDataSourceFactory. SharedPoolDataSource getConnection fails when testOnBorrow is set with a null validation query. Nested connections in a transaction (local) throws null pointer. BasicDataSource does not set disconnectionSql properties on its PoolableConnectionFactory. InstanceKeyDataSource discards native SQLException when given password does not match password used to create the connection. Update Apache Commons Logging to 1.2 from 1.1.3. Correct some Javadoc references to Apache Commons Pool 2 classes that have changed names since Pool 1.x. Do not ignore the configured custom eviction policy when creating a BasicDataSource. Added invalidateConnection method to BasicDataSource. Unsuccessful Connection enlistment in XA Transaction ignored by TransactionContext. Made expired connection logging configurable in BasicDataSource. Setting logExpiredConnections to false suppresses expired connection log messages. Made Datasources implement AutoCloseable. Added fastFailValidation property to PoolableConnection, configurable in BasicDataSource. When set to true, connections that have previously thrown fatal disconnection errors will fail validation immediately (no driver calls). Changed BasicDataSource createDataSource method to ensure that initialization completes before clients get reference to newly created instances. Fixed connection leak when SQLException is thrown while enlisting an XA transaction. Setting jmxName to null should suppress JMX registration of connection and statement pools. Eliminated synchronization in BasicDataSource getNumActive, getNumIdle methods. Added property name verification to BasicDataSourceFactory. References including obsolete or unrecognized properties now generate log messages. Small performance improvements when returning connections to the pool. Fixed DelegatingStatement close to ensure closed statements do not retain references to pooled prepared statements. Due to finalization code added in 2.0, this was causing pooled prepared statements to be closed by GC while in use by clients. Added check in PoolingDataSource constructor to ensure that the connection factory and pool are properly linked. Fixed connection leak when managed connections are closed during transactions. Enable PoolableConnection class to load without JMX. BasicManagedDataSource - unregister from JMX on close(). Log validation failures of poolable connections. DelegatingStatement.close() fails with NPE if statement is null CPDSConnectionFactory.validateObject(Object) ignores Throwable. Provide a new option (cacheState) to cache current values of autoCommit and readOnly so database queries are not required for every call to the associated getters. This option is enabled by default. Removed unnecessary synchronisation in BasicDataSource#createDataSource. The Java package name has been changed from org.apache.commons.dbcp to org.apache.commons.dbcp2. Update to Commons Pool 2 (based on java.util.concurrent) to provide pooling functionality. Updated source code for Java 1.6 (added @Override & @Deprecated annotations). Removed JOCL support. Remove deprecated SQLNestedException. Fix threading issues with accessToUnderlyingConnectionAllowed attribute of PoolingDriver which is used to support unit testing. BasicDataSource instances are now exposed via JMX. All the configuration properties are available as is the connection pool and the statement pools (if statement pooling is enabled). Fix thread safety issues in the SharedPoolDataSource and the PerUserPoolDataSource. Allow accessToUnderlyingConnectionAllowed to be configured when configuration takes place via JNDI in a JavaEE container. Fix threading issue when using multiple instances of the SharedPoolDataSource concurrently. Ensure that the close state of a pooled connection and the underlying connection is consistent when the underlying connection is closed as a result of an error condition. Make all mutable fields private. Return BasicDataSource rather than DataSource from BasicDataSourceFactory so a cast is not required to use BasicDataSource specific methods. The equals() implementations of the DelegatingXxx classes are now symmetric. There are some important API changes underlying this fix. Firstly, two DelegatingXxx instances are no longer considered equal if they have the same innermost delegate. Secondly, a DelegatingXxx instance is not considered equal to its innermost delegate. The getInnermostDelegateInternal() method has been made public (but remains part of the internal API) to allow classes extending this implementation to access the innermost delegate when required. Expose the new Pool 2 property evictionPolicyClassName to enable more sophisticated eviction strategies to be used. Add support for pooling PreparedStatements that use auto-generated keys. Enable JDBC resources that are no longer referenced by client code to be eligible for garbage collection. Enable DBCP to work with a SecurityManager such that only DBCP needs to be granted the necessary permissions to communicate with the database. Correct path to Javadoc overview in build.xml. The default values for readOnly, autoCommit and transactionIsolation are now taken from the JDBC driver. No calls to setReadOnly(), setAutoCommit() or setTransactionIsolation() will be made for a newly borrowed connection unless a default is explicitly configured and the connection is currently using a different setting. Register pooled connections with JMX so that they may be forcibly closed via JMX if required. Modify SharedPoolDataSource and PerUserPoolDataSource to expose all of the configuration properties of the underlying connection pool(s). This represents a significant refactoring of these classes and a number of property names have changed as a result. Provide an option to control if autoCommit is always set to true when a connection is returned to the connection pool. Provide an option to control if rollback is called when a connection is returned to the poll with autoCommit disabled. Provide an option to set the default query timeout. Connection.isValid() should not throw an SQLException if the connection is closed. Use Connection.isValid() to validate connections unless a validation query is explicitly configured. Note that this means it is no longer necessary for a validation query to be specified in order for validation to take place. When testing with Oracle, this resulted in database validation being approximately 7 times faster. Add support for validation testing database connections on creation. Correct the documentation for the maxOpenPreparedStatements parameter and review the use of the phrase non-positive throughout the documentation and javadoc, replacing it with negative where that is the correct definition to use. Avoid multiple calls to Connection.getAutoCommit() in PoolableConnectionFactory.passivateObject() as it could be an expensive call. Use one line per statement for methods with multiple statements rather than using a single line. Expose all of the AbandonedConfig properties through a BasicDataSource. Correct implementation of DelegatingConnection.isWrapperFor() so it works correctly with older JDBC drivers. Correct implementation of DelegatingStatement.isWrapperFor(). Also fix DelegatingDatabaseMetaData.isWrapperFor() and DelegatingResultSet.isWrapperFor() that had the same problem. LocalXAConnectionFactory does not properly check if Xid is equal to currentXid when resuming which may result in an XAException. Ensure that the XAConnection is closed when the associated Connection is closed. Clarify Jaavdoc for isClosed() method of PoolableConnection. Avoid NullPointerException and throw an XAException if an attempt is made to commit the current transaction for a connection when no transaction has been started. Using batchUpdate() should not invalidate the PreparedStatement when it is returned to the pool. Improve documentation for JNDI example using BasicDataSource. Exposed GenericObjectPool's softMinEvictableIdleTimeMillis property for configuration and use by BasicDataSource. Made equals reflexive in DelegatingStatement (and subclasses), DelegatingMetaData, DelegatingResultSet and PoolingDriver#PoolGuardConnectionWrapper. Modified createDataSource method in BasicDataSource to ensure that GenericObjectPool Evictor tasks are not started and orphaned when BasicDataSource encounters errors on initialization. Prior to this fix, when minIdle and timeBetweenEvictionRunsMillis are both positive, Evictors orphaned by failed initialization can continue to generate database connection requests. This issue is duplicated by DBCP-339 and DBCP-93. Changed DelegatingDatabaseMetaData to no longer add itself to the AbandonedTrace of its parent connection. This was causing excessive memory consumption and was not necessary, as resultsets created by DelegatingDatabaseMetaData instances are attached to the parent connection's trace on creation. Also fixes DBCP-352. Modified execute methods of Statement objects to ensure that whenever a statement is used, the lastUsed property of its parent connection is updated. Correctly implemented the option to configure the class loader used to load the JDBC driver. LIFO configuration option has been added to BasicDataSource. When set to true (the default), the pool acts as a LIFO queue; setting to false causes connections to enter and exit to pool in FIFO order. Test transitive dependencies brought in by geronimo-transaction created version conflicts (commons logging and junit). These have been explicitly excluded in the POM. BasicDataSourceFactory incorrectly used "initConnectSqls" in versions 1.3 and 1.4 of DBCP as the property name for connectionInitSqls. Online docs for 1.3/1/4 have been updated to reflect this inconsistency. The BasicDataSourceFactory property name has been changed to "connectInitSqls" to match the online docs and the BasicDataSource property name. Eliminated poolKeys cache from PerUserPoolDataSource. Eliminated userKeys LRUMap cache from SharedPoolDataSource. Made private fields final where possible. PerUserPoolDataSource.getPooledConnectionAndInfo multi-threading bug. Remove throws clause from method that does not throw an exception. Remove code that catches and ignores Exceptions when calling PooledConnection.removeConnectionEventListener(ConnectionEventListener) as the method does not throw any Exceptions. Remove impossible null check. Renamed variables with duplicate names in different scopes. Clarified javadoc for BasicDataSource close() method. Made PoolingConnection pool CallableStatements. When BasicDataSource's poolPreparedStatements property is true, CallableStatements are now pooled along with PreparedStatements. The maxOpenPreparedStatements property limits the combined number of Callable and Prepared statements that can be in use at a given time. Use an API specific exception for logging abandoned objects to make scanning the logs for these exceptions simpler and to provide a better message that includes the creation time of the abandoned object. Ensure Statement.getGeneratedKeys() works correctly with the CPDS adapter. Removed incorrectly advertised ClassNotFoundException from JOCLContentHandler.ConstructorDetails.createObject(). Make the class loader used to load the JDBC driver configurable for the BasicDatasource. Handle user password changes for InstanceKeyDataSources. Made XADataSource configurable in BasicManagedDataSource. Added PoolableManagedConnection and PoolableManagedConnectionFactory so that pooled managed connections can unregister themselves from transaction registries, avoiding resource leaks. Added connectionProperties property to DriverAdapterCPDS. Added a validationQueryTimeout configuration parameter to BasicDataSource allowing the user to specify a timeout value (in seconds) for connection validation queries. Added a connectionInitSqls configuration parameter to BasicDataSource allowing the user to specify a collection of SQL statements to execute one time when a physical database connection is first opened. PoolableConnectionFactory.makeObject() is no longer synchronized. This provides improved response times when load spikes at the cost of a faster rise in database server load. This change was made as a partial fix for DBCP-212. The synchronization changes in Commons Pool 1.5 complete the fix for this issue. Reverted DelegatingConnection close to 1.2.2 version to ensure open statements are closed before the underlying connection is closed. Refactor DelegatingConnection and ManagedConnection enable overridden equals() and hashcode() to work correctly. Add a DelegatingDatabaseMetaData to track ResultSets returned from DatabaseMetaData objects. Modified BasicDataSourceFactory to complete initialization of the pool by creating initialSize connections rather than leaving this to lazy initialization when the pool is used. Eliminated masked _stmt field in descendents of DelegatingStatement. Modified DBCP sources to support compilation under JDK 1.4-1.6 using Ant flags to do conditional compilation. Added a static initializer to BasicDatasource that calls DriverManager.getDrivers() to force initialization before we ever do anything that might use Class.forName() to load (and register) a JDBC driver. Eliminated direct System.out calls in AbandonedTrace. Modified DelegatingStatement close to clear open batches. Eliminated unused private "parent" field in AbandonedTrace. Fixed errors handling boolean-valued Reference properties in InstanceKeyObjectFactory, DriverAdapterCPDS that were causing testOnBorrow and poolPreparedStatements properties to be incorrectly set when creating objects from javax.naming.Reference instances. Made private instance fields of AbandonedTrace volatile (parent, createdBy, lastUsed, createdTime) or final (trace). Narrowed synchronization in AbandonedTrace to resolve an Evictor deadlock. Corrected Javadoc to state that getLoginTimeout and setLoginTimeout are NOT supported by BasicDataSource. Added Maven 2 pom.xml. Removed a block of code from TestJOCLed that set the Xerces parser manually. This was to support early JDKs. The 1.3 version of DBCP requires JDK 1.4+. Added support for pooling managed connections. Added BasicManagedDataSource, extending BasicDataSource. Also improved extensibility of BasicDataSource by encapsulating methods to create object pool, connection factory and datasource instance previously embedded in createDataSource. Changed behavior to allow Connection, Statement, PreparedStatement, CallableStatement and ResultSet to be closed multiple times. The first time close is called the resource is closed and any subsequent calls have no effect. This behavior is required as per the Javadocs for these classes. Also added tests for closing all types multiple times and updated any tests that incorrectly assert that a resource can not be closed more then once. Fixes DBCP-3, DBCP-5, DBCP-23 and DBCP-134. Modified PoolingDataSource, PoolingDriver and DelegatingStatement to assure that all returned Statements, PreparedStatements, CallableStatements and ResultSets are wrapped with a delegating object, which already properly handle the back pointers for Connection and Statement. Also added tests to assure that the *same* object used to create the statement or result set is returned from either getConnection() or getStatement(). SQLNestedException has been deprecated and will be replaced in DBCP 2.0 with SQLException and standard Java exception chaining. BasicDataSource.close() now permanently marks the data source as closed, and no new connections can be obtained from the data source. At close all idle connections are destroyed and the method returns. As the remaining active connections are closed, they are destroyed. Eliminated potential sources of NullPointerExceptions in PoolingConnection. Improved error recovery and listener cleanup in KeyedCPDSConnectionFactory. Substituted calls to destroyObject with _pool.invalidateObject on error to ensure pool active count is decremented on error events. Ensured that events from closed or invalid connections are ignored and listeners are cleaned up. Fixed error in SharedPoolDataSource causing incorrect passwords to be stored under certain conditions. Added exception handler to ensure that PooledConnections are not orphaned when an exception occurs in setUpDefaults or clearWarnings in InstanceKeyDataSource.getConnection. Made getPool synchronized in PoolableConnectionFactory. Fixes inconsistent synchronization accessing _pool. Fixed inconsistent synchronization on _rollbackAfterValidation, _validationQuery and _pool in CPDSConnectionFactory and KeyedCPDSConnectionFactory by making the first two volatile and making both getter and setter for _pool synchronized. See <a href="changes-report.html#a1.4">DBCP 1.4 Changes </a> for details. Version 1.3 is identical to 1.4, other than JDBC 4 methods being filtered out of the DBCP 1.3 sources. Changes Since 1.2.2 are the same for 1.3 and 1.4. Add a <i>JNDI How To</i> to the User Guide. DriverManagerConnectionFactory: blank user name and password handling. Broken behaviour for BasicDataSource.setMaxActive(0). BasicDataSource does not work with getConnection(String, String). Enhancements to prepared statement in DriverAdapterCPDS. Better messages and docs for LoginTimeout UnsupportedOperationException. Error in JOCL snippet in org.apache.commons.dbcp package javadoc. Added toString() methods to DelegatingPreparedStatement and DelegatingStatement Changes to make DBCP compile on JDK 1.5 by adding source="1.4" to compiler arguments (there are compiler errors in JDK 5.0 without this source switch that cannot be fixed without JDK 5.0-specific syntax). Per-user pooling with Oracle driver and default isolation settings. Error in JOCL document in javadoc. Added toString() method to DelegatingConnection. Add DriverManager.invalidateConnection(). Improved Exception nesting in ConnectionPool. Fix broken website links for examples. Modified PoolableConnection close method to invalidate instance when invoked on an already closed connection. Inserted null checks to avoid NPE in close operations. Changed getReference method in InstanceKeyDataSource to return a concrete factory and added implementations of getReference in concrete subclasses. Inserted null check in close method of SharedPoolDataSource to avoid NPE when invoked on non-initialized pool. Document fact that true values for testOnBorrow, testOnReturn, testWhileIdle only have effect when validationQuery is set to a non-null string. Modified activateObject in PoolableConnection to test connection properties before resetting to defaults. Corrected maxActive documentation in configuration.html. Upgraded dependency to Pool 1.3. Added connection info to SQLException messages when closed connections (resp stmts) are accessed in DelegatingConnection, DelegatingStatement. Fixed errors in pool parameter documentation and made 0 value for _maxPreparedStatements in DriverAdapterCPDS behave like a negative value, to be consistent with documentation and pool behavior. Made userKeys an instance variable (i.e., not static) in SharedPoolDataSource. Changed implementation of equals in PoolingDataSource.PoolGuardConnectionWrapper to ensure it is reflexive, even when wrapped connections are not DelegatingConnections. Added rollbackAfterValidation property and code to issue a rollback on a connection after validation when this property is set to true to eliminate Oracle driver exceptions. Default property value is false. Removed dependency on Commons Collections by adding collections 2.1 sources for LRUMap and SequencedHashMap with package scope to datasources package. Removed synchronization from prepareStatement methods in PoolingConnection. Synchronization in these methods was causing deadlocks. No resources other than the prepared statement pool are accessed by these methods, and the pool methods are synchronized. Also fixes DBCP-202. See <a href="release-notes-1.2.1.html">DBCP 1.2.1 Release Notes</a> for details. See <a href="release-notes-1.2.html">DBCP 1.2 Release Notes</a> for details. See <a href="release-notes-1.1.html">DBCP 1.1 Release Notes</a> for details. Initial Release commons-dbcp-rel-commons-dbcp-2.10.0/src/changes/release-notes.vm000066400000000000000000000067301447311732500246400ustar00rootroot00000000000000## Licensed to the Apache Software Foundation (ASF) under one ## or more contributor license agreements. See the NOTICE file ## distributed with this work for additional information ## regarding copyright ownership. The ASF licenses this file ## to you under the Apache License, Version 2.0 (the ## "License"); you may not use this file except in compliance ## with the License. You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, ## software distributed under the License is distributed on an ## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ## KIND, either express or implied. See the License for the ## specific language governing permissions and limitations ## under the License. ${project.name} Version ${version} RELEASE NOTES The ${developmentTeam} is pleased to announce the release of ${project.name} ${version}. $introduction.replaceAll("(? commons-dbcp-rel-commons-dbcp-2.10.0/src/conf/eclipse/000077500000000000000000000000001447311732500224615ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/conf/eclipse/formatter.xml000066400000000000000000001123441447311732500252130ustar00rootroot00000000000000 commons-dbcp-rel-commons-dbcp-2.10.0/src/conf/findbugs-exclude-filter.xml000066400000000000000000000065521447311732500263020ustar00rootroot00000000000000 commons-dbcp-rel-commons-dbcp-2.10.0/src/main/000077500000000000000000000000001447311732500210345ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/assembly/000077500000000000000000000000001447311732500226535ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/assembly/bin.xml000066400000000000000000000031371447311732500241510ustar00rootroot00000000000000 bin tar.gz zip false LICENSE.txt NOTICE.txt README.txt RELEASE-NOTES.txt target *.jar target/site/apidocs apidocs commons-dbcp-rel-commons-dbcp-2.10.0/src/main/assembly/src-tar-gz.xml000066400000000000000000000053411447311732500253710ustar00rootroot00000000000000 src tar.gz ${project.artifactId}-${project.version}-src build.properties.sample build.xml checkstyle.xml findbugs-exclude-filter.xml LICENSE.txt NOTICE.txt pom.xml README.txt RELEASE-NOTES.txt test-jar.xml lf doc static_structure_dia.gif lf src/site/resources src/site/xdoc lf src/site site.xml lf src/media src/changes lf src/main lf src/test lf commons-dbcp-rel-commons-dbcp-2.10.0/src/main/assembly/src-zip.xml000066400000000000000000000053531447311732500247720ustar00rootroot00000000000000 src zip ${project.artifactId}-${project.version}-src build.properties.sample build.xml checkstyle.xml findbugs-exclude-filter.xml LICENSE.txt NOTICE.txt pom.xml README.txt RELEASE-NOTES.txt test-jar.xml crlf doc static_structure_dia.gif crlf src/site/resources src/site/xdoc crlf src/site site.xml crlf src/media src/changes crlf src/main crlf src/test crlf commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/000077500000000000000000000000001447311732500217555ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/000077500000000000000000000000001447311732500225445ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/000077500000000000000000000000001447311732500237655ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/000077500000000000000000000000001447311732500254405ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/000077500000000000000000000000001447311732500264325ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/AbandonedTrace.java000066400000000000000000000153711447311732500321360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.lang.ref.WeakReference; import java.sql.SQLException; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.function.Consumer; import org.apache.commons.pool2.TrackedUse; /** * Tracks connection usage for recovering and reporting abandoned connections. *

* The JDBC Connection, Statement, and ResultSet classes extend this class. *

* * @since 2.0 */ public class AbandonedTrace implements TrackedUse, AutoCloseable { static void add(AbandonedTrace receiver, AbandonedTrace trace) { if (receiver != null) { receiver.addTrace(trace); } } /** A list of objects created by children of this object. */ private final List> traceList = new ArrayList<>(); /** Last time this connection was used. */ private volatile Instant lastUsedInstant = Instant.EPOCH; /** * Creates a new AbandonedTrace without config and without doing abandoned tracing. */ public AbandonedTrace() { init(null); } /** * Constructs a new AbandonedTrace with a parent object. * * @param parent * AbandonedTrace parent object. */ public AbandonedTrace(final AbandonedTrace parent) { init(parent); } /** * Adds an object to the list of objects being traced. * * @param trace * AbandonedTrace object to add. */ protected void addTrace(final AbandonedTrace trace) { synchronized (this.traceList) { this.traceList.add(new WeakReference<>(trace)); } setLastUsed(); } /** * Clears the list of objects being traced by this object. */ protected void clearTrace() { synchronized (this.traceList) { this.traceList.clear(); } } /** * Subclasses can implement this nop. * * @throws SQLException Ignored here, for subclasses. * @since 2.10.0 */ @Override public void close() throws SQLException { // nop } /** * Closes this resource and if an exception is caught, then calls {@code exceptionHandler}. * * @param exceptionHandler Consumes exception thrown closing this resource. * @since 2.10.0 */ protected void close(final Consumer exceptionHandler) { Utils.close(this, exceptionHandler); } /** * Gets the last time this object was used in milliseconds. * * @return long time in milliseconds. */ @Override @Deprecated public long getLastUsed() { return lastUsedInstant.toEpochMilli(); } @Override public Instant getLastUsedInstant() { return lastUsedInstant; } /** * Gets a list of objects being traced by this object. * * @return List of objects. */ protected List getTrace() { final int size = traceList.size(); if (size == 0) { return Collections.emptyList(); } final ArrayList result = new ArrayList<>(size); synchronized (this.traceList) { final Iterator> iter = traceList.iterator(); while (iter.hasNext()) { final AbandonedTrace trace = iter.next().get(); if (trace == null) { // Clean-up since we are here anyway iter.remove(); } else { result.add(trace); } } } return result; } /** * Initializes abandoned tracing for this object. * * @param parent * AbandonedTrace parent object. */ private void init(final AbandonedTrace parent) { AbandonedTrace.add(parent, this); } /** * Removes this object the source object is tracing. * * @param source The object tracing * @since 2.7.0 */ protected void removeThisTrace(final Object source) { if (source instanceof AbandonedTrace) { AbandonedTrace.class.cast(source).removeTrace(this); } } /** * Removes a child object this object is tracing. * * @param trace * AbandonedTrace object to remove. */ protected void removeTrace(final AbandonedTrace trace) { synchronized (this.traceList) { final Iterator> iter = traceList.iterator(); while (iter.hasNext()) { final AbandonedTrace traceInList = iter.next().get(); if (trace != null && trace.equals(traceInList)) { iter.remove(); break; } if (traceInList == null) { // Clean-up since we are here anyway iter.remove(); } } } } /** * Sets the time this object was last used to the current time in milliseconds. */ protected void setLastUsed() { lastUsedInstant = Instant.now(); } /** * Sets the instant this object was last used. * * @param lastUsedInstant * instant. * @since 2.10.0 */ protected void setLastUsed(final Instant lastUsedInstant) { this.lastUsedInstant = lastUsedInstant; } /** * Sets the time in milliseconds this object was last used. * * @param lastUsedMillis * time in milliseconds. * @deprecated Use {@link #setLastUsed(Instant)} */ @Deprecated protected void setLastUsed(final long lastUsedMillis) { this.lastUsedInstant = Instant.ofEpochMilli(lastUsedMillis); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java000066400000000000000000003202141447311732500322730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.time.Duration; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.function.BiConsumer; import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.StandardMBean; import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.AbandonedConfig; import org.apache.commons.pool2.impl.BaseObjectPoolConfig; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; /** * Basic implementation of {@code javax.sql.DataSource} that is configured via JavaBeans properties. * *

* This is not the only way to combine the commons-dbcp2 and commons-pool2 packages, but provides a * one-stop solution for basic requirements. *

* * @since 2.0 */ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration, AutoCloseable { private static final Log log = LogFactory.getLog(BasicDataSource.class); static { // Attempt to prevent deadlocks - see DBCP - 272 DriverManager.getDrivers(); try { // Load classes now to prevent AccessControlExceptions later // A number of classes are loaded when getConnection() is called // but the following classes are not loaded and therefore require // explicit loading. if (Utils.isSecurityEnabled()) { final ClassLoader loader = BasicDataSource.class.getClassLoader(); final String dbcpPackageName = BasicDataSource.class.getPackage().getName(); loader.loadClass(dbcpPackageName + ".DelegatingCallableStatement"); loader.loadClass(dbcpPackageName + ".DelegatingDatabaseMetaData"); loader.loadClass(dbcpPackageName + ".DelegatingPreparedStatement"); loader.loadClass(dbcpPackageName + ".DelegatingResultSet"); loader.loadClass(dbcpPackageName + ".PoolableCallableStatement"); loader.loadClass(dbcpPackageName + ".PoolablePreparedStatement"); loader.loadClass(dbcpPackageName + ".PoolingConnection$StatementType"); loader.loadClass(dbcpPackageName + ".PStmtKey"); final String poolPackageName = PooledObject.class.getPackage().getName(); loader.loadClass(poolPackageName + ".impl.LinkedBlockingDeque$Node"); loader.loadClass(poolPackageName + ".impl.GenericKeyedObjectPool$ObjectDeque"); } } catch (final ClassNotFoundException cnfe) { throw new IllegalStateException("Unable to pre-load classes", cnfe); } } /** * Validates the given factory. * * @param connectionFactory the factory * @throws SQLException Thrown by one of the factory methods while managing a temporary pooled object. */ @SuppressWarnings("resource") protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory) throws SQLException { PoolableConnection conn = null; PooledObject p = null; try { p = connectionFactory.makeObject(); conn = p.getObject(); connectionFactory.activateObject(p); connectionFactory.validateConnection(conn); connectionFactory.passivateObject(p); } finally { if (p != null) { connectionFactory.destroyObject(p); } } } /** * The default auto-commit state of connections created by this pool. */ private volatile Boolean defaultAutoCommit; /** * The default read-only state of connections created by this pool. */ private transient Boolean defaultReadOnly; /** * The default TransactionIsolation state of connections created by this pool. */ private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION; private Duration defaultQueryTimeoutDuration; /** * The default "catalog" of connections created by this pool. */ private volatile String defaultCatalog; /** * The default "schema" of connections created by this pool. */ private volatile String defaultSchema; /** * The property that controls if the pooled connections cache some state rather than query the database for current * state to improve performance. */ private boolean cacheState = true; /** * The instance of the JDBC Driver to use. */ private Driver driver; /** * The fully qualified Java class name of the JDBC driver to be used. */ private String driverClassName; /** * The class loader instance to use to load the JDBC driver. If not specified, {@link Class#forName(String)} is used * to load the JDBC driver. If specified, {@link Class#forName(String, boolean, ClassLoader)} is used. */ private ClassLoader driverClassLoader; /** * True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle * connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle * instance pool in the order that they are returned to the pool. */ private boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO; /** * The maximum number of active connections that can be allocated from this pool at the same time, or negative for * no limit. */ private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL; /** * The maximum number of connections that can remain idle in the pool, without extra ones being destroyed, or * negative for no limit. If maxIdle is set too low on heavily loaded systems it is possible you will see * connections being closed and almost immediately new connections being opened. This is a result of the active * threads momentarily closing connections faster than they are opening them, causing the number of idle connections * to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good * starting point. */ private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; /** * The minimum number of active connections that can remain idle in the pool, without extra ones being created when * the evictor runs, or 0 to create none. The pool attempts to ensure that minIdle connections are available when * the idle object evictor runs. The value of this property has no effect unless * {@link #durationBetweenEvictionRuns} has a positive value. */ private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; /** * The initial number of connections that are created when the pool is started. */ private int initialSize; /** * The maximum Duration that the pool will wait (when there are no available connections) for a * connection to be returned before throwing an exception, or <= 0 to wait indefinitely. */ private Duration maxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT; /** * Prepared statement pooling for this pool. When this property is set to {@code true} both PreparedStatements * and CallableStatements are pooled. */ private boolean poolPreparedStatements; private boolean clearStatementPoolOnReturn; /** *

* The maximum number of open statements that can be allocated from the statement pool at the same time, or negative * for no limit. Since a connection usually only uses one or two statements at a time, this is mostly used to help * detect resource leaks. *

*

* Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall}) are pooled along * with PreparedStatements (produced by {@link Connection#prepareStatement}) and * {@code maxOpenPreparedStatements} limits the total number of prepared or callable statements that may be in * use at a given time. *

*/ private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; /** * The indication of whether objects will be validated as soon as they have been created by the pool. If the object * fails to validate, the borrow operation that triggered the creation will fail. */ private boolean testOnCreate; /** * The indication of whether objects will be validated before being borrowed from the pool. If the object fails to * validate, it will be dropped from the pool, and we will attempt to borrow another. */ private boolean testOnBorrow = true; /** * The indication of whether objects will be validated before being returned to the pool. */ private boolean testOnReturn; /** * The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle * object evictor thread will be run. */ private Duration durationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS; /** * The number of objects to examine during each run of the idle object evictor thread (if any). */ private int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; /** * The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle * object evictor (if any). */ private Duration minEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION; /** * The minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the idle * object evictor, with the extra condition that at least "minIdle" connections remain in the pool. Note that * {@code minEvictableIdleTimeMillis} takes precedence over this parameter. See * {@link #getSoftMinEvictableIdleDuration()}. */ private Duration softMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION; private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME; /** * The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to * validate, it will be dropped from the pool. */ private boolean testWhileIdle; /** * The connection password to be passed to our JDBC driver to establish a connection. */ private volatile String password; /** * The connection string to be passed to our JDBC driver to establish a connection. */ private String connectionString; /** * The connection user name to be passed to our JDBC driver to establish a connection. */ private String userName; /** * The SQL query that will be used to validate connections from this pool before returning them to the caller. If * specified, this query MUST be an SQL SELECT statement that returns at least one row. If not * specified, {@link Connection#isValid(int)} will be used to validate connections. */ private volatile String validationQuery; /** * Timeout in seconds before connection validation queries fail. */ private volatile Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1); /** * The fully qualified Java class name of a {@link ConnectionFactory} implementation. */ private String connectionFactoryClassName; /** * These SQL statements run once after a Connection is created. *

* This property can be used for example to run ALTER SESSION SET NLS_SORT=XCYECH in an Oracle Database only once * after connection creation. *

*/ private volatile List connectionInitSqls; /** * Controls access to the underlying connection. */ private boolean accessToUnderlyingConnectionAllowed; private Duration maxConnDuration = Duration.ofMillis(-1); private boolean logExpiredConnections = true; private String jmxName; private boolean registerConnectionMBean = true; private boolean autoCommitOnReturn = true; private boolean rollbackOnReturn = true; private volatile Set disconnectionSqlCodes; private boolean fastFailValidation; /** * The object pool that internally manages our connections. */ private volatile GenericObjectPool connectionPool; /** * The connection properties that will be sent to our JDBC driver when establishing new connections. * NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be * included here. */ private Properties connectionProperties = new Properties(); /** * The data source we will use to manage connections. This object should be acquired ONLY by calls * to the {@code createDataSource()} method. */ private volatile DataSource dataSource; /** * The PrintWriter to which log messages should be directed. */ private volatile PrintWriter logWriter = new PrintWriter( new OutputStreamWriter(System.out, StandardCharsets.UTF_8)); private AbandonedConfig abandonedConfig; private boolean closed; /** * Actual name under which this component has been registered. */ private ObjectNameWrapper registeredJmxObjectName; /** * Adds a custom connection property to the set that will be passed to our JDBC driver. This MUST * be called before the first connection is retrieved (along with all the other configuration property setters). * Calls to this method after the connection pool has been initialized have no effect. * * @param name Name of the custom connection property * @param value Value of the custom connection property */ public void addConnectionProperty(final String name, final String value) { connectionProperties.put(name, value); } /** * Closes and releases all idle connections that are currently stored in the connection pool associated with this * data source. *

* Connections that are checked out to clients when this method is invoked are not affected. When client * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the * underlying JDBC connections are closed. *

*

* Attempts to acquire connections using {@link #getConnection()} after this method has been invoked result in * SQLExceptions. To reopen a datasource that has been closed using this method, use {@link #start()}. *

*

* This method is idempotent - i.e., closing an already closed BasicDataSource has no effect and does not generate * exceptions. *

* * @throws SQLException if an error occurs closing idle connections */ @Override public synchronized void close() throws SQLException { if (registeredJmxObjectName != null) { registeredJmxObjectName.unregisterMBean(); registeredJmxObjectName = null; } closed = true; final GenericObjectPool oldPool = connectionPool; connectionPool = null; dataSource = null; try { if (oldPool != null) { oldPool.close(); } } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException(Utils.getMessage("pool.close.fail"), e); } } /** * Closes the connection pool, silently swallowing any exception that occurs. */ private void closeConnectionPool() { final GenericObjectPool oldPool = connectionPool; connectionPool = null; Utils.closeQuietly(oldPool); } /** * Creates a JDBC connection factory for this data source. The JDBC driver is loaded using the following algorithm: *
    *
  1. If a Driver instance has been specified via {@link #setDriver(Driver)} use it
  2. *
  3. If no Driver instance was specified and {code driverClassName} is specified that class is loaded using the * {@link ClassLoader} of this class or, if {code driverClassLoader} is set, {code driverClassName} is loaded * with the specified {@link ClassLoader}.
  4. *
  5. If {code driverClassName} is specified and the previous attempt fails, the class is loaded using the * context class loader of the current thread.
  6. *
  7. If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {code connectionString}. *
*

* This method exists so subclasses can replace the implementation class. *

* * @return A new connection factory. * * @throws SQLException If the connection factory cannot be created */ protected ConnectionFactory createConnectionFactory() throws SQLException { // Load the JDBC driver class return ConnectionFactoryFactory.createConnectionFactory(this, DriverFactory.createDriver(this)); } /** * Creates a connection pool for this datasource. This method only exists so subclasses can replace the * implementation class. *

* This implementation configures all pool properties other than timeBetweenEvictionRunsMillis. Setting that * property is deferred to {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis to a * positive value causes {@link GenericObjectPool}'s eviction timer to be started. *

* * @param factory The factory to use to create new connections for this pool. */ protected void createConnectionPool(final PoolableConnectionFactory factory) { // Create an object pool to contain our active connections final GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); updateJmxName(config); // Disable JMX on the underlying pool if the DS is not registered: config.setJmxEnabled(registeredJmxObjectName != null); final GenericObjectPool gop = createObjectPool(factory, config, abandonedConfig); gop.setMaxTotal(maxTotal); gop.setMaxIdle(maxIdle); gop.setMinIdle(minIdle); gop.setMaxWait(maxWaitDuration); gop.setTestOnCreate(testOnCreate); gop.setTestOnBorrow(testOnBorrow); gop.setTestOnReturn(testOnReturn); gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun); gop.setMinEvictableIdle(minEvictableIdleDuration); gop.setSoftMinEvictableIdle(softMinEvictableIdleDuration); gop.setTestWhileIdle(testWhileIdle); gop.setLifo(lifo); gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections)); gop.setEvictionPolicyClassName(evictionPolicyClassName); factory.setPool(gop); connectionPool = gop; } /** * Creates (if necessary) and return the internal data source we are using to manage our connections. * * @return The current internal DataSource or a newly created instance if it has not yet been created. * @throws SQLException if the object pool cannot be created. */ protected synchronized DataSource createDataSource() throws SQLException { if (closed) { throw new SQLException("Data source is closed"); } // Return the pool if we have already created it // This is double-checked locking. This is safe since dataSource is // volatile and the code is targeted at Java 5 onwards. if (dataSource != null) { return dataSource; } synchronized (this) { if (dataSource != null) { return dataSource; } jmxRegister(); // create factory which returns raw physical connections final ConnectionFactory driverConnectionFactory = createConnectionFactory(); // Set up the poolable connection factory final PoolableConnectionFactory poolableConnectionFactory; try { poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory); poolableConnectionFactory.setPoolStatements(poolPreparedStatements); poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements); // create a pool for our connections createConnectionPool(poolableConnectionFactory); final DataSource newDataSource = createDataSourceInstance(); newDataSource.setLogWriter(logWriter); connectionPool.addObjects(initialSize); // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor // task startPoolMaintenance(); dataSource = newDataSource; } catch (final SQLException | RuntimeException se) { closeConnectionPool(); throw se; } catch (final Exception ex) { closeConnectionPool(); throw new SQLException("Error creating connection factory", ex); } return dataSource; } } /** * Creates the actual data source instance. This method only exists so that subclasses can replace the * implementation class. * * @throws SQLException if unable to create a datasource instance * * @return A new DataSource instance */ protected DataSource createDataSourceInstance() throws SQLException { final PoolingDataSource pds = new PoolingDataSource<>(connectionPool); pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); return pds; } /** * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}. * * @param factory the object factory * @param poolConfig the object pool configuration * @param abandonedConfig the abandoned objects configuration * @return a non-null instance */ protected GenericObjectPool createObjectPool(final PoolableConnectionFactory factory, final GenericObjectPoolConfig poolConfig, final AbandonedConfig abandonedConfig) { final GenericObjectPool gop; if (abandonedConfig != null && (abandonedConfig.getRemoveAbandonedOnBorrow() || abandonedConfig.getRemoveAbandonedOnMaintenance())) { gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig); } else { gop = new GenericObjectPool<>(factory, poolConfig); } return gop; } /** * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists so * subclasses can replace the default implementation. * * @param driverConnectionFactory JDBC connection factory * @throws SQLException if an error occurs creating the PoolableConnectionFactory * * @return A new PoolableConnectionFactory configured with the current configuration of this BasicDataSource */ protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory) throws SQLException { PoolableConnectionFactory connectionFactory = null; try { if (registerConnectionMBean) { connectionFactory = new PoolableConnectionFactory(driverConnectionFactory, ObjectNameWrapper.unwrap(registeredJmxObjectName)); } else { connectionFactory = new PoolableConnectionFactory(driverConnectionFactory, null); } connectionFactory.setValidationQuery(validationQuery); connectionFactory.setValidationQueryTimeout(validationQueryTimeoutDuration); connectionFactory.setConnectionInitSql(connectionInitSqls); connectionFactory.setDefaultReadOnly(defaultReadOnly); connectionFactory.setDefaultAutoCommit(defaultAutoCommit); connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation); connectionFactory.setDefaultCatalog(defaultCatalog); connectionFactory.setDefaultSchema(defaultSchema); connectionFactory.setCacheState(cacheState); connectionFactory.setPoolStatements(poolPreparedStatements); connectionFactory.setClearStatementPoolOnReturn(clearStatementPoolOnReturn); connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements); connectionFactory.setMaxConn(maxConnDuration); connectionFactory.setRollbackOnReturn(getRollbackOnReturn()); connectionFactory.setAutoCommitOnReturn(getAutoCommitOnReturn()); connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeoutDuration()); connectionFactory.setFastFailValidation(fastFailValidation); connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes); validateConnectionFactory(connectionFactory); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e); } return connectionFactory; } /** * Manually evicts idle connections * * @throws Exception when there is a problem evicting idle objects. */ public void evict() throws Exception { if (connectionPool != null) { connectionPool.evict(); } } /** * Gets the print writer used by this configuration to log information on abandoned objects. * * @return The print writer used by this configuration to log information on abandoned objects. */ public PrintWriter getAbandonedLogWriter() { return abandonedConfig == null ? null : abandonedConfig.getLogWriter(); } /** * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, should the * connection pool record a stack trace every time a method is called on a pooled connection and retain the most * recent stack trace to aid debugging of abandoned connections? * * @return {@code true} if usage tracking is enabled */ @Override public boolean getAbandonedUsageTracking() { return abandonedConfig != null && abandonedConfig.getUseUsageTracking(); } /** * Gets the value of the flag that controls whether or not connections being returned to the pool will be checked * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit * setting is {@code false} when the connection is returned. It is {@code true} by default. * * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit. */ public boolean getAutoCommitOnReturn() { return autoCommitOnReturn; } /** * Gets the state caching flag. * * @return the state caching flag */ @Override public boolean getCacheState() { return cacheState; } /** * Creates (if necessary) and return a connection to the database. * * @throws SQLException if a database access error occurs * @return a database connection */ @Override public Connection getConnection() throws SQLException { if (Utils.isSecurityEnabled()) { final PrivilegedExceptionAction action = () -> createDataSource().getConnection(); try { return AccessController.doPrivileged(action); } catch (final PrivilegedActionException e) { final Throwable cause = e.getCause(); if (cause instanceof SQLException) { throw (SQLException) cause; } throw new SQLException(e); } } return createDataSource().getConnection(); } /** * BasicDataSource does NOT support this method. * * @param user Database user on whose behalf the Connection is being made * @param pass The database user's password * * @throws UnsupportedOperationException always thrown. * @throws SQLException if a database access error occurs * @return nothing - always throws UnsupportedOperationException */ @Override public Connection getConnection(final String user, final String pass) throws SQLException { // This method isn't supported by the PoolingDataSource returned by the // createDataSource throw new UnsupportedOperationException("Not supported by BasicDataSource"); } /** * Gets the ConnectionFactoryClassName that has been configured for use by this pool. *

* Note: This getter only returns the last value set by a call to {@link #setConnectionFactoryClassName(String)}. *

* * @return the ConnectionFactoryClassName that has been configured for use by this pool. * @since 2.7.0 */ public String getConnectionFactoryClassName() { return this.connectionFactoryClassName; } /** * Gets the list of SQL statements executed when a physical connection is first created. Returns an empty list if * there are no initialization statements configured. * * @return initialization SQL statements */ public List getConnectionInitSqls() { final List result = connectionInitSqls; return result == null ? Collections.emptyList() : result; } /** * Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX. */ @Override public String[] getConnectionInitSqlsAsArray() { return getConnectionInitSqls().toArray(Utils.EMPTY_STRING_ARRAY); } /** * Gets the underlying connection pool. * * @return the underlying connection pool. * @since 2.10.0 */ public GenericObjectPool getConnectionPool() { return connectionPool; } Properties getConnectionProperties() { return connectionProperties; } /** * Gets the default auto-commit property. * * @return true if default auto-commit is enabled */ @Override public Boolean getDefaultAutoCommit() { return defaultAutoCommit; } /** * Gets the default catalog. * * @return the default catalog */ @Override public String getDefaultCatalog() { return this.defaultCatalog; } /** * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this * connection. {@code null} means that the driver default will be used. * * @return The default query timeout in seconds. * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}. */ @Deprecated public Integer getDefaultQueryTimeout() { return defaultQueryTimeoutDuration == null ? null : (int) defaultQueryTimeoutDuration.getSeconds(); } /** * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this * connection. {@code null} means that the driver default will be used. * * @return The default query timeout Duration. * @since 2.10.0 */ public Duration getDefaultQueryTimeoutDuration() { return defaultQueryTimeoutDuration; } /** * Gets the default readOnly property. * * @return true if connections are readOnly by default */ @Override public Boolean getDefaultReadOnly() { return defaultReadOnly; } /** * Gets the default schema. * * @return the default schema. * @since 2.5.0 */ @Override public String getDefaultSchema() { return this.defaultSchema; } /** * Gets the default transaction isolation state of returned connections. * * @return the default value for transaction isolation state * @see Connection#getTransactionIsolation */ @Override public int getDefaultTransactionIsolation() { return this.defaultTransactionIsolation; } /** * Gets the set of SQL_STATE codes considered to signal fatal conditions. * * @return fatal disconnection state codes * @see #setDisconnectionSqlCodes(Collection) * @since 2.1 */ public Set getDisconnectionSqlCodes() { final Set result = disconnectionSqlCodes; return result == null ? Collections.emptySet() : result; } /** * Provides the same data as {@link #getDisconnectionSqlCodes} but in an array so it is accessible via JMX. * * @since 2.1 */ @Override public String[] getDisconnectionSqlCodesAsArray() { return getDisconnectionSqlCodes().toArray(Utils.EMPTY_STRING_ARRAY); } /** * Gets the JDBC Driver that has been configured for use by this pool. *

* Note: This getter only returns the last value set by a call to {@link #setDriver(Driver)}. It does not return any * driver instance that may have been created from the value set via {@link #setDriverClassName(String)}. *

* * @return the JDBC Driver that has been configured for use by this pool */ public synchronized Driver getDriver() { return driver; } /** * Gets the class loader specified for loading the JDBC driver. Returns {@code null} if no class loader has * been explicitly specified. *

* Note: This getter only returns the last value set by a call to {@link #setDriverClassLoader(ClassLoader)}. It * does not return the class loader of any driver that may have been set via {@link #setDriver(Driver)}. *

* * @return The class loader specified for loading the JDBC driver. */ public synchronized ClassLoader getDriverClassLoader() { return this.driverClassLoader; } /** * Gets the JDBC driver class name. *

* Note: This getter only returns the last value set by a call to {@link #setDriverClassName(String)}. It does not * return the class name of any driver that may have been set via {@link #setDriver(Driver)}. *

* * @return the JDBC driver class name */ @Override public synchronized String getDriverClassName() { return this.driverClassName; } /** * Gets the value of the flag that controls whether or not connections being returned to the pool will be checked * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit * setting is {@code false} when the connection is returned. It is {@code true} by default. * * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit. * @deprecated Use {@link #getAutoCommitOnReturn()}. */ @Deprecated public boolean getEnableAutoCommitOnReturn() { return autoCommitOnReturn; } /** * Gets the EvictionPolicy implementation in use with this connection pool. * * @return The EvictionPolicy implementation in use with this connection pool. */ public synchronized String getEvictionPolicyClassName() { return evictionPolicyClassName; } /** * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with * SQL_STATE indicating fatal disconnection errors. * * @return true if connections created by this datasource will fast fail validation. * @see #setDisconnectionSqlCodes(Collection) * @since 2.1 */ @Override public boolean getFastFailValidation() { return fastFailValidation; } /** * Gets the initial size of the connection pool. * * @return the number of connections created when the pool is initialized */ @Override public synchronized int getInitialSize() { return this.initialSize; } /** * Gets the JMX name that has been requested for this DataSource. If the requested name is not valid, an * alternative may be chosen. * * @return The JMX name that has been requested for this DataSource. */ public String getJmxName() { return jmxName; } /** * Gets the LIFO property. * * @return true if connection pool behaves as a LIFO queue. */ @Override public synchronized boolean getLifo() { return this.lifo; } /** * Flag to log stack traces for application code which abandoned a Statement or Connection. *

* Defaults to false. *

*

* Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because * a stack trace has to be generated. *

*/ @Override public boolean getLogAbandoned() { return abandonedConfig != null && abandonedConfig.getLogAbandoned(); } /** * When {@link #getMaxConnDuration()} is set to limit connection lifetime, this property determines whether or * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. * * @since 2.1 */ @Override public boolean getLogExpiredConnections() { return logExpiredConnections; } /** * BasicDataSource does NOT support this method. * *

* Gets the login timeout (in seconds) for connecting to the database. *

*

* Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. *

* * @throws SQLException if a database access error occurs * @throws UnsupportedOperationException If the DataSource implementation does not support the login timeout * feature. * @return login timeout in seconds */ @Override public int getLoginTimeout() throws SQLException { // This method isn't supported by the PoolingDataSource returned by the createDataSource throw new UnsupportedOperationException("Not supported by BasicDataSource"); } /** * Gets the log writer being used by this data source. *

* Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. *

* * @throws SQLException if a database access error occurs * @return log writer in use */ @Override public PrintWriter getLogWriter() throws SQLException { return createDataSource().getLogWriter(); } /** * Gets the maximum permitted duration of a connection. A value of zero or less indicates an * infinite lifetime. * @return the maximum permitted duration of a connection. * @since 2.10.0 */ public Duration getMaxConnDuration() { return maxConnDuration; } /** * Gets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an * infinite lifetime. * @deprecated Use {@link #getMaxConnDuration()}. */ @Override @Deprecated public long getMaxConnLifetimeMillis() { return maxConnDuration.toMillis(); } /** * Gets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed * on return to the pool. *

* A negative value indicates that there is no limit *

* * @return the maximum number of idle connections */ @Override public synchronized int getMaxIdle() { return this.maxIdle; } /** * Gets the value of the {@code maxOpenPreparedStatements} property. * * @return the maximum number of open statements */ @Override public synchronized int getMaxOpenPreparedStatements() { return this.maxOpenPreparedStatements; } /** * Gets the maximum number of active connections that can be allocated at the same time. *

* A negative number means that there is no limit. *

* * @return the maximum number of active connections */ @Override public synchronized int getMaxTotal() { return this.maxTotal; } /** * Gets the maximum Duration that the pool will wait for a connection to be returned before throwing an exception. A * value less than or equal to zero means the pool is set to wait indefinitely. * * @return the maxWaitDuration property value. * @since 2.10.0 */ public synchronized Duration getMaxWaitDuration() { return this.maxWaitDuration; } /** * Gets the maximum number of milliseconds that the pool will wait for a connection to be returned before * throwing an exception. A value less than or equal to zero means the pool is set to wait indefinitely. * * @return the maxWaitMillis property value. * @deprecated Use {@link #getMaxWaitDuration()}. */ @Deprecated @Override public synchronized long getMaxWaitMillis() { return this.maxWaitDuration.toMillis(); } /** * Gets the {code minEvictableIdleDuration} property. * * @return the value of the {code minEvictableIdleDuration} property * @see #setMinEvictableIdle(Duration) * @since 2.10.0 */ public synchronized Duration getMinEvictableIdleDuration() { return this.minEvictableIdleDuration; } /** * Gets the {code minEvictableIdleDuration} property. * * @return the value of the {code minEvictableIdleDuration} property * @see #setMinEvictableIdle(Duration) * @deprecated Use {@link #getMinEvictableIdleDuration()}. */ @Deprecated @Override public synchronized long getMinEvictableIdleTimeMillis() { return this.minEvictableIdleDuration.toMillis(); } /** * Gets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections * are available when the idle object evictor runs. The value of this property has no effect unless * {code durationBetweenEvictionRuns} has a positive value. * * @return the minimum number of idle connections * @see GenericObjectPool#getMinIdle() */ @Override public synchronized int getMinIdle() { return this.minIdle; } /** * [Read Only] The current number of active connections that have been allocated from this data source. * * @return the current number of active connections */ @Override public int getNumActive() { // Copy reference to avoid NPE if close happens after null check final GenericObjectPool pool = connectionPool; return pool == null ? 0 : pool.getNumActive(); } /** * [Read Only] The current number of idle connections that are waiting to be allocated from this data source. * * @return the current number of idle connections */ @Override public int getNumIdle() { // Copy reference to avoid NPE if close happens after null check final GenericObjectPool pool = connectionPool; return pool == null ? 0 : pool.getNumIdle(); } /** * Gets the value of the {code numTestsPerEvictionRun} property. * * @return the number of objects to examine during idle object evictor runs * @see #setNumTestsPerEvictionRun(int) */ @Override public synchronized int getNumTestsPerEvictionRun() { return this.numTestsPerEvictionRun; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } /** * Gets the password passed to the JDBC driver to establish connections. * * @return the connection password */ @Override public String getPassword() { return this.password; } /** * Gets the registered JMX ObjectName. * * @return the registered JMX ObjectName. */ protected ObjectName getRegisteredJmxName() { return ObjectNameWrapper.unwrap(registeredJmxObjectName); } /** * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked. *

* The default value is false. *

*

* If set to true a connection is considered abandoned and eligible for removal if it has not been used for more * than {@link #getRemoveAbandonedTimeoutDuration() removeAbandonedTimeout} seconds. *

*

* Abandoned connections are identified and removed when {@link #getConnection()} is invoked and all of the * following conditions hold: *

*
    *
  • {@link #getRemoveAbandonedOnBorrow()}
  • *
  • {@link #getNumActive()} > {@link #getMaxTotal()} - 3
  • *
  • {@link #getNumIdle()} < 2
  • *
* * @see #getRemoveAbandonedTimeoutDuration() */ @Override public boolean getRemoveAbandonedOnBorrow() { return abandonedConfig != null && abandonedConfig.getRemoveAbandonedOnBorrow(); } /** * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout during pool maintenance. *

* The default value is false. *

*

* If set to true a connection is considered abandoned and eligible for removal if it has not been used for more * than {@link #getRemoveAbandonedTimeoutDuration() removeAbandonedTimeout} seconds. *

* * @see #getRemoveAbandonedTimeoutDuration() */ @Override public boolean getRemoveAbandonedOnMaintenance() { return abandonedConfig != null && abandonedConfig.getRemoveAbandonedOnMaintenance(); } /** * Gets the timeout in seconds before an abandoned connection can be removed. *

* Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one * of the execute methods) resets the lastUsed property of the parent connection. *

*

* Abandoned connection cleanup happens when: *

*
    *
  • {@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true
  • *
  • {@link #getNumIdle() numIdle} < 2
  • *
  • {@link #getNumActive() numActive} > {@link #getMaxTotal() maxTotal} - 3
  • *
*

* The default value is 300 seconds. *

* @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}. */ @Deprecated @Override public int getRemoveAbandonedTimeout() { return (int) getRemoveAbandonedTimeoutDuration().getSeconds(); } /** * Gets the timeout before an abandoned connection can be removed. *

* Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one * of the execute methods) resets the lastUsed property of the parent connection. *

*

* Abandoned connection cleanup happens when: *

*
    *
  • {@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true
  • *
  • {@link #getNumIdle() numIdle} < 2
  • *
  • {@link #getNumActive() numActive} > {@link #getMaxTotal() maxTotal} - 3
  • *
*

* The default value is 300 seconds. *

* @return Timeout before an abandoned connection can be removed. * @since 2.10.0 */ public Duration getRemoveAbandonedTimeoutDuration() { return abandonedConfig == null ? Duration.ofSeconds(300) : abandonedConfig.getRemoveAbandonedTimeoutDuration(); } /** * Gets the current value of the flag that controls whether a connection will be rolled back when it is returned to * the pool if auto commit is not enabled and the connection is not read only. * * @return whether a connection will be rolled back when it is returned to the pool. */ public boolean getRollbackOnReturn() { return rollbackOnReturn; } /** * Gets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool. *

* When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value, * minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are * visited by the evictor, idle time is first compared against {@code minEvictableIdleTimeMillis} (without * considering the number of idle connections in the pool) and then against {@code softMinEvictableIdleTimeMillis}, * including the {@code minIdle}, constraint. *

* * @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming * there are minIdle idle connections in the pool * @since 2.10.0 */ public synchronized Duration getSoftMinEvictableIdleDuration() { return softMinEvictableIdleDuration; } /** * Gets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool. *

* When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value, * minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are * visited by the evictor, idle time is first compared against {@code minEvictableIdleTimeMillis} (without * considering the number of idle connections in the pool) and then against {@code softMinEvictableIdleTimeMillis}, * including the {@code minIdle}, constraint. *

* * @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming * there are minIdle idle connections in the pool * @deprecated Use {@link #getSoftMinEvictableIdleDuration()}. */ @Deprecated @Override public synchronized long getSoftMinEvictableIdleTimeMillis() { return softMinEvictableIdleDuration.toMillis(); } /** * Gets the {code testOnBorrow} property. * * @return true if objects are validated before being borrowed from the pool * * @see #setTestOnBorrow(boolean) */ @Override public synchronized boolean getTestOnBorrow() { return this.testOnBorrow; } /** * Gets the {code testOnCreate} property. * * @return true if objects are validated immediately after they are created by the pool * @see #setTestOnCreate(boolean) */ @Override public synchronized boolean getTestOnCreate() { return this.testOnCreate; } /** * Gets the value of the {code testOnReturn} property. * * @return true if objects are validated before being returned to the pool * @see #setTestOnReturn(boolean) */ public synchronized boolean getTestOnReturn() { return this.testOnReturn; } /** * Gets the value of the {code testWhileIdle} property. * * @return true if objects examined by the idle object evictor are validated * @see #setTestWhileIdle(boolean) */ @Override public synchronized boolean getTestWhileIdle() { return this.testWhileIdle; } /** * Gets the value of the {code durationBetweenEvictionRuns} property. * * @return the time (in milliseconds) between evictor runs * @see #setDurationBetweenEvictionRuns(Duration) * @since 2.10.0 */ public synchronized Duration getDurationBetweenEvictionRuns() { return this.durationBetweenEvictionRuns; } /** * Gets the value of the {code durationBetweenEvictionRuns} property. * * @return the time (in milliseconds) between evictor runs * @see #setDurationBetweenEvictionRuns(Duration) * @deprecated Use {@link #getDurationBetweenEvictionRuns()}. */ @Deprecated @Override public synchronized long getTimeBetweenEvictionRunsMillis() { return this.durationBetweenEvictionRuns.toMillis(); } /** * Gets the JDBC connection {code connectionString} property. * * @return the {code connectionString} passed to the JDBC driver to establish connections */ @Override public synchronized String getUrl() { return this.connectionString; } /** * Gets the JDBC connection {code userName} property. * * @return the {code userName} passed to the JDBC driver to establish connections */ @Override public String getUsername() { return this.userName; } /** * Gets the validation query used to validate connections before returning them. * * @return the SQL validation query * @see #setValidationQuery(String) */ @Override public String getValidationQuery() { return this.validationQuery; } /** * Gets the validation query timeout. * * @return the timeout in seconds before connection validation queries fail. */ public Duration getValidationQueryTimeoutDuration() { return validationQueryTimeoutDuration; } /** * Gets the validation query timeout. * * @return the timeout in seconds before connection validation queries fail. * @deprecated Use {@link #getValidationQueryTimeoutDuration()}. */ @Deprecated @Override public int getValidationQueryTimeout() { return (int) validationQueryTimeoutDuration.getSeconds(); } /** * Manually invalidates a connection, effectively requesting the pool to try to close it, remove it from the pool * and reclaim pool capacity. * * @param connection The Connection to invalidate. * * @throws IllegalStateException if invalidating the connection failed. * @since 2.1 */ @SuppressWarnings("resource") public void invalidateConnection(final Connection connection) throws IllegalStateException { if (connection == null) { return; } if (connectionPool == null) { throw new IllegalStateException("Cannot invalidate connection: ConnectionPool is null."); } final PoolableConnection poolableConnection; try { poolableConnection = connection.unwrap(PoolableConnection.class); if (poolableConnection == null) { throw new IllegalStateException( "Cannot invalidate connection: Connection is not a poolable connection."); } } catch (final SQLException e) { throw new IllegalStateException("Cannot invalidate connection: Unwrapping poolable connection failed.", e); } try { connectionPool.invalidateObject(poolableConnection); } catch (final Exception e) { throw new IllegalStateException("Invalidating connection threw unexpected exception", e); } } /** * Gets the value of the accessToUnderlyingConnectionAllowed property. * * @return true if access to the underlying connection is allowed, false otherwise. */ @Override public synchronized boolean isAccessToUnderlyingConnectionAllowed() { return this.accessToUnderlyingConnectionAllowed; } /** * Returns true if the statement pool is cleared when the connection is returned to its pool. * * @return true if the statement pool is cleared at connection return * @since 2.8.0 */ @Override public boolean isClearStatementPoolOnReturn() { return clearStatementPoolOnReturn; } /** * If true, this data source is closed and no more connections can be retrieved from this data source. * * @return true, if the data source is closed; false otherwise */ @Override public synchronized boolean isClosed() { return closed; } /** * Delegates in a null-safe manner to {@link String#isEmpty()}. * * @param value the string to test, may be null. * @return boolean false if value is null, otherwise {@link String#isEmpty()}. */ private boolean isEmpty(final String value) { return value == null || value.trim().isEmpty(); } /** * Returns true if we are pooling statements. * * @return true if prepared and callable statements are pooled */ @Override public synchronized boolean isPoolPreparedStatements() { return this.poolPreparedStatements; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { return iface != null && iface.isInstance(this); } private void jmxRegister() { // Return immediately if this DataSource has already been registered if (registeredJmxObjectName != null) { return; } // Return immediately if no JMX name has been specified final String requestedName = getJmxName(); if (requestedName == null) { return; } registeredJmxObjectName = registerJmxObjectName(requestedName, null); try { final StandardMBean standardMBean = new StandardMBean(this, DataSourceMXBean.class); registeredJmxObjectName.registerMBean(standardMBean); } catch (final NotCompliantMBeanException e) { log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored."); } } /** * Logs the given message. * * @param message the message to log. */ protected void log(final String message) { if (logWriter != null) { logWriter.println(message); } } /** * Logs the given throwable. * @param message TODO * @param throwable the throwable. * * @since 2.7.0 */ protected void log(final String message, final Throwable throwable) { if (logWriter != null) { logWriter.println(message); throwable.printStackTrace(logWriter); } } @Override public void postDeregister() { // NO-OP } @Override public void postRegister(final Boolean registrationDone) { // NO-OP } @Override public void preDeregister() throws Exception { // NO-OP } @Override public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) { registeredJmxObjectName = registerJmxObjectName(getJmxName(), objectName); return ObjectNameWrapper.unwrap(registeredJmxObjectName); } private ObjectNameWrapper registerJmxObjectName(final String requestedName, final ObjectName objectName) { ObjectNameWrapper objectNameWrapper = null; if (requestedName != null) { try { objectNameWrapper = ObjectNameWrapper.wrap(requestedName); } catch (final MalformedObjectNameException e) { log.warn("The requested JMX name '" + requestedName + "' was not valid and will be ignored."); } } if (objectNameWrapper == null) { objectNameWrapper = ObjectNameWrapper.wrap(objectName); } return objectNameWrapper; } /** * Removes a custom connection property. * * @param name Name of the custom connection property to remove * @see #addConnectionProperty(String, String) */ public void removeConnectionProperty(final String name) { connectionProperties.remove(name); } /** * Restarts the datasource. *

* This method calls {@link #close()} and {@link #start()} in sequence within synchronized scope so any * connection requests that come in while the datasource is shutting down will be served by the new pool. *

* Idle connections that are stored in the connection pool when this method is invoked are closed, but * connections that are checked out to clients when this method is invoked are not affected. When client * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the * underlying JDBC connections are closed. These connections do not count in {@link #getMaxTotal()} or * {@link #getNumActive()} after invoking this method. For example, if there are 3 connections checked out by * clients when {@link #restart()} is invoked, after this method is called, {@link #getNumActive()} will * return 0 and up to {@link #getMaxTotal()} + 3 connections may be open until the connections sourced from * the original pool are returned. *

* The new connection pool created by this method is initialized with currently set configuration properties. * * @throws SQLException if an error occurs initializing the datasource */ @Override public synchronized void restart() throws SQLException { close(); start(); } private void setAbandoned(final BiConsumer consumer, final T object) { if (abandonedConfig == null) { abandonedConfig = new AbandonedConfig(); } consumer.accept(abandonedConfig, object); final GenericObjectPool gop = this.connectionPool; if (gop != null) { gop.setAbandonedConfig(abandonedConfig); } } private void setConnectionPool(final BiConsumer, T> consumer, final T object) { if (connectionPool != null) { consumer.accept(connectionPool, object); } } /** * Sets the print writer to be used by this configuration to log information on abandoned objects. * * @param logWriter The new log writer */ public void setAbandonedLogWriter(final PrintWriter logWriter) { setAbandoned(AbandonedConfig::setLogWriter, logWriter); } /** * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, configure whether * the connection pool should record a stack trace every time a method is called on a pooled connection and retain * the most recent stack trace to aid debugging of abandoned connections. * * @param usageTracking A value of {@code true} will enable the recording of a stack trace on every use of a * pooled connection */ public void setAbandonedUsageTracking(final boolean usageTracking) { setAbandoned(AbandonedConfig::setUseUsageTracking, usageTracking); } /** * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to * the underlying connection. (Default: false) *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param allow Access to the underlying connection is granted when true. */ public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { this.accessToUnderlyingConnectionAllowed = allow; } /** * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit * setting is {@code false} when the connection is returned. It is {@code true} by default. * * @param autoCommitOnReturn Whether or not connections being returned to the pool will be checked and configured * with auto-commit. * @since 2.6.0 */ public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) { this.autoCommitOnReturn = autoCommitOnReturn; } /** * Sets the state caching flag. * * @param cacheState The new value for the state caching flag */ public void setCacheState(final boolean cacheState) { this.cacheState = cacheState; } /** * Sets whether the pool of statements (which was enabled with {@link #setPoolPreparedStatements(boolean)}) should * be cleared when the connection is returned to its pool. Default is false. * * @param clearStatementPoolOnReturn clear or not * @since 2.8.0 */ public void setClearStatementPoolOnReturn(final boolean clearStatementPoolOnReturn) { this.clearStatementPoolOnReturn = clearStatementPoolOnReturn; } /** * Sets the ConnectionFactory class name. * * @param connectionFactoryClassName A class name. * @since 2.7.0 */ public void setConnectionFactoryClassName(final String connectionFactoryClassName) { this.connectionFactoryClassName = isEmpty(connectionFactoryClassName) ? null : connectionFactoryClassName; } /** * Sets the list of SQL statements to be executed when a physical connection is first created. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param connectionInitSqls Collection of SQL statements to execute on connection creation */ public void setConnectionInitSqls(final Collection connectionInitSqls) { // if (connectionInitSqls != null && !connectionInitSqls.isEmpty()) { // ArrayList newVal = null; // for (final String s : connectionInitSqls) { // if (!isEmpty(s)) { // if (newVal == null) { // newVal = new ArrayList<>(); // } // newVal.add(s); // } // } // this.connectionInitSqls = newVal; // } else { // this.connectionInitSqls = null; // } final List collect = Utils.isEmpty(connectionInitSqls) ? null : connectionInitSqls.stream().filter(s -> !isEmpty(s)).collect(Collectors.toList()); this.connectionInitSqls = Utils.isEmpty(collect) ? null : collect; } /** * Sets the connection properties passed to driver.connect(...). *

* Format of the string must be [propertyName=property;]* *

*

* NOTE - The "user" and "password" properties will be added explicitly, so they do not need to be included here. *

* * @param connectionProperties the connection properties used to create new connections */ public void setConnectionProperties(final String connectionProperties) { Objects.requireNonNull(connectionProperties, "connectionProperties"); final String[] entries = connectionProperties.split(";"); final Properties properties = new Properties(); Stream.of(entries).filter(e -> !e.isEmpty()).forEach(entry -> { final int index = entry.indexOf('='); if (index > 0) { final String name = entry.substring(0, index); final String value = entry.substring(index + 1); properties.setProperty(name, value); } else { // no value is empty string which is how // java.util.Properties works properties.setProperty(entry, ""); } }); this.connectionProperties = properties; } /** * Sets default auto-commit state of connections returned by this datasource. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param defaultAutoCommit default auto-commit value */ public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { this.defaultAutoCommit = defaultAutoCommit; } /** * Sets the default catalog. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param defaultCatalog the default catalog */ public void setDefaultCatalog(final String defaultCatalog) { this.defaultCatalog = isEmpty(defaultCatalog) ? null : defaultCatalog; } /** * Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this * connection. {@code null} means that the driver default will be used. * * @param defaultQueryTimeoutDuration The default query timeout Duration. * @since 2.10.0 */ public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) { this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration; } /** * Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this * connection. {@code null} means that the driver default will be used. * * @param defaultQueryTimeoutSeconds The default query timeout in seconds. * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}. */ @Deprecated public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds); } /** * Sets defaultReadonly property. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param defaultReadOnly default read-only value */ public void setDefaultReadOnly(final Boolean defaultReadOnly) { this.defaultReadOnly = defaultReadOnly; } /** * Sets the default schema. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param defaultSchema the default catalog * @since 2.5.0 */ public void setDefaultSchema(final String defaultSchema) { this.defaultSchema = isEmpty(defaultSchema) ? null : defaultSchema; } /** * Sets the default transaction isolation state for returned connections. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param defaultTransactionIsolation the default transaction isolation state * @see Connection#getTransactionIsolation */ public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { this.defaultTransactionIsolation = defaultTransactionIsolation; } /** * Sets the SQL_STATE codes considered to signal fatal conditions. *

* Overrides the defaults in {@link Utils#getDisconnectionSqlCodes()} (plus anything starting with * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #getFastFailValidation()} * is {@code true}, whenever connections created by this datasource generate exceptions with SQL_STATE codes in this * list, they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at * isValid or validation query). *

*

* If {@link #getFastFailValidation()} is {@code false} setting this property has no effect. *

*

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: {@code getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter}. *

* * @param disconnectionSqlCodes SQL_STATE codes considered to signal fatal conditions * @since 2.1 */ public void setDisconnectionSqlCodes(final Collection disconnectionSqlCodes) { // if (disconnectionSqlCodes != null && !disconnectionSqlCodes.isEmpty()) { // HashSet newVal = null; // for (final String s : disconnectionSqlCodes) { // if (!isEmpty(s)) { // if (newVal == null) { // newVal = new HashSet<>(); // } // newVal.add(s); // } // } // this.disconnectionSqlCodes = newVal; // } else { // this.disconnectionSqlCodes = null; // } final Set collect = Utils.isEmpty(disconnectionSqlCodes) ? null : disconnectionSqlCodes.stream().filter(s -> !isEmpty(s)).collect(Collectors.toSet()); this.disconnectionSqlCodes = Utils.isEmpty(collect) ? null : collect; } /** * Sets the JDBC Driver instance to use for this pool. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param driver The JDBC Driver instance to use for this pool. */ public synchronized void setDriver(final Driver driver) { this.driver = driver; } /** * Sets the class loader to be used to load the JDBC driver. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param driverClassLoader the class loader with which to load the JDBC driver */ public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) { this.driverClassLoader = driverClassLoader; } /** * Sets the JDBC driver class name. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param driverClassName the class name of the JDBC driver */ public synchronized void setDriverClassName(final String driverClassName) { this.driverClassName = isEmpty(driverClassName) ? null : driverClassName; } /** * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit * setting is {@code false} when the connection is returned. It is {@code true} by default. * * @param autoCommitOnReturn Whether or not connections being returned to the pool will be checked and configured * with auto-commit. * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}. */ @Deprecated public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) { this.autoCommitOnReturn = autoCommitOnReturn; } /** * Sets the EvictionPolicy implementation to use with this connection pool. * * @param evictionPolicyClassName The fully qualified class name of the EvictionPolicy implementation */ public synchronized void setEvictionPolicyClassName(final String evictionPolicyClassName) { setConnectionPool(GenericObjectPool::setEvictionPolicyClassName, evictionPolicyClassName); this.evictionPolicyClassName = evictionPolicyClassName; } /** * @see #getFastFailValidation() * @param fastFailValidation true means connections created by this factory will fast fail validation * @since 2.1 */ public void setFastFailValidation(final boolean fastFailValidation) { this.fastFailValidation = fastFailValidation; } /** * Sets the initial size of the connection pool. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param initialSize the number of connections created when the pool is initialized */ public synchronized void setInitialSize(final int initialSize) { this.initialSize = initialSize; } /** * Sets the JMX name that has been requested for this DataSource. If the requested name is not valid, an alternative * may be chosen. This DataSource will attempt to register itself using this name. If another component registers * this DataSource with JMX and this name is valid this name will be used in preference to any specified by the * other component. * * @param jmxName The JMX name that has been requested for this DataSource */ public void setJmxName(final String jmxName) { this.jmxName = jmxName; } /** * Sets if connection level JMX tracking is requested for this DataSource. If true, each connection will be * registered for tracking with JMX. * * @param registerConnectionMBean connection tracking requested for this DataSource. */ public void setRegisterConnectionMBean(final boolean registerConnectionMBean) { this.registerConnectionMBean = registerConnectionMBean; } /** * Sets the LIFO property. True means the pool behaves as a LIFO queue; false means FIFO. * * @param lifo the new value for the LIFO property */ public synchronized void setLifo(final boolean lifo) { this.lifo = lifo; setConnectionPool(GenericObjectPool::setLifo, lifo); } /** * @param logAbandoned new logAbandoned property value */ public void setLogAbandoned(final boolean logAbandoned) { setAbandoned(AbandonedConfig::setLogAbandoned, logAbandoned); } /** * When {@link #getMaxConnDuration()} is set to limit connection lifetime, this property determines whether or * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this * property to false to suppress log messages when connections expire. * * @param logExpiredConnections Whether or not log messages are generated when the pool closes connections due to * maximum lifetime exceeded. */ public void setLogExpiredConnections(final boolean logExpiredConnections) { this.logExpiredConnections = logExpiredConnections; } /** * BasicDataSource does NOT support this method. * *

* Set the login timeout (in seconds) for connecting to the database. *

*

* Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. *

* * @param loginTimeout The new login timeout, or zero for no timeout * @throws UnsupportedOperationException If the DataSource implementation does not support the login timeout * feature. * @throws SQLException if a database access error occurs */ @Override public void setLoginTimeout(final int loginTimeout) throws SQLException { // This method isn't supported by the PoolingDataSource returned by the // createDataSource throw new UnsupportedOperationException("Not supported by BasicDataSource"); } /** * Sets the log writer being used by this data source. *

* Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. *

* * @param logWriter The new log writer * @throws SQLException if a database access error occurs */ @Override public void setLogWriter(final PrintWriter logWriter) throws SQLException { createDataSource().setLogWriter(logWriter); this.logWriter = logWriter; } /** * Sets the maximum permitted lifetime of a connection. A value of zero or less indicates an * infinite lifetime. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param maxConnDuration The maximum permitted lifetime of a connection. * @since 2.10.0 */ public void setMaxConn(final Duration maxConnDuration) { this.maxConnDuration = maxConnDuration; } /** * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an * infinite lifetime. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param maxConnLifetimeMillis The maximum permitted lifetime of a connection in milliseconds. * @deprecated Use {@link #setMaxConn(Duration)}. */ @Deprecated public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { this.maxConnDuration = Duration.ofMillis(maxConnLifetimeMillis); } /** * Sets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed on * return to the pool. * * @see #getMaxIdle() * @param maxIdle the new value for maxIdle */ public synchronized void setMaxIdle(final int maxIdle) { this.maxIdle = maxIdle; setConnectionPool(GenericObjectPool::setMaxIdle, maxIdle); } /** * Sets the value of the {@code maxOpenPreparedStatements} property. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param maxOpenStatements the new maximum number of prepared statements */ public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) { this.maxOpenPreparedStatements = maxOpenStatements; } /** * Sets the maximum total number of idle and borrows connections that can be active at the same time. Use a negative * value for no limit. * * @param maxTotal the new value for maxTotal * @see #getMaxTotal() */ public synchronized void setMaxTotal(final int maxTotal) { this.maxTotal = maxTotal; setConnectionPool(GenericObjectPool::setMaxTotal, maxTotal); } /** * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely. * * @param maxWaitDuration the new value for MaxWaitMillis * @see #getMaxWaitDuration() * @since 2.10.0 */ public synchronized void setMaxWait(final Duration maxWaitDuration) { this.maxWaitDuration = maxWaitDuration; setConnectionPool(GenericObjectPool::setMaxWait, maxWaitDuration); } /** * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely. * * @param maxWaitMillis the new value for MaxWaitMillis * @see #getMaxWaitDuration() * @deprecated {@link #setMaxWait(Duration)}. */ @Deprecated public synchronized void setMaxWaitMillis(final long maxWaitMillis) { setMaxWait(Duration.ofMillis(maxWaitMillis)); } /** * Sets the {code minEvictableIdleDuration} property. * * @param minEvictableIdleDuration the minimum amount of time an object may sit idle in the pool * @see #setMinEvictableIdle(Duration) * @since 2.10.0 */ public synchronized void setMinEvictableIdle(final Duration minEvictableIdleDuration) { this.minEvictableIdleDuration = minEvictableIdleDuration; setConnectionPool(GenericObjectPool::setMinEvictableIdle, minEvictableIdleDuration); } /** * Sets the {code minEvictableIdleDuration} property. * * @param minEvictableIdleTimeMillis the minimum amount of time an object may sit idle in the pool * @see #setMinEvictableIdle(Duration) * @deprecated Use {@link #setMinEvictableIdle(Duration)}. */ @Deprecated public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) { setMinEvictableIdle(Duration.ofMillis(minEvictableIdleTimeMillis)); } /** * Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are * available when the idle object evictor runs. The value of this property has no effect unless * {code durationBetweenEvictionRuns} has a positive value. * * @param minIdle the new value for minIdle * @see GenericObjectPool#setMinIdle(int) */ public synchronized void setMinIdle(final int minIdle) { this.minIdle = minIdle; setConnectionPool(GenericObjectPool::setMinIdle, minIdle); } /** * Sets the value of the {code numTestsPerEvictionRun} property. * * @param numTestsPerEvictionRun the new {code numTestsPerEvictionRun} value * @see #setNumTestsPerEvictionRun(int) */ public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { this.numTestsPerEvictionRun = numTestsPerEvictionRun; setConnectionPool(GenericObjectPool::setNumTestsPerEvictionRun, numTestsPerEvictionRun); } /** * Sets the {code password}. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param password new value for the password */ public void setPassword(final String password) { this.password = password; } /** * Sets whether to pool statements or not. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param poolingStatements pooling on or off */ public synchronized void setPoolPreparedStatements(final boolean poolingStatements) { this.poolPreparedStatements = poolingStatements; } /** * @param removeAbandonedOnBorrow true means abandoned connections may be removed when connections are borrowed from * the pool. * @see #getRemoveAbandonedOnBorrow() */ public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) { setAbandoned(AbandonedConfig::setRemoveAbandonedOnBorrow, removeAbandonedOnBorrow); } /** * @param removeAbandonedOnMaintenance true means abandoned connections may be removed on pool maintenance. * @see #getRemoveAbandonedOnMaintenance() */ public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) { setAbandoned(AbandonedConfig::setRemoveAbandonedOnMaintenance, removeAbandonedOnMaintenance); } /** * Sets the timeout before an abandoned connection can be removed. *

* Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and * {code getRemoveAbandonedOnMaintenance()} are false. *

* * @param removeAbandonedTimeout new abandoned timeout * @see #getRemoveAbandonedTimeoutDuration() * @see #getRemoveAbandonedOnBorrow() * @see #getRemoveAbandonedOnMaintenance() * @since 2.10.0 */ public void setRemoveAbandonedTimeout(final Duration removeAbandonedTimeout) { setAbandoned(AbandonedConfig::setRemoveAbandonedTimeout, removeAbandonedTimeout); } /** * Sets the timeout in seconds before an abandoned connection can be removed. *

* Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and * {@link #getRemoveAbandonedOnMaintenance()} are false. *

* * @param removeAbandonedTimeout new abandoned timeout in seconds * @see #getRemoveAbandonedTimeoutDuration() * @see #getRemoveAbandonedOnBorrow() * @see #getRemoveAbandonedOnMaintenance() * @deprecated Use {@link #setRemoveAbandonedTimeout(Duration)}. */ @Deprecated public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) { setAbandoned(AbandonedConfig::setRemoveAbandonedTimeout, Duration.ofSeconds(removeAbandonedTimeout)); } /** * Sets the flag that controls if a connection will be rolled back when it is returned to the pool if auto commit is * not enabled and the connection is not read only. * * @param rollbackOnReturn whether a connection will be rolled back when it is returned to the pool. */ public void setRollbackOnReturn(final boolean rollbackOnReturn) { this.rollbackOnReturn = rollbackOnReturn; } /** * Sets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the * idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool. * * @param softMinEvictableIdleTimeMillis minimum amount of time a connection may sit idle in the pool before it is * eligible for eviction, assuming there are minIdle idle connections in the * pool. * @see #getSoftMinEvictableIdleTimeMillis * @since 2.10.0 */ public synchronized void setSoftMinEvictableIdle(final Duration softMinEvictableIdleTimeMillis) { this.softMinEvictableIdleDuration = softMinEvictableIdleTimeMillis; setConnectionPool(GenericObjectPool::setSoftMinEvictableIdle, softMinEvictableIdleTimeMillis); } /** * Sets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the * idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool. * * @param softMinEvictableIdleTimeMillis minimum amount of time a connection may sit idle in the pool before it is * eligible for eviction, assuming there are minIdle idle connections in the * pool. * @see #getSoftMinEvictableIdleTimeMillis * @deprecated Use {@link #setSoftMinEvictableIdle(Duration)}. */ @Deprecated public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) { setSoftMinEvictableIdle(Duration.ofMillis(softMinEvictableIdleTimeMillis)); } /** * Sets the {code testOnBorrow} property. This property determines whether or not the pool will validate objects * before they are borrowed from the pool. * * @param testOnBorrow new value for testOnBorrow property */ public synchronized void setTestOnBorrow(final boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; setConnectionPool(GenericObjectPool::setTestOnBorrow, testOnBorrow); } /** * Sets the {code testOnCreate} property. This property determines whether or not the pool will validate objects * immediately after they are created by the pool * * @param testOnCreate new value for testOnCreate property */ public synchronized void setTestOnCreate(final boolean testOnCreate) { this.testOnCreate = testOnCreate; setConnectionPool(GenericObjectPool::setTestOnCreate, testOnCreate); } /** * Sets the {@code testOnReturn} property. This property determines whether or not the pool will validate * objects before they are returned to the pool. * * @param testOnReturn new value for testOnReturn property */ public synchronized void setTestOnReturn(final boolean testOnReturn) { this.testOnReturn = testOnReturn; setConnectionPool(GenericObjectPool::setTestOnReturn, testOnReturn); } /** * Sets the {@code testWhileIdle} property. This property determines whether or not the idle object evictor * will validate connections. * * @param testWhileIdle new value for testWhileIdle property */ public synchronized void setTestWhileIdle(final boolean testWhileIdle) { this.testWhileIdle = testWhileIdle; setConnectionPool(GenericObjectPool::setTestWhileIdle, testWhileIdle); } /** * Sets the {code durationBetweenEvictionRuns} property. * * @param timeBetweenEvictionRunsMillis the new time between evictor runs * @see #setDurationBetweenEvictionRuns(Duration) * @since 2.10.0 */ public synchronized void setDurationBetweenEvictionRuns(final Duration timeBetweenEvictionRunsMillis) { this.durationBetweenEvictionRuns = timeBetweenEvictionRunsMillis; setConnectionPool(GenericObjectPool::setTimeBetweenEvictionRuns, timeBetweenEvictionRunsMillis); } /** * Sets the {code durationBetweenEvictionRuns} property. * * @param timeBetweenEvictionRunsMillis the new time between evictor runs * @see #setDurationBetweenEvictionRuns(Duration) * @deprecated Use {@link #setDurationBetweenEvictionRuns(Duration)}. */ @Deprecated public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { setDurationBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis)); } /** * Sets the {code connection string}. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param connectionString the new value for the JDBC connection connectionString */ public synchronized void setUrl(final String connectionString) { this.connectionString = connectionString; } /** * Sets the {code userName}. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param userName the new value for the JDBC connection user name */ public void setUsername(final String userName) { this.userName = userName; } /** * Sets the {code validationQuery}. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param validationQuery the new value for the validation query */ public void setValidationQuery(final String validationQuery) { this.validationQuery = isEmpty(validationQuery) ? null : validationQuery; } /** * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param validationQueryTimeoutDuration new validation query timeout value in seconds * @since 2.10.0 */ public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) { this.validationQueryTimeoutDuration = validationQueryTimeoutDuration; } /** * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout. *

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param validationQueryTimeoutSeconds new validation query timeout value in seconds * @deprecated Use {@link #setValidationQueryTimeout(Duration)}. */ @Deprecated public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds); } /** * Starts the datasource. *

* It is not necessary to call this method before using a newly created BasicDataSource instance, but * calling it in that context causes the datasource to be immediately initialized (instead of waiting for * the first {@link #getConnection()} request). Its primary use is to restart and reinitialize a * datasource that has been closed. *

* When this method is called after {@link #close()}, connections checked out by clients * before the datasource was stopped do not count in {@link #getMaxTotal()} or {@link #getNumActive()}. * For example, if there are 3 connections checked out by clients when {@link #close()} is invoked and they are * not returned before {@link #start()} is invoked, after this method is called, {@link #getNumActive()} will * return 0. These connections will be physically closed when they are returned, but they will not count against * the maximum allowed in the newly started datasource. * * @throws SQLException if an error occurs initializing the datasource */ @Override public synchronized void start() throws SQLException { closed = false; createDataSource(); } /** * Starts the connection pool maintenance task, if configured. */ protected void startPoolMaintenance() { if (connectionPool != null && durationBetweenEvictionRuns.compareTo(Duration.ZERO) > 0) { connectionPool.setTimeBetweenEvictionRuns(durationBetweenEvictionRuns); } } @Override public T unwrap(final Class iface) throws SQLException { if (isWrapperFor(iface)) { return iface.cast(this); } throw new SQLException(this + " is not a wrapper for " + iface); } private void updateJmxName(final GenericObjectPoolConfig config) { if (registeredJmxObjectName == null) { return; } final StringBuilder base = new StringBuilder(registeredJmxObjectName.toString()); base.append(Constants.JMX_CONNECTION_POOL_BASE_EXT); config.setJmxNameBase(base.toString()); config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX); } } BasicDataSourceFactory.java000066400000000000000000000621001447311732500335410ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.StringTokenizer; import java.util.function.Consumer; import java.util.function.Function; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.impl.BaseObjectPoolConfig; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; /** * JNDI object factory that creates an instance of {@code BasicDataSource} that has been configured based on the * {@code RefAddr} values of the specified {@code Reference}, which must match the names and data types of the * {@code BasicDataSource} bean properties with the following exceptions: *

    *
  • {@code connectionInitSqls} must be passed to this factory as a single String using semicolon to delimit the * statements whereas {@code BasicDataSource} requires a collection of Strings.
  • *
* * @since 2.0 */ public class BasicDataSourceFactory implements ObjectFactory { private static final Log log = LogFactory.getLog(BasicDataSourceFactory.class); private static final String PROP_DEFAULT_AUTO_COMMIT = "defaultAutoCommit"; private static final String PROP_DEFAULT_READ_ONLY = "defaultReadOnly"; private static final String PROP_DEFAULT_TRANSACTION_ISOLATION = "defaultTransactionIsolation"; private static final String PROP_DEFAULT_CATALOG = "defaultCatalog"; private static final String PROP_DEFAULT_SCHEMA = "defaultSchema"; private static final String PROP_CACHE_STATE = "cacheState"; private static final String PROP_DRIVER_CLASS_NAME = "driverClassName"; private static final String PROP_LIFO = "lifo"; private static final String PROP_MAX_TOTAL = "maxTotal"; private static final String PROP_MAX_IDLE = "maxIdle"; private static final String PROP_MIN_IDLE = "minIdle"; private static final String PROP_INITIAL_SIZE = "initialSize"; private static final String PROP_MAX_WAIT_MILLIS = "maxWaitMillis"; private static final String PROP_TEST_ON_CREATE = "testOnCreate"; private static final String PROP_TEST_ON_BORROW = "testOnBorrow"; private static final String PROP_TEST_ON_RETURN = "testOnReturn"; private static final String PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS = "timeBetweenEvictionRunsMillis"; private static final String PROP_NUM_TESTS_PER_EVICTION_RUN = "numTestsPerEvictionRun"; private static final String PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS = "minEvictableIdleTimeMillis"; private static final String PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = "softMinEvictableIdleTimeMillis"; private static final String PROP_EVICTION_POLICY_CLASS_NAME = "evictionPolicyClassName"; private static final String PROP_TEST_WHILE_IDLE = "testWhileIdle"; private static final String PROP_PASSWORD = Constants.KEY_PASSWORD; private static final String PROP_URL = "url"; private static final String PROP_USER_NAME = "username"; private static final String PROP_VALIDATION_QUERY = "validationQuery"; private static final String PROP_VALIDATION_QUERY_TIMEOUT = "validationQueryTimeout"; private static final String PROP_JMX_NAME = "jmxName"; private static final String PROP_REGISTER_CONNECTION_MBEAN = "registerConnectionMBean"; private static final String PROP_CONNECTION_FACTORY_CLASS_NAME = "connectionFactoryClassName"; /** * The property name for connectionInitSqls. The associated value String must be of the form [query;]* */ private static final String PROP_CONNECTION_INIT_SQLS = "connectionInitSqls"; private static final String PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED = "accessToUnderlyingConnectionAllowed"; private static final String PROP_REMOVE_ABANDONED_ON_BORROW = "removeAbandonedOnBorrow"; private static final String PROP_REMOVE_ABANDONED_ON_MAINTENANCE = "removeAbandonedOnMaintenance"; private static final String PROP_REMOVE_ABANDONED_TIMEOUT = "removeAbandonedTimeout"; private static final String PROP_LOG_ABANDONED = "logAbandoned"; private static final String PROP_ABANDONED_USAGE_TRACKING = "abandonedUsageTracking"; private static final String PROP_POOL_PREPARED_STATEMENTS = "poolPreparedStatements"; private static final String PROP_CLEAR_STATEMENT_POOL_ON_RETURN = "clearStatementPoolOnReturn"; private static final String PROP_MAX_OPEN_PREPARED_STATEMENTS = "maxOpenPreparedStatements"; private static final String PROP_CONNECTION_PROPERTIES = "connectionProperties"; private static final String PROP_MAX_CONN_LIFETIME_MILLIS = "maxConnLifetimeMillis"; private static final String PROP_LOG_EXPIRED_CONNECTIONS = "logExpiredConnections"; private static final String PROP_ROLLBACK_ON_RETURN = "rollbackOnReturn"; private static final String PROP_ENABLE_AUTO_COMMIT_ON_RETURN = "enableAutoCommitOnReturn"; private static final String PROP_DEFAULT_QUERY_TIMEOUT = "defaultQueryTimeout"; private static final String PROP_FAST_FAIL_VALIDATION = "fastFailValidation"; /** * Value string must be of the form [STATE_CODE,]* */ private static final String PROP_DISCONNECTION_SQL_CODES = "disconnectionSqlCodes"; /* * Block with obsolete properties from DBCP 1.x. Warn users that these are ignored and they should use the 2.x * properties. */ private static final String NUPROP_MAX_ACTIVE = "maxActive"; private static final String NUPROP_REMOVE_ABANDONED = "removeAbandoned"; private static final String NUPROP_MAXWAIT = "maxWait"; /* * Block with properties expected in a DataSource This props will not be listed as ignored - we know that they may * appear in Resource, and not listing them as ignored. */ private static final String SILENT_PROP_FACTORY = "factory"; private static final String SILENT_PROP_SCOPE = "scope"; private static final String SILENT_PROP_SINGLETON = "singleton"; private static final String SILENT_PROP_AUTH = "auth"; private static final List ALL_PROPERTY_NAMES = Arrays.asList(PROP_DEFAULT_AUTO_COMMIT, PROP_DEFAULT_READ_ONLY, PROP_DEFAULT_TRANSACTION_ISOLATION, PROP_DEFAULT_CATALOG, PROP_DEFAULT_SCHEMA, PROP_CACHE_STATE, PROP_DRIVER_CLASS_NAME, PROP_LIFO, PROP_MAX_TOTAL, PROP_MAX_IDLE, PROP_MIN_IDLE, PROP_INITIAL_SIZE, PROP_MAX_WAIT_MILLIS, PROP_TEST_ON_CREATE, PROP_TEST_ON_BORROW, PROP_TEST_ON_RETURN, PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS, PROP_NUM_TESTS_PER_EVICTION_RUN, PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS, PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS, PROP_EVICTION_POLICY_CLASS_NAME, PROP_TEST_WHILE_IDLE, PROP_PASSWORD, PROP_URL, PROP_USER_NAME, PROP_VALIDATION_QUERY, PROP_VALIDATION_QUERY_TIMEOUT, PROP_CONNECTION_INIT_SQLS, PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED, PROP_REMOVE_ABANDONED_ON_BORROW, PROP_REMOVE_ABANDONED_ON_MAINTENANCE, PROP_REMOVE_ABANDONED_TIMEOUT, PROP_LOG_ABANDONED, PROP_ABANDONED_USAGE_TRACKING, PROP_POOL_PREPARED_STATEMENTS, PROP_CLEAR_STATEMENT_POOL_ON_RETURN, PROP_MAX_OPEN_PREPARED_STATEMENTS, PROP_CONNECTION_PROPERTIES, PROP_MAX_CONN_LIFETIME_MILLIS, PROP_LOG_EXPIRED_CONNECTIONS, PROP_ROLLBACK_ON_RETURN, PROP_ENABLE_AUTO_COMMIT_ON_RETURN, PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION, PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME, PROP_REGISTER_CONNECTION_MBEAN, PROP_CONNECTION_FACTORY_CLASS_NAME); /** * Obsolete properties from DBCP 1.x. with warning strings suggesting new properties. LinkedHashMap will guarantee * that properties will be listed to output in order of insertion into map. */ private static final Map NUPROP_WARNTEXT = new LinkedHashMap<>(); static { NUPROP_WARNTEXT.put(NUPROP_MAX_ACTIVE, "Property " + NUPROP_MAX_ACTIVE + " is not used in DBCP2, use " + PROP_MAX_TOTAL + " instead. " + PROP_MAX_TOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL + "."); NUPROP_WARNTEXT.put(NUPROP_REMOVE_ABANDONED, "Property " + NUPROP_REMOVE_ABANDONED + " is not used in DBCP2," + " use one or both of " + PROP_REMOVE_ABANDONED_ON_BORROW + " or " + PROP_REMOVE_ABANDONED_ON_MAINTENANCE + " instead. " + "Both have default value set to false."); NUPROP_WARNTEXT.put(NUPROP_MAXWAIT, "Property " + NUPROP_MAXWAIT + " is not used in DBCP2" + " , use " + PROP_MAX_WAIT_MILLIS + " instead. " + PROP_MAX_WAIT_MILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT + "."); } /** * Silent Properties. These properties will not be listed as ignored - we know that they may appear in JDBC Resource * references, and we will not list them as ignored. */ private static final List SILENT_PROPERTIES = new ArrayList<>(); static { SILENT_PROPERTIES.add(SILENT_PROP_FACTORY); SILENT_PROPERTIES.add(SILENT_PROP_SCOPE); SILENT_PROPERTIES.add(SILENT_PROP_SINGLETON); SILENT_PROPERTIES.add(SILENT_PROP_AUTH); } private static void accept(final Properties properties, final String name, final Function parser, final Consumer consumer) { getOptional(properties, name).ifPresent(v -> consumer.accept(parser.apply(v))); } private static void acceptBoolean(final Properties properties, final String name, final Consumer consumer) { accept(properties, name, Boolean::parseBoolean, consumer); } private static void acceptDurationOfMillis(final Properties properties, final String name, final Consumer consumer) { accept(properties, name, s -> Duration.ofMillis(Long.parseLong(s)), consumer); } private static void acceptDurationOfSeconds(final Properties properties, final String name, final Consumer consumer) { accept(properties, name, s -> Duration.ofSeconds(Long.parseLong(s)), consumer); } private static void acceptInt(final Properties properties, final String name, final Consumer consumer) { accept(properties, name, Integer::parseInt, consumer); } private static void acceptString(final Properties properties, final String name, final Consumer consumer) { accept(properties, name, Function.identity(), consumer); } /** * Creates and configures a {@link BasicDataSource} instance based on the given properties. * * @param properties * The data source configuration properties. * @return A new a {@link BasicDataSource} instance based on the given properties. * @throws SQLException * Thrown when an error occurs creating the data source. */ public static BasicDataSource createDataSource(final Properties properties) throws SQLException { final BasicDataSource dataSource = new BasicDataSource(); acceptBoolean(properties, PROP_DEFAULT_AUTO_COMMIT, dataSource::setDefaultAutoCommit); acceptBoolean(properties, PROP_DEFAULT_READ_ONLY, dataSource::setDefaultReadOnly); getOptional(properties, PROP_DEFAULT_TRANSACTION_ISOLATION).ifPresent(value -> { value = value.toUpperCase(Locale.ROOT); int level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION; if ("NONE".equals(value)) { level = Connection.TRANSACTION_NONE; } else if ("READ_COMMITTED".equals(value)) { level = Connection.TRANSACTION_READ_COMMITTED; } else if ("READ_UNCOMMITTED".equals(value)) { level = Connection.TRANSACTION_READ_UNCOMMITTED; } else if ("REPEATABLE_READ".equals(value)) { level = Connection.TRANSACTION_REPEATABLE_READ; } else if ("SERIALIZABLE".equals(value)) { level = Connection.TRANSACTION_SERIALIZABLE; } else { try { level = Integer.parseInt(value); } catch (final NumberFormatException e) { System.err.println("Could not parse defaultTransactionIsolation: " + value); System.err.println("WARNING: defaultTransactionIsolation not set"); System.err.println("using default value of database driver"); level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION; } } dataSource.setDefaultTransactionIsolation(level); }); acceptString(properties, PROP_DEFAULT_SCHEMA, dataSource::setDefaultSchema); acceptString(properties, PROP_DEFAULT_CATALOG, dataSource::setDefaultCatalog); acceptBoolean(properties, PROP_CACHE_STATE, dataSource::setCacheState); acceptString(properties, PROP_DRIVER_CLASS_NAME, dataSource::setDriverClassName); acceptBoolean(properties, PROP_LIFO, dataSource::setLifo); acceptInt(properties, PROP_MAX_TOTAL, dataSource::setMaxTotal); acceptInt(properties, PROP_MAX_IDLE, dataSource::setMaxIdle); acceptInt(properties, PROP_MIN_IDLE, dataSource::setMinIdle); acceptInt(properties, PROP_INITIAL_SIZE, dataSource::setInitialSize); acceptDurationOfMillis(properties, PROP_MAX_WAIT_MILLIS, dataSource::setMaxWait); acceptBoolean(properties, PROP_TEST_ON_CREATE, dataSource::setTestOnCreate); acceptBoolean(properties, PROP_TEST_ON_BORROW, dataSource::setTestOnBorrow); acceptBoolean(properties, PROP_TEST_ON_RETURN, dataSource::setTestOnReturn); acceptDurationOfMillis(properties, PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS, dataSource::setDurationBetweenEvictionRuns); acceptInt(properties, PROP_NUM_TESTS_PER_EVICTION_RUN, dataSource::setNumTestsPerEvictionRun); acceptDurationOfMillis(properties, PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS, dataSource::setMinEvictableIdle); acceptDurationOfMillis(properties, PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS, dataSource::setSoftMinEvictableIdle); acceptString(properties, PROP_EVICTION_POLICY_CLASS_NAME, dataSource::setEvictionPolicyClassName); acceptBoolean(properties, PROP_TEST_WHILE_IDLE, dataSource::setTestWhileIdle); acceptString(properties, PROP_PASSWORD, dataSource::setPassword); acceptString(properties, PROP_URL, dataSource::setUrl); acceptString(properties, PROP_USER_NAME, dataSource::setUsername); acceptString(properties, PROP_VALIDATION_QUERY, dataSource::setValidationQuery); acceptDurationOfSeconds(properties, PROP_VALIDATION_QUERY_TIMEOUT, dataSource::setValidationQueryTimeout); acceptBoolean(properties, PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED, dataSource::setAccessToUnderlyingConnectionAllowed); acceptBoolean(properties, PROP_REMOVE_ABANDONED_ON_BORROW, dataSource::setRemoveAbandonedOnBorrow); acceptBoolean(properties, PROP_REMOVE_ABANDONED_ON_MAINTENANCE, dataSource::setRemoveAbandonedOnMaintenance); acceptDurationOfSeconds(properties, PROP_REMOVE_ABANDONED_TIMEOUT, dataSource::setRemoveAbandonedTimeout); acceptBoolean(properties, PROP_LOG_ABANDONED, dataSource::setLogAbandoned); acceptBoolean(properties, PROP_ABANDONED_USAGE_TRACKING, dataSource::setAbandonedUsageTracking); acceptBoolean(properties, PROP_POOL_PREPARED_STATEMENTS, dataSource::setPoolPreparedStatements); acceptBoolean(properties, PROP_CLEAR_STATEMENT_POOL_ON_RETURN, dataSource::setClearStatementPoolOnReturn); acceptInt(properties, PROP_MAX_OPEN_PREPARED_STATEMENTS, dataSource::setMaxOpenPreparedStatements); getOptional(properties, PROP_CONNECTION_INIT_SQLS).ifPresent(v -> dataSource.setConnectionInitSqls(parseList(v, ';'))); final String value = properties.getProperty(PROP_CONNECTION_PROPERTIES); if (value != null) { for (final Object key : getProperties(value).keySet()) { final String propertyName = Objects.toString(key, null); dataSource.addConnectionProperty(propertyName, getProperties(value).getProperty(propertyName)); } } acceptDurationOfMillis(properties, PROP_MAX_CONN_LIFETIME_MILLIS, dataSource::setMaxConn); acceptBoolean(properties, PROP_LOG_EXPIRED_CONNECTIONS, dataSource::setLogExpiredConnections); acceptString(properties, PROP_JMX_NAME, dataSource::setJmxName); acceptBoolean(properties, PROP_REGISTER_CONNECTION_MBEAN, dataSource::setRegisterConnectionMBean); acceptBoolean(properties, PROP_ENABLE_AUTO_COMMIT_ON_RETURN, dataSource::setAutoCommitOnReturn); acceptBoolean(properties, PROP_ROLLBACK_ON_RETURN, dataSource::setRollbackOnReturn); acceptDurationOfSeconds(properties, PROP_DEFAULT_QUERY_TIMEOUT, dataSource::setDefaultQueryTimeout); acceptBoolean(properties, PROP_FAST_FAIL_VALIDATION, dataSource::setFastFailValidation); getOptional(properties, PROP_DISCONNECTION_SQL_CODES).ifPresent(v -> dataSource.setDisconnectionSqlCodes(parseList(v, ','))); acceptString(properties, PROP_CONNECTION_FACTORY_CLASS_NAME, dataSource::setConnectionFactoryClassName); // DBCP-215 // Trick to make sure that initialSize connections are created if (dataSource.getInitialSize() > 0) { dataSource.getLogWriter(); } // Return the configured DataSource instance return dataSource; } private static Optional getOptional(final Properties properties, final String name) { return Optional.ofNullable(properties.getProperty(name)); } /** * Parse properties from the string. Format of the string must be [propertyName=property;]* * * @param propText The source text * @return Properties A new Properties instance * @throws SQLException When a paring exception occurs */ private static Properties getProperties(final String propText) throws SQLException { final Properties p = new Properties(); if (propText != null) { try { p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes(StandardCharsets.ISO_8859_1))); } catch (IOException e) { throw new SQLException(propText, e); } } return p; } /** * Parse list of property values from a delimited string * * @param value * delimited list of values * @param delimiter * character used to separate values in the list * @return String Collection of values */ private static Collection parseList(final String value, final char delimiter) { final StringTokenizer tokenizer = new StringTokenizer(value, Character.toString(delimiter)); final Collection tokens = new ArrayList<>(tokenizer.countTokens()); while (tokenizer.hasMoreTokens()) { tokens.add(tokenizer.nextToken()); } return tokens; } /** * Creates and return a new {@code BasicDataSource} instance. If no instance can be created, return * {@code 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 {@code nameCtx} * @param nameCtx * The context relative to which the {@code name} parameter is specified, or {@code null} if * {@code name} is relative to the default initial context * @param environment * The possibly null environment that is used in creating this object * * @throws SQLException * if an exception occurs creating the instance */ @Override public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable environment) throws SQLException { // We only know how to deal with {@code javax.naming.Reference}s // that specify a class name of "javax.sql.DataSource" if (obj == null || !(obj instanceof Reference)) { return null; } final Reference ref = (Reference) obj; if (!"javax.sql.DataSource".equals(ref.getClassName())) { return null; } // Check property names and log warnings about obsolete and / or unknown properties final List warnMessages = new ArrayList<>(); final List infoMessages = new ArrayList<>(); validatePropertyNames(ref, name, warnMessages, infoMessages); warnMessages.forEach(log::warn); infoMessages.forEach(log::info); final Properties properties = new Properties(); ALL_PROPERTY_NAMES.forEach(propertyName -> { final RefAddr ra = ref.get(propertyName); if (ra != null) { properties.setProperty(propertyName, Objects.toString(ra.getContent(), null)); } }); return createDataSource(properties); } /** * Collects warnings and info messages. Warnings are generated when an obsolete property is set. Unknown properties * generate info messages. * * @param ref * Reference to check properties of * @param name * Name provided to getObject * @param warnMessages * container for warning messages * @param infoMessages * container for info messages */ private void validatePropertyNames(final Reference ref, final Name name, final List warnMessages, final List infoMessages) { final String nameString = name != null ? "Name = " + name.toString() + " " : ""; if (NUPROP_WARNTEXT != null && !NUPROP_WARNTEXT.isEmpty()) { NUPROP_WARNTEXT.forEach((propertyName, value) -> { final RefAddr ra = ref.get(propertyName); if (ra != null && !ALL_PROPERTY_NAMES.contains(ra.getType())) { final StringBuilder stringBuilder = new StringBuilder(nameString); final String propertyValue = Objects.toString(ra.getContent(), null); stringBuilder.append(value).append(" You have set value of \"").append(propertyValue).append("\" for \"").append(propertyName) .append("\" property, which is being ignored."); warnMessages.add(stringBuilder.toString()); } }); } final Enumeration allRefAddrs = ref.getAll(); while (allRefAddrs.hasMoreElements()) { final RefAddr ra = allRefAddrs.nextElement(); final String propertyName = ra.getType(); // If property name is not in the properties list, we haven't warned on it // and it is not in the "silent" list, tell user we are ignoring it. if (!(ALL_PROPERTY_NAMES.contains(propertyName) || NUPROP_WARNTEXT.containsKey(propertyName) || SILENT_PROPERTIES.contains(propertyName))) { final String propertyValue = Objects.toString(ra.getContent(), null); final StringBuilder stringBuilder = new StringBuilder(nameString); stringBuilder.append("Ignoring unknown property: ").append("value of \"").append(propertyValue).append("\" for \"").append(propertyName) .append("\" property"); infoMessages.add(stringBuilder.toString()); } } } } BasicDataSourceMXBean.java000066400000000000000000000026431447311732500332520ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; /** * Interface to keep API compatibility. Methods listed here are not made available to * JMX. *

* As of 2.9.0, this interface extends {@link DataSourceMXBean}. *

* * @since 2.0 */ public interface BasicDataSourceMXBean extends DataSourceMXBean { /** * See {@link BasicDataSource#getPassword()} * * @return {@link BasicDataSource#getPassword()} * @deprecated exposing password via JMX is an Information Exposure issue. */ @Deprecated String getPassword(); } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/ConnectionFactory.java000066400000000000000000000025021447311732500327230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.SQLException; /** * Abstract factory interface for creating {@link java.sql.Connection}s. * * @since 2.0 */ public interface ConnectionFactory { /** * Create a new {@link java.sql.Connection} in an implementation specific fashion. * * @return a new {@link java.sql.Connection} * @throws SQLException * if a database error occurs creating the connection */ Connection createConnection() throws SQLException; } ConnectionFactoryFactory.java000066400000000000000000000065771447311732500342140ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Driver; import java.sql.SQLException; import java.util.Properties; /* * Creates {@link ConnectionFactory} instances. * * @since 2.7.0 */ final class ConnectionFactoryFactory { /** * Creates a new {@link DriverConnectionFactory} allowing for an override through * {@link BasicDataSource#getDriverClassName()}. * * @param basicDataSource Configures creation. * @param driver The JDBC driver. * @return a new {@link DriverConnectionFactory} allowing for a {@link BasicDataSource#getDriverClassName()} * override. * @throws SQLException Thrown when instantiation fails. */ static ConnectionFactory createConnectionFactory(final BasicDataSource basicDataSource, final Driver driver) throws SQLException { final Properties connectionProperties = basicDataSource.getConnectionProperties(); final String url = basicDataSource.getUrl(); // Set up the driver connection factory we will use final String user = basicDataSource.getUsername(); if (user != null) { connectionProperties.put(Constants.KEY_USER, user); } else { basicDataSource.log(String.format("DBCP DataSource configured without a '%s'", Constants.KEY_USER)); } final String pwd = basicDataSource.getPassword(); if (pwd != null) { connectionProperties.put(Constants.KEY_PASSWORD, pwd); } else { basicDataSource.log(String.format("DBCP DataSource configured without a '%s'", Constants.KEY_PASSWORD)); } final String connectionFactoryClassName = basicDataSource.getConnectionFactoryClassName(); if (connectionFactoryClassName != null) { try { final Class connectionFactoryFromCCL = Class.forName(connectionFactoryClassName); return (ConnectionFactory) connectionFactoryFromCCL .getConstructor(Driver.class, String.class, Properties.class) .newInstance(driver, url, connectionProperties); } catch (final Exception t) { final String message = "Cannot load ConnectionFactory implementation '" + connectionFactoryClassName + "'"; basicDataSource.log(message, t); throw new SQLException(message, t); } } // Defaults to DriverConnectionFactory return new DriverConnectionFactory(driver, url, connectionProperties); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/Constants.java000066400000000000000000000032131447311732500312500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; /** * Constants. * * @since 2.0 */ public class Constants { public static final String JMX_CONNECTION_POOL_BASE_EXT = ",connectionpool="; public static final String JMX_CONNECTION_POOL_PREFIX = "connections"; public static final String JMX_CONNECTION_BASE_EXT = JMX_CONNECTION_POOL_BASE_EXT + JMX_CONNECTION_POOL_PREFIX + ",connection="; public static final String JMX_STATEMENT_POOL_BASE_EXT = JMX_CONNECTION_BASE_EXT; public static final String JMX_STATEMENT_POOL_PREFIX = ",statementpool=statements"; /** * JDBC properties and URL key for passwords. * * @since 2.9.0 */ public static final String KEY_PASSWORD = "password"; /** * JDBC properties and URL key for users. * * @since 2.9.0 */ public static final String KEY_USER = "user"; } DataSourceConnectionFactory.java000066400000000000000000000064761447311732500346350ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; /** * A {@link DataSource}-based implementation of {@link ConnectionFactory}. * * @since 2.0 */ public class DataSourceConnectionFactory implements ConnectionFactory { private final DataSource dataSource; private final String userName; private final char[] userPassword; /** * Constructs an instance for the given DataSource. * * @param dataSource * The DataSource for this factory. */ public DataSourceConnectionFactory(final DataSource dataSource) { this(dataSource, null, (char[]) null); } /** * Constructs an instance for the given DataSource. * * @param dataSource * The DataSource for this factory. * @param userName * The user name. * @param userPassword * The user password. * @since 2.4.0 */ public DataSourceConnectionFactory(final DataSource dataSource, final String userName, final char[] userPassword) { this.dataSource = dataSource; this.userName = userName; this.userPassword = Utils.clone(userPassword); } /** * Constructs an instance for the given DataSource. * * @param dataSource * The DataSource for this factory. * @param userName * The user name. * @param password * The user password. */ public DataSourceConnectionFactory(final DataSource dataSource, final String userName, final String password) { this.dataSource = dataSource; this.userName = userName; this.userPassword = Utils.toCharArray(password); } @Override public Connection createConnection() throws SQLException { if (null == userName && null == userPassword) { return dataSource.getConnection(); } return dataSource.getConnection(userName, Utils.toString(userPassword)); } /** * @return The data source. * @since 2.6.0 */ public DataSource getDataSource() { return dataSource; } /** * @return The user name. * @since 2.6.0 */ public String getUserName() { return userName; } /** * @return The user password. * @since 2.6.0 */ public char[] getUserPassword() { return Utils.clone(userPassword); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/DataSourceMXBean.java000066400000000000000000000217171447311732500323720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.SQLException; /** * Defines the methods that will be made available via * JMX. * * @since 2.9.0 */ public interface DataSourceMXBean { /** * See {@link BasicDataSource#getAbandonedUsageTracking()}. * * @return {@link BasicDataSource#getAbandonedUsageTracking()} */ boolean getAbandonedUsageTracking(); /** * See {@link BasicDataSource#getCacheState()}. * * @return {@link BasicDataSource#getCacheState()}. */ boolean getCacheState(); /** * See {@link BasicDataSource#getConnectionInitSqlsAsArray()}. * * @return {@link BasicDataSource#getConnectionInitSqlsAsArray()}. */ String[] getConnectionInitSqlsAsArray(); /** * See {@link BasicDataSource#getDefaultAutoCommit()}. * * @return {@link BasicDataSource#getDefaultAutoCommit()}. */ Boolean getDefaultAutoCommit(); /** * See {@link BasicDataSource#getDefaultCatalog()}. * * @return {@link BasicDataSource#getDefaultCatalog()}. */ String getDefaultCatalog(); /** * See {@link BasicDataSource#getDefaultReadOnly()}. * * @return {@link BasicDataSource#getDefaultReadOnly()}. */ Boolean getDefaultReadOnly(); /** * See {@link BasicDataSource#getDefaultSchema()}. * * @return {@link BasicDataSource#getDefaultSchema()}. * @since 2.5.0 */ default String getDefaultSchema() { return null; } /** * See {@link BasicDataSource#getDefaultTransactionIsolation()}. * * @return {@link BasicDataSource#getDefaultTransactionIsolation()}. */ int getDefaultTransactionIsolation(); /** * See {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}. * * @return {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}. * @since 2.1 */ String[] getDisconnectionSqlCodesAsArray(); /** * See {@link BasicDataSource#getDriverClassName()}. * * @return {@link BasicDataSource#getDriverClassName()}. */ String getDriverClassName(); /** * See {@link BasicDataSource#getFastFailValidation()}. * * @return {@link BasicDataSource#getFastFailValidation()}. * @since 2.1 */ boolean getFastFailValidation(); /** * See {@link BasicDataSource#getInitialSize()}. * * @return {@link BasicDataSource#getInitialSize()}. */ int getInitialSize(); /** * See {@link BasicDataSource#getLifo()}. * * @return {@link BasicDataSource#getLifo()}. */ boolean getLifo(); /** * See {@link BasicDataSource#getLogAbandoned()}. * * @return {@link BasicDataSource#getLogAbandoned()}. */ boolean getLogAbandoned(); /** * See {@link BasicDataSource#getLogExpiredConnections()}. * * @return {@link BasicDataSource#getLogExpiredConnections()}. * @since 2.1 */ boolean getLogExpiredConnections(); /** * See {@link BasicDataSource#getMaxConnLifetimeMillis()}. * * @return {@link BasicDataSource#getMaxConnLifetimeMillis()}. */ long getMaxConnLifetimeMillis(); /** * See {@link BasicDataSource#getMaxIdle()}. * * @return {@link BasicDataSource#getMaxIdle()}. */ int getMaxIdle(); /** * See {@link BasicDataSource#getMaxOpenPreparedStatements()}. * * @return {@link BasicDataSource#getMaxOpenPreparedStatements()}. */ int getMaxOpenPreparedStatements(); /** * See {@link BasicDataSource#getMaxTotal()}. * * @return {@link BasicDataSource#getMaxTotal()}. */ int getMaxTotal(); /** * See {@link BasicDataSource#getMaxWaitMillis()}. * * @return {@link BasicDataSource#getMaxWaitMillis()}. */ long getMaxWaitMillis(); /** * See {@link BasicDataSource#getMinEvictableIdleTimeMillis()}. * * @return {@link BasicDataSource#getMinEvictableIdleTimeMillis()}. */ long getMinEvictableIdleTimeMillis(); /** * See {@link BasicDataSource#getMinIdle()}. * * @return {@link BasicDataSource#getMinIdle()}. */ int getMinIdle(); /** * See {@link BasicDataSource#getNumActive()}. * * @return {@link BasicDataSource#getNumActive()}. */ int getNumActive(); /** * See {@link BasicDataSource#getNumIdle()}. * * @return {@link BasicDataSource#getNumIdle()}. */ int getNumIdle(); /** * See {@link BasicDataSource#getNumTestsPerEvictionRun()}. * * @return {@link BasicDataSource#getNumTestsPerEvictionRun()}. */ int getNumTestsPerEvictionRun(); /** * See {@link BasicDataSource#getRemoveAbandonedOnBorrow()}. * * @return {@link BasicDataSource#getRemoveAbandonedOnBorrow()}. */ boolean getRemoveAbandonedOnBorrow(); /** * See {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}. * * @return {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}. */ boolean getRemoveAbandonedOnMaintenance(); /** * See {@link BasicDataSource#getRemoveAbandonedTimeout()}. * * @return {@link BasicDataSource#getRemoveAbandonedTimeout()}. */ int getRemoveAbandonedTimeout(); /** * See {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}. * * @return {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}. */ long getSoftMinEvictableIdleTimeMillis(); /** * See {@link BasicDataSource#getTestOnBorrow()}. * * @return {@link BasicDataSource#getTestOnBorrow()}. */ boolean getTestOnBorrow(); /** * See {@link BasicDataSource#getTestOnCreate()}. * * @return {@link BasicDataSource#getTestOnCreate()}. */ boolean getTestOnCreate(); /** * See {@link BasicDataSource#getTestWhileIdle()}. * * @return {@link BasicDataSource#getTestWhileIdle()}. */ boolean getTestWhileIdle(); /** * See {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}. * * @return {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}. */ long getTimeBetweenEvictionRunsMillis(); /** * See {@link BasicDataSource#getUrl()}. * * @return {@link BasicDataSource#getUrl()}. */ String getUrl(); /** * See {@link BasicDataSource#getUsername()}. * * @return {@link BasicDataSource#getUsername()}. */ String getUsername(); /** * See {@link BasicDataSource#getValidationQuery()}. * * @return {@link BasicDataSource#getValidationQuery()}. */ String getValidationQuery(); /** * See {@link BasicDataSource#getValidationQueryTimeout()}. * * @return {@link BasicDataSource#getValidationQueryTimeout()}. */ int getValidationQueryTimeout(); /** * See {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}. * * @return {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}. */ boolean isAccessToUnderlyingConnectionAllowed(); /** * See {@link BasicDataSource#isClearStatementPoolOnReturn()}. * * @return {@link BasicDataSource#isClearStatementPoolOnReturn()}. * @since 2.8.0 */ default boolean isClearStatementPoolOnReturn() { return false; } /** * See {@link BasicDataSource#isClosed()}. * * @return {@link BasicDataSource#isClosed()}. */ boolean isClosed(); /** * See {@link BasicDataSource#isPoolPreparedStatements()}. * * @return {@link BasicDataSource#isPoolPreparedStatements()}. */ boolean isPoolPreparedStatements(); /** * See {@link BasicDataSource#restart()} * * @throws SQLException if an error occurs initializing the data source. * * @since 2.8.0 */ default void restart() throws SQLException { // do nothing by default? } /** * See {@link BasicDataSource#start()} * * @throws SQLException if an error occurs initializing the data source. * * @since 2.8.0 */ default void start() throws SQLException { // do nothing } } DelegatingCallableStatement.java000066400000000000000000001226431447311732500345760ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Date; import java.sql.NClob; import java.sql.Ref; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLType; import java.sql.SQLXML; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; import java.util.Map; /** * A base delegating implementation of {@link CallableStatement}. *

* All of the methods from the {@link CallableStatement} interface simply call the corresponding method on the * "delegate" provided in my constructor. *

*

* Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the * Statement ensures that the Connection which created it can close any open Statement's on Connection close. *

* * @since 2.0 */ public class DelegatingCallableStatement extends DelegatingPreparedStatement implements CallableStatement { /** * Creates a wrapper for the Statement which traces this Statement to the Connection which created it and the code * which created it. * * @param connection * the {@link DelegatingConnection} that created this statement * @param statement * the {@link CallableStatement} to delegate all calls to */ public DelegatingCallableStatement(final DelegatingConnection connection, final CallableStatement statement) { super(connection, statement); } @Override public Array getArray(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getArray(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Array getArray(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getArray(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public BigDecimal getBigDecimal(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBigDecimal(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } /** @deprecated Use {@link #getBigDecimal(int)} or {@link #getBigDecimal(String)} */ @Override @Deprecated public BigDecimal getBigDecimal(final int parameterIndex, final int scale) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBigDecimal(parameterIndex, scale); } catch (final SQLException e) { handleException(e); return null; } } @Override public BigDecimal getBigDecimal(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBigDecimal(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Blob getBlob(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBlob(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Blob getBlob(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBlob(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public boolean getBoolean(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBoolean(parameterIndex); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean getBoolean(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBoolean(parameterName); } catch (final SQLException e) { handleException(e); return false; } } @Override public byte getByte(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getByte(parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public byte getByte(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getByte(parameterName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public byte[] getBytes(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBytes(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public byte[] getBytes(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getBytes(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Reader getCharacterStream(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getCharacterStream(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Reader getCharacterStream(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getCharacterStream(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Clob getClob(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getClob(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Clob getClob(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getClob(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getDate(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final int parameterIndex, final Calendar cal) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getDate(parameterIndex, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getDate(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final String parameterName, final Calendar cal) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getDate(parameterName, cal); } catch (final SQLException e) { handleException(e); return null; } } private CallableStatement getDelegateCallableStatement() { return (CallableStatement) getDelegate(); } @Override public double getDouble(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getDouble(parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public double getDouble(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getDouble(parameterName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public float getFloat(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getFloat(parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public float getFloat(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getFloat(parameterName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getInt(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getInt(parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getInt(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getInt(parameterName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public long getLong(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getLong(parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public long getLong(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getLong(parameterName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public Reader getNCharacterStream(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getNCharacterStream(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Reader getNCharacterStream(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getNCharacterStream(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public NClob getNClob(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getNClob(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public NClob getNClob(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getNClob(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getNString(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getNString(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getNString(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getNString(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getObject(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public T getObject(final int parameterIndex, final Class type) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getObject(parameterIndex, type); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final int i, final Map> map) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getObject(i, map); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getObject(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public T getObject(final String parameterName, final Class type) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getObject(parameterName, type); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final String parameterName, final Map> map) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getObject(parameterName, map); } catch (final SQLException e) { handleException(e); return null; } } @Override public Ref getRef(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getRef(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Ref getRef(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getRef(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public RowId getRowId(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getRowId(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public RowId getRowId(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getRowId(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public short getShort(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getShort(parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public short getShort(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getShort(parameterName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public SQLXML getSQLXML(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getSQLXML(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public SQLXML getSQLXML(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getSQLXML(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getString(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getString(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getString(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getString(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTime(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final int parameterIndex, final Calendar cal) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTime(parameterIndex, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTime(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final String parameterName, final Calendar cal) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTime(parameterName, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTimestamp(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final int parameterIndex, final Calendar cal) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTimestamp(parameterIndex, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTimestamp(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final String parameterName, final Calendar cal) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getTimestamp(parameterName, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public URL getURL(final int parameterIndex) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getURL(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public URL getURL(final String parameterName) throws SQLException { checkOpen(); try { return getDelegateCallableStatement().getURL(parameterName); } catch (final SQLException e) { handleException(e); return null; } } @Override public void registerOutParameter(final int parameterIndex, final int sqlType) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterIndex, sqlType); } catch (final SQLException e) { handleException(e); } } @Override public void registerOutParameter(final int parameterIndex, final int sqlType, final int scale) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterIndex, sqlType, scale); } catch (final SQLException e) { handleException(e); } } @Override public void registerOutParameter(final int paramIndex, final int sqlType, final String typeName) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(paramIndex, sqlType, typeName); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void registerOutParameter(final int parameterIndex, final SQLType sqlType) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterIndex, sqlType); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void registerOutParameter(final int parameterIndex, final SQLType sqlType, final int scale) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterIndex, sqlType, scale); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void registerOutParameter(final int parameterIndex, final SQLType sqlType, final String typeName) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterIndex, sqlType, typeName); } catch (final SQLException e) { handleException(e); } } @Override public void registerOutParameter(final String parameterName, final int sqlType) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterName, sqlType); } catch (final SQLException e) { handleException(e); } } @Override public void registerOutParameter(final String parameterName, final int sqlType, final int scale) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterName, sqlType, scale); } catch (final SQLException e) { handleException(e); } } @Override public void registerOutParameter(final String parameterName, final int sqlType, final String typeName) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterName, sqlType, typeName); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void registerOutParameter(final String parameterName, final SQLType sqlType) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterName, sqlType); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void registerOutParameter(final String parameterName, final SQLType sqlType, final int scale) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterName, sqlType, scale); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void registerOutParameter(final String parameterName, final SQLType sqlType, final String typeName) throws SQLException { checkOpen(); try { getDelegateCallableStatement().registerOutParameter(parameterName, sqlType, typeName); } catch (final SQLException e) { handleException(e); } } @Override public void setAsciiStream(final String parameterName, final InputStream inputStream) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setAsciiStream(parameterName, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void setAsciiStream(final String parameterName, final InputStream x, final int length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setAsciiStream(parameterName, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void setAsciiStream(final String parameterName, final InputStream inputStream, final long length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setAsciiStream(parameterName, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBigDecimal(final String parameterName, final BigDecimal x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBigDecimal(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setBinaryStream(final String parameterName, final InputStream inputStream) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBinaryStream(parameterName, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void setBinaryStream(final String parameterName, final InputStream x, final int length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBinaryStream(parameterName, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBinaryStream(final String parameterName, final InputStream inputStream, final long length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBinaryStream(parameterName, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBlob(final String parameterName, final Blob blob) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBlob(parameterName, blob); } catch (final SQLException e) { handleException(e); } } @Override public void setBlob(final String parameterName, final InputStream inputStream) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBlob(parameterName, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void setBlob(final String parameterName, final InputStream inputStream, final long length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBlob(parameterName, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBoolean(final String parameterName, final boolean x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBoolean(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setByte(final String parameterName, final byte x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setByte(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setBytes(final String parameterName, final byte[] x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setBytes(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setCharacterStream(final String parameterName, final Reader reader) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setCharacterStream(parameterName, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setCharacterStream(final String parameterName, final Reader reader, final int length) throws SQLException { checkOpen(); getDelegateCallableStatement().setCharacterStream(parameterName, reader, length); } @Override public void setCharacterStream(final String parameterName, final Reader reader, final long length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setCharacterStream(parameterName, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setClob(final String parameterName, final Clob clob) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setClob(parameterName, clob); } catch (final SQLException e) { handleException(e); } } @Override public void setClob(final String parameterName, final Reader reader) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setClob(parameterName, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setClob(final String parameterName, final Reader reader, final long length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setClob(parameterName, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setDate(final String parameterName, final Date x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setDate(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setDate(final String parameterName, final Date x, final Calendar cal) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setDate(parameterName, x, cal); } catch (final SQLException e) { handleException(e); } } @Override public void setDouble(final String parameterName, final double x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setDouble(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setFloat(final String parameterName, final float x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setFloat(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setInt(final String parameterName, final int x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setInt(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setLong(final String parameterName, final long x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setLong(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setNCharacterStream(final String parameterName, final Reader reader) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNCharacterStream(parameterName, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setNCharacterStream(final String parameterName, final Reader reader, final long length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNCharacterStream(parameterName, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setNClob(final String parameterName, final NClob value) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNClob(parameterName, value); } catch (final SQLException e) { handleException(e); } } @Override public void setNClob(final String parameterName, final Reader reader) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNClob(parameterName, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setNClob(final String parameterName, final Reader reader, final long length) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNClob(parameterName, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setNString(final String parameterName, final String value) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNString(parameterName, value); } catch (final SQLException e) { handleException(e); } } @Override public void setNull(final String parameterName, final int sqlType) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNull(parameterName, sqlType); } catch (final SQLException e) { handleException(e); } } @Override public void setNull(final String parameterName, final int sqlType, final String typeName) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setNull(parameterName, sqlType, typeName); } catch (final SQLException e) { handleException(e); } } @Override public void setObject(final String parameterName, final Object x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setObject(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setObject(final String parameterName, final Object x, final int targetSqlType) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setObject(parameterName, x, targetSqlType); } catch (final SQLException e) { handleException(e); } } @Override public void setObject(final String parameterName, final Object x, final int targetSqlType, final int scale) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setObject(parameterName, x, targetSqlType, scale); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void setObject(final String parameterName, final Object x, final SQLType targetSqlType) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setObject(parameterName, x, targetSqlType); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void setObject(final String parameterName, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setObject(parameterName, x, targetSqlType, scaleOrLength); } catch (final SQLException e) { handleException(e); } } @Override public void setRowId(final String parameterName, final RowId value) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setRowId(parameterName, value); } catch (final SQLException e) { handleException(e); } } @Override public void setShort(final String parameterName, final short x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setShort(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setSQLXML(final String parameterName, final SQLXML value) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setSQLXML(parameterName, value); } catch (final SQLException e) { handleException(e); } } @Override public void setString(final String parameterName, final String x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setString(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setTime(final String parameterName, final Time x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setTime(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setTime(final String parameterName, final Time x, final Calendar cal) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setTime(parameterName, x, cal); } catch (final SQLException e) { handleException(e); } } @Override public void setTimestamp(final String parameterName, final Timestamp x) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setTimestamp(parameterName, x); } catch (final SQLException e) { handleException(e); } } @Override public void setTimestamp(final String parameterName, final Timestamp x, final Calendar cal) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setTimestamp(parameterName, x, cal); } catch (final SQLException e) { handleException(e); } } @Override public void setURL(final String parameterName, final URL val) throws SQLException { checkOpen(); try { getDelegateCallableStatement().setURL(parameterName, val); } catch (final SQLException e) { handleException(e); } } @Override public boolean wasNull() throws SQLException { checkOpen(); try { return getDelegateCallableStatement().wasNull(); } catch (final SQLException e) { handleException(e); return false; } } } DelegatingConnection.java000066400000000000000000001032631447311732500333060ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.ClientInfoStatus; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; import org.apache.commons.dbcp2.managed.ManagedConnection; /** * A base delegating implementation of {@link Connection}. *

* All of the methods from the {@link Connection} interface simply check to see that the {@link Connection} is active, * and call the corresponding method on the "delegate" provided in my constructor. *

*

* Extends AbandonedTrace to implement Connection tracking and logging of code which created the Connection. Tracking * the Connection ensures that the AbandonedObjectPool can close this connection and recycle it if its pool of * connections is nearing exhaustion and this connection's last usage is older than the removeAbandonedTimeout. *

* * @param * the Connection type * * @since 2.0 */ public class DelegatingConnection extends AbandonedTrace implements Connection { private static final Map EMPTY_FAILED_PROPERTIES = Collections .emptyMap(); /** My delegate {@link Connection}. */ private volatile C connection; private volatile boolean closed; private boolean cacheState = true; private Boolean cachedAutoCommit; private Boolean cachedReadOnly; private String cachedCatalog; private String cachedSchema; private Duration defaultQueryTimeoutDuration; /** * Creates a wrapper for the Connection which traces this Connection in the AbandonedObjectPool. * * @param connection the {@link Connection} to delegate all calls to, may be null (see {@link ManagedConnection}). */ public DelegatingConnection(final C connection) { this.connection = connection; } @Override public void abort(final Executor executor) throws SQLException { try { Jdbc41Bridge.abort(connection, executor); } catch (final SQLException e) { handleException(e); } } protected void activate() { closed = false; setLastUsed(); if (connection instanceof DelegatingConnection) { ((DelegatingConnection) connection).activate(); } } protected void checkOpen() throws SQLException { if (closed) { if (null != connection) { String label; try { label = connection.toString(); } catch (final Exception e) { // leave label empty label = ""; } throw new SQLException("Connection " + label + " is closed."); } throw new SQLException("Connection is null."); } } /** * Clears the cached state. Call when you know that the underlying connection may have been accessed * directly. */ public void clearCachedState() { cachedAutoCommit = null; cachedReadOnly = null; cachedSchema = null; cachedCatalog = null; if (connection instanceof DelegatingConnection) { ((DelegatingConnection) connection).clearCachedState(); } } @Override public void clearWarnings() throws SQLException { checkOpen(); try { connection.clearWarnings(); } catch (final SQLException e) { handleException(e); } } /** * Closes the underlying connection, and close any Statements that were not explicitly closed. Sub-classes that * override this method must: *
    *
  1. Call {@link #passivate()}
  2. *
  3. Call close (or the equivalent appropriate action) on the wrapped connection
  4. *
  5. Set {@code closed} to {@code false}
  6. *
*/ @Override public void close() throws SQLException { if (!closed) { closeInternal(); } } protected final void closeInternal() throws SQLException { try { passivate(); } finally { if (connection != null) { boolean connectionIsClosed; try { connectionIsClosed = connection.isClosed(); } catch (final SQLException e) { // not sure what the state is, so assume the connection is open. connectionIsClosed = false; } try { // DBCP-512: Avoid exceptions when closing a connection in multi-threaded use case. // Avoid closing again, which should be a no-op, but some drivers like H2 throw an exception when // closing from multiple threads. if (!connectionIsClosed) { connection.close(); } } finally { closed = true; } } else { closed = true; } } } @Override public void commit() throws SQLException { checkOpen(); try { connection.commit(); } catch (final SQLException e) { handleException(e); } } @Override public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { checkOpen(); try { return connection.createArrayOf(typeName, elements); } catch (final SQLException e) { handleException(e); return null; } } @Override public Blob createBlob() throws SQLException { checkOpen(); try { return connection.createBlob(); } catch (final SQLException e) { handleException(e); return null; } } @Override public Clob createClob() throws SQLException { checkOpen(); try { return connection.createClob(); } catch (final SQLException e) { handleException(e); return null; } } @Override public NClob createNClob() throws SQLException { checkOpen(); try { return connection.createNClob(); } catch (final SQLException e) { handleException(e); return null; } } @Override public SQLXML createSQLXML() throws SQLException { checkOpen(); try { return connection.createSQLXML(); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public Statement createStatement() throws SQLException { checkOpen(); try { return init(new DelegatingStatement(this, connection.createStatement())); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); try { return init(new DelegatingStatement(this, connection.createStatement(resultSetType, resultSetConcurrency))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public Statement createStatement(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); try { return init(new DelegatingStatement(this, connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability))); } catch (final SQLException e) { handleException(e); return null; } } @Override public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { checkOpen(); try { return connection.createStruct(typeName, attributes); } catch (final SQLException e) { handleException(e); return null; } } @Override public boolean getAutoCommit() throws SQLException { checkOpen(); if (cacheState && cachedAutoCommit != null) { return cachedAutoCommit; } try { cachedAutoCommit = connection.getAutoCommit(); return cachedAutoCommit; } catch (final SQLException e) { handleException(e); return false; } } /** * Returns the state caching flag. * * @return the state caching flag */ public boolean getCacheState() { return cacheState; } @Override public String getCatalog() throws SQLException { checkOpen(); if (cacheState && cachedCatalog != null) { return cachedCatalog; } try { cachedCatalog = connection.getCatalog(); return cachedCatalog; } catch (final SQLException e) { handleException(e); return null; } } @Override public Properties getClientInfo() throws SQLException { checkOpen(); try { return connection.getClientInfo(); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getClientInfo(final String name) throws SQLException { checkOpen(); try { return connection.getClientInfo(name); } catch (final SQLException e) { handleException(e); return null; } } /** * Gets the default query timeout that will be used for {@link Statement}s created from this connection. * {@code null} means that the driver default will be used. * * @return query timeout limit in seconds; zero means there is no limit. * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}. */ @Deprecated public Integer getDefaultQueryTimeout() { return defaultQueryTimeoutDuration == null ? null : (int) defaultQueryTimeoutDuration.getSeconds(); } /** * Gets the default query timeout that will be used for {@link Statement}s created from this connection. * {@code null} means that the driver default will be used. * * @return query timeout limit; zero means there is no limit. * @since 2.10.0 */ public Duration getDefaultQueryTimeoutDuration() { return defaultQueryTimeoutDuration; } /** * Returns my underlying {@link Connection}. * * @return my underlying {@link Connection}. */ public C getDelegate() { return getDelegateInternal(); } /** * Gets the delegate connection. * * @return the delegate connection. */ protected final C getDelegateInternal() { return connection; } @Override public int getHoldability() throws SQLException { checkOpen(); try { return connection.getHoldability(); } catch (final SQLException e) { handleException(e); return 0; } } /** * If my underlying {@link Connection} is not a {@code DelegatingConnection}, returns it, otherwise recursively * invokes this method on my delegate. *

* Hence this method will return the first delegate that is not a {@code DelegatingConnection}, or {@code null} when * no non-{@code DelegatingConnection} delegate can be found by traversing this chain. *

*

* This method is useful when you may have nested {@code DelegatingConnection}s, and you want to make sure to obtain * a "genuine" {@link Connection}. *

* * @return innermost delegate. */ public Connection getInnermostDelegate() { return getInnermostDelegateInternal(); } /** * Although this method is public, it is part of the internal API and should not be used by clients. The signature * of this method may change at any time including in ways that break backwards compatibility. * * @return innermost delegate. */ @SuppressWarnings("resource") public final Connection getInnermostDelegateInternal() { Connection conn = connection; while (conn instanceof DelegatingConnection) { conn = ((DelegatingConnection) conn).getDelegateInternal(); if (this == conn) { return null; } } return conn; } @Override public DatabaseMetaData getMetaData() throws SQLException { checkOpen(); try { return new DelegatingDatabaseMetaData(this, connection.getMetaData()); } catch (final SQLException e) { handleException(e); return null; } } @Override public int getNetworkTimeout() throws SQLException { checkOpen(); try { return Jdbc41Bridge.getNetworkTimeout(connection); } catch (final SQLException e) { handleException(e); return 0; } } @Override public String getSchema() throws SQLException { checkOpen(); if (cacheState && cachedSchema != null) { return cachedSchema; } try { cachedSchema = Jdbc41Bridge.getSchema(connection); return cachedSchema; } catch (final SQLException e) { handleException(e); return null; } } @Override public int getTransactionIsolation() throws SQLException { checkOpen(); try { return connection.getTransactionIsolation(); } catch (final SQLException e) { handleException(e); return -1; } } @Override public Map> getTypeMap() throws SQLException { checkOpen(); try { return connection.getTypeMap(); } catch (final SQLException e) { handleException(e); return null; } } @Override public SQLWarning getWarnings() throws SQLException { checkOpen(); try { return connection.getWarnings(); } catch (final SQLException e) { handleException(e); return null; } } /** * Handles the given exception by throwing it. * * @param e the exception to throw. * @throws SQLException the exception to throw. */ protected void handleException(final SQLException e) throws SQLException { throw e; } /** * Handles the given {@code SQLException}. * * @param The throwable type. * @param e The SQLException * @return the given {@code SQLException} * @since 2.7.0 */ protected T handleExceptionNoThrow(final T e) { return e; } /** * Initializes the given statement with this connection's settings. * * @param The DelegatingStatement type. * @param delegatingStatement The DelegatingStatement to initialize. * @return The given DelegatingStatement. * @throws SQLException if a database access error occurs, this method is called on a closed Statement. */ private T init(final T delegatingStatement) throws SQLException { if (defaultQueryTimeoutDuration != null && defaultQueryTimeoutDuration.getSeconds() != delegatingStatement.getQueryTimeout()) { delegatingStatement.setQueryTimeout((int) defaultQueryTimeoutDuration.getSeconds()); } return delegatingStatement; } /** * Compares innermost delegate to the given connection. * * @param c * connection to compare innermost delegate with * @return true if innermost delegate equals {@code c} */ @SuppressWarnings("resource") public boolean innermostDelegateEquals(final Connection c) { final Connection innerCon = getInnermostDelegateInternal(); if (innerCon == null) { return c == null; } return innerCon.equals(c); } @Override public boolean isClosed() throws SQLException { return closed || connection == null || connection.isClosed(); } protected boolean isClosedInternal() { return closed; } @Override public boolean isReadOnly() throws SQLException { checkOpen(); if (cacheState && cachedReadOnly != null) { return cachedReadOnly; } try { cachedReadOnly = connection.isReadOnly(); return cachedReadOnly; } catch (final SQLException e) { handleException(e); return false; } } /** * Tests if the connection has not been closed and is still valid. * * @param timeout The duration to wait for the database operation used to validate the connection to complete. * @return See {@link Connection#isValid(int)}. * @throws SQLException See {@link Connection#isValid(int)}. * @see Connection#isValid(int) * @since 2.10.0 */ public boolean isValid(final Duration timeout) throws SQLException { if (isClosed()) { return false; } try { return connection.isValid((int) timeout.getSeconds()); } catch (final SQLException e) { handleException(e); return false; } } /** * @deprecated Use {@link #isValid(Duration)}. */ @Override @Deprecated public boolean isValid(final int timeoutSeconds) throws SQLException { return isValid(Duration.ofSeconds(timeoutSeconds)); } @Override public boolean isWrapperFor(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return true; } if (iface.isAssignableFrom(connection.getClass())) { return true; } return connection.isWrapperFor(iface); } @Override public String nativeSQL(final String sql) throws SQLException { checkOpen(); try { return connection.nativeSQL(sql); } catch (final SQLException e) { handleException(e); return null; } } protected void passivate() throws SQLException { // The JDBC specification requires that a Connection close any open // Statements when it is closed. // DBCP-288. Not all the traced objects will be statements final List traceList = getTrace(); if (!Utils.isEmpty(traceList)) { final List thrownList = new ArrayList<>(); traceList.forEach(trace -> trace.close(thrownList::add)); clearTrace(); if (!thrownList.isEmpty()) { throw new SQLExceptionList(thrownList); } } setLastUsed(Instant.EPOCH); } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public CallableStatement prepareCall(final String sql) throws SQLException { checkOpen(); try { return init(new DelegatingCallableStatement(this, connection.prepareCall(sql))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); try { return init(new DelegatingCallableStatement(this, connection.prepareCall(sql, resultSetType, resultSetConcurrency))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); try { return init(new DelegatingCallableStatement(this, connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public PreparedStatement prepareStatement(final String sql) throws SQLException { checkOpen(); try { return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); try { return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, autoGeneratedKeys))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); try { return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, resultSetType, resultSetConcurrency))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); try { return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { checkOpen(); try { return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, columnIndexes))); } catch (final SQLException e) { handleException(e); return null; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { checkOpen(); try { return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, columnNames))); } catch (final SQLException e) { handleException(e); return null; } } @Override public void releaseSavepoint(final Savepoint savepoint) throws SQLException { checkOpen(); try { connection.releaseSavepoint(savepoint); } catch (final SQLException e) { handleException(e); } } @Override public void rollback() throws SQLException { checkOpen(); try { connection.rollback(); } catch (final SQLException e) { handleException(e); } } @Override public void rollback(final Savepoint savepoint) throws SQLException { checkOpen(); try { connection.rollback(savepoint); } catch (final SQLException e) { handleException(e); } } @Override public void setAutoCommit(final boolean autoCommit) throws SQLException { checkOpen(); try { connection.setAutoCommit(autoCommit); if (cacheState) { cachedAutoCommit = connection.getAutoCommit(); } } catch (final SQLException e) { cachedAutoCommit = null; handleException(e); } } /** * Sets the state caching flag. * * @param cacheState * The new value for the state caching flag */ public void setCacheState(final boolean cacheState) { this.cacheState = cacheState; } @Override public void setCatalog(final String catalog) throws SQLException { checkOpen(); try { connection.setCatalog(catalog); if (cacheState) { cachedCatalog = connection.getCatalog(); } } catch (final SQLException e) { cachedCatalog = null; handleException(e); } } @Override public void setClientInfo(final Properties properties) throws SQLClientInfoException { try { checkOpen(); connection.setClientInfo(properties); } catch (final SQLClientInfoException e) { throw e; } catch (final SQLException e) { throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e); } } @Override public void setClientInfo(final String name, final String value) throws SQLClientInfoException { try { checkOpen(); connection.setClientInfo(name, value); } catch (final SQLClientInfoException e) { throw e; } catch (final SQLException e) { throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e); } } protected void setClosedInternal(final boolean closed) { this.closed = closed; } /** * Sets the default query timeout that will be used for {@link Statement}s created from this connection. * {@code null} means that the driver default will be used. * * @param defaultQueryTimeoutDuration * the new query timeout limit Duration; zero means there is no limit. * @since 2.10.0 */ public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) { this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration; } /** * Sets the default query timeout that will be used for {@link Statement}s created from this connection. * {@code null} means that the driver default will be used. * * @param defaultQueryTimeoutSeconds * the new query timeout limit in seconds; zero means there is no limit. * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}. */ @Deprecated public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds); } /** * Sets my delegate. * * @param connection * my delegate, may be null. */ public void setDelegate(final C connection) { this.connection = connection; } @Override public void setHoldability(final int holdability) throws SQLException { checkOpen(); try { connection.setHoldability(holdability); } catch (final SQLException e) { handleException(e); } } @Override public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { checkOpen(); try { Jdbc41Bridge.setNetworkTimeout(connection, executor, milliseconds); } catch (final SQLException e) { handleException(e); } } @Override public void setReadOnly(final boolean readOnly) throws SQLException { checkOpen(); try { connection.setReadOnly(readOnly); if (cacheState) { cachedReadOnly = connection.isReadOnly(); } } catch (final SQLException e) { cachedReadOnly = null; handleException(e); } } @Override public Savepoint setSavepoint() throws SQLException { checkOpen(); try { return connection.setSavepoint(); } catch (final SQLException e) { handleException(e); return null; } } @Override public Savepoint setSavepoint(final String name) throws SQLException { checkOpen(); try { return connection.setSavepoint(name); } catch (final SQLException e) { handleException(e); return null; } } @Override public void setSchema(final String schema) throws SQLException { checkOpen(); try { Jdbc41Bridge.setSchema(connection, schema); if (cacheState) { cachedSchema = connection.getSchema(); } } catch (final SQLException e) { cachedSchema = null; handleException(e); } } @Override public void setTransactionIsolation(final int level) throws SQLException { checkOpen(); try { connection.setTransactionIsolation(level); } catch (final SQLException e) { handleException(e); } } @Override public void setTypeMap(final Map> map) throws SQLException { checkOpen(); try { connection.setTypeMap(map); } catch (final SQLException e) { handleException(e); } } /** * Returns a string representation of the metadata associated with the innermost delegate connection. */ @SuppressWarnings("resource") @Override public synchronized String toString() { String str = null; final Connection conn = this.getInnermostDelegateInternal(); if (conn != null) { try { if (conn.isClosed()) { str = "connection is closed"; } else { final StringBuilder sb = new StringBuilder(); sb.append(hashCode()); final DatabaseMetaData meta = conn.getMetaData(); if (meta != null) { sb.append(", URL="); sb.append(meta.getURL()); sb.append(", "); sb.append(meta.getDriverName()); str = sb.toString(); } } } catch (final SQLException ignored) { // Ignore } } return str != null ? str : super.toString(); } @Override public T unwrap(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return iface.cast(this); } if (iface.isAssignableFrom(connection.getClass())) { return iface.cast(connection); } return connection.unwrap(iface); } } DelegatingDatabaseMetaData.java000066400000000000000000001614531447311732500343210ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.RowIdLifetime; import java.sql.SQLException; /** *

* A base delegating implementation of {@link DatabaseMetaData}. *

*

* Methods that create {@link ResultSet} objects are wrapped to create {@link DelegatingResultSet} objects and the * remaining methods simply call the corresponding method on the "delegate" provided in the constructor. *

* * @since 2.0 */ public class DelegatingDatabaseMetaData implements DatabaseMetaData { /** My delegate {@link DatabaseMetaData} */ private final DatabaseMetaData databaseMetaData; /** The connection that created me. **/ private final DelegatingConnection connection; /** * Constructs a new instance for the given delegating connection and database meta data. * * @param connection * the delegating connection * @param databaseMetaData * the database meta data */ public DelegatingDatabaseMetaData(final DelegatingConnection connection, final DatabaseMetaData databaseMetaData) { this.connection = connection; this.databaseMetaData = databaseMetaData; } @Override public boolean allProceduresAreCallable() throws SQLException { try { return databaseMetaData.allProceduresAreCallable(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean allTablesAreSelectable() throws SQLException { try { return databaseMetaData.allTablesAreSelectable(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean autoCommitFailureClosesAllResultSets() throws SQLException { try { return databaseMetaData.autoCommitFailureClosesAllResultSets(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean dataDefinitionCausesTransactionCommit() throws SQLException { try { return databaseMetaData.dataDefinitionCausesTransactionCommit(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean dataDefinitionIgnoredInTransactions() throws SQLException { try { return databaseMetaData.dataDefinitionIgnoredInTransactions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean deletesAreDetected(final int type) throws SQLException { try { return databaseMetaData.deletesAreDetected(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { try { return databaseMetaData.doesMaxRowSizeIncludeBlobs(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean generatedKeyAlwaysReturned() throws SQLException { connection.checkOpen(); try { return Jdbc41Bridge.generatedKeyAlwaysReturned(databaseMetaData); } catch (final SQLException e) { handleException(e); return false; } } @Override public ResultSet getAttributes(final String catalog, final String schemaPattern, final String typeNamePattern, final String attributeNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getAttributes(catalog, schemaPattern, typeNamePattern, attributeNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getBestRowIdentifier(final String catalog, final String schema, final String table, final int scope, final boolean nullable) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getBestRowIdentifier(catalog, schema, table, scope, nullable)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getCatalogs() throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getCatalogs()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getCatalogSeparator() throws SQLException { try { return databaseMetaData.getCatalogSeparator(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getCatalogTerm() throws SQLException { try { return databaseMetaData.getCatalogTerm(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getClientInfoProperties() throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getClientInfoProperties()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getColumnPrivileges(final String catalog, final String schema, final String table, final String columnNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getColumnPrivileges(catalog, schema, table, columnNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getColumns(final String catalog, final String schemaPattern, final String tableNamePattern, final String columnNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public Connection getConnection() throws SQLException { return connection; } @Override public ResultSet getCrossReference(final String parentCatalog, final String parentSchema, final String parentTable, final String foreignCatalog, final String foreignSchema, final String foreignTable) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getCrossReference(parentCatalog, parentSchema, parentTable, foreignCatalog, foreignSchema, foreignTable)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public int getDatabaseMajorVersion() throws SQLException { try { return databaseMetaData.getDatabaseMajorVersion(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getDatabaseMinorVersion() throws SQLException { try { return databaseMetaData.getDatabaseMinorVersion(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public String getDatabaseProductName() throws SQLException { try { return databaseMetaData.getDatabaseProductName(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getDatabaseProductVersion() throws SQLException { try { return databaseMetaData.getDatabaseProductVersion(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public int getDefaultTransactionIsolation() throws SQLException { try { return databaseMetaData.getDefaultTransactionIsolation(); } catch (final SQLException e) { handleException(e); return 0; } } /** * Gets the underlying database meta data. * * @return The underlying database meta data. */ public DatabaseMetaData getDelegate() { return databaseMetaData; } @Override public int getDriverMajorVersion() { return databaseMetaData.getDriverMajorVersion(); } @Override public int getDriverMinorVersion() { return databaseMetaData.getDriverMinorVersion(); } @Override public String getDriverName() throws SQLException { try { return databaseMetaData.getDriverName(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getDriverVersion() throws SQLException { try { return databaseMetaData.getDriverVersion(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getExportedKeys(final String catalog, final String schema, final String table) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getExportedKeys(catalog, schema, table)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getExtraNameCharacters() throws SQLException { try { return databaseMetaData.getExtraNameCharacters(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getFunctionColumns(final String catalog, final String schemaPattern, final String functionNamePattern, final String columnNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getFunctionColumns(catalog, schemaPattern, functionNamePattern, columnNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getFunctions(final String catalog, final String schemaPattern, final String functionNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getFunctions(catalog, schemaPattern, functionNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getIdentifierQuoteString() throws SQLException { try { return databaseMetaData.getIdentifierQuoteString(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getImportedKeys(final String catalog, final String schema, final String table) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getImportedKeys(catalog, schema, table)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getIndexInfo(final String catalog, final String schema, final String table, final boolean unique, final boolean approximate) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getIndexInfo(catalog, schema, table, unique, approximate)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } /** * If my underlying {@link ResultSet} is not a {@code DelegatingResultSet}, returns it, otherwise recursively * invokes this method on my delegate. *

* Hence this method will return the first delegate that is not a {@code DelegatingResultSet}, or {@code null} when * no non-{@code DelegatingResultSet} delegate can be found by traversing this chain. *

*

* This method is useful when you may have nested {@code DelegatingResultSet}s, and you want to make sure to obtain * a "genuine" {@link ResultSet}. *

* * @return the innermost database meta data. */ public DatabaseMetaData getInnermostDelegate() { DatabaseMetaData m = databaseMetaData; while (m instanceof DelegatingDatabaseMetaData) { m = ((DelegatingDatabaseMetaData) m).getDelegate(); if (this == m) { return null; } } return m; } @Override public int getJDBCMajorVersion() throws SQLException { try { return databaseMetaData.getJDBCMajorVersion(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getJDBCMinorVersion() throws SQLException { try { return databaseMetaData.getJDBCMinorVersion(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxBinaryLiteralLength() throws SQLException { try { return databaseMetaData.getMaxBinaryLiteralLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxCatalogNameLength() throws SQLException { try { return databaseMetaData.getMaxCatalogNameLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxCharLiteralLength() throws SQLException { try { return databaseMetaData.getMaxCharLiteralLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxColumnNameLength() throws SQLException { try { return databaseMetaData.getMaxColumnNameLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxColumnsInGroupBy() throws SQLException { try { return databaseMetaData.getMaxColumnsInGroupBy(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxColumnsInIndex() throws SQLException { try { return databaseMetaData.getMaxColumnsInIndex(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxColumnsInOrderBy() throws SQLException { try { return databaseMetaData.getMaxColumnsInOrderBy(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxColumnsInSelect() throws SQLException { try { return databaseMetaData.getMaxColumnsInSelect(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxColumnsInTable() throws SQLException { try { return databaseMetaData.getMaxColumnsInTable(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxConnections() throws SQLException { try { return databaseMetaData.getMaxConnections(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxCursorNameLength() throws SQLException { try { return databaseMetaData.getMaxCursorNameLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxIndexLength() throws SQLException { try { return databaseMetaData.getMaxIndexLength(); } catch (final SQLException e) { handleException(e); return 0; } } /** * @since 2.5.0 */ @Override public long getMaxLogicalLobSize() throws SQLException { try { return databaseMetaData.getMaxLogicalLobSize(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxProcedureNameLength() throws SQLException { try { return databaseMetaData.getMaxProcedureNameLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxRowSize() throws SQLException { try { return databaseMetaData.getMaxRowSize(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxSchemaNameLength() throws SQLException { try { return databaseMetaData.getMaxSchemaNameLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxStatementLength() throws SQLException { try { return databaseMetaData.getMaxStatementLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxStatements() throws SQLException { try { return databaseMetaData.getMaxStatements(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxTableNameLength() throws SQLException { try { return databaseMetaData.getMaxTableNameLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxTablesInSelect() throws SQLException { try { return databaseMetaData.getMaxTablesInSelect(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxUserNameLength() throws SQLException { try { return databaseMetaData.getMaxUserNameLength(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public String getNumericFunctions() throws SQLException { try { return databaseMetaData.getNumericFunctions(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getPrimaryKeys(final String catalog, final String schema, final String table) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getPrimaryKeys(catalog, schema, table)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getProcedureColumns(final String catalog, final String schemaPattern, final String procedureNamePattern, final String columnNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getProcedureColumns(catalog, schemaPattern, procedureNamePattern, columnNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getProcedures(final String catalog, final String schemaPattern, final String procedureNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getProcedures(catalog, schemaPattern, procedureNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getProcedureTerm() throws SQLException { try { return databaseMetaData.getProcedureTerm(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getPseudoColumns(final String catalog, final String schemaPattern, final String tableNamePattern, final String columnNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, Jdbc41Bridge.getPseudoColumns(databaseMetaData, catalog, schemaPattern, tableNamePattern, columnNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public int getResultSetHoldability() throws SQLException { try { return databaseMetaData.getResultSetHoldability(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public RowIdLifetime getRowIdLifetime() throws SQLException { try { return databaseMetaData.getRowIdLifetime(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getSchemas() throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getSchemas()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getSchemas(final String catalog, final String schemaPattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getSchemas(catalog, schemaPattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getSchemaTerm() throws SQLException { try { return databaseMetaData.getSchemaTerm(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getSearchStringEscape() throws SQLException { try { return databaseMetaData.getSearchStringEscape(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getSQLKeywords() throws SQLException { try { return databaseMetaData.getSQLKeywords(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public int getSQLStateType() throws SQLException { try { return databaseMetaData.getSQLStateType(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public String getStringFunctions() throws SQLException { try { return databaseMetaData.getStringFunctions(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getSuperTables(final String catalog, final String schemaPattern, final String tableNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getSuperTables(catalog, schemaPattern, tableNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getSuperTypes(final String catalog, final String schemaPattern, final String typeNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getSuperTypes(catalog, schemaPattern, typeNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getSystemFunctions() throws SQLException { try { return databaseMetaData.getSystemFunctions(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getTablePrivileges(final String catalog, final String schemaPattern, final String tableNamePattern) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getTablePrivileges(catalog, schemaPattern, tableNamePattern)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getTables(final String catalog, final String schemaPattern, final String tableNamePattern, final String[] types) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getTables(catalog, schemaPattern, tableNamePattern, types)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getTableTypes() throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getTableTypes()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getTimeDateFunctions() throws SQLException { try { return databaseMetaData.getTimeDateFunctions(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getTypeInfo() throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getTypeInfo()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getUDTs(final String catalog, final String schemaPattern, final String typeNamePattern, final int[] types) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getUDTs(catalog, schemaPattern, typeNamePattern, types)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getURL() throws SQLException { try { return databaseMetaData.getURL(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public String getUserName() throws SQLException { try { return databaseMetaData.getUserName(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public ResultSet getVersionColumns(final String catalog, final String schema, final String table) throws SQLException { connection.checkOpen(); try { return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getVersionColumns(catalog, schema, table)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } protected void handleException(final SQLException e) throws SQLException { if (connection == null) { throw e; } connection.handleException(e); } @Override public boolean insertsAreDetected(final int type) throws SQLException { try { return databaseMetaData.insertsAreDetected(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isCatalogAtStart() throws SQLException { try { return databaseMetaData.isCatalogAtStart(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isReadOnly() throws SQLException { try { return databaseMetaData.isReadOnly(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isWrapperFor(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return true; } if (iface.isAssignableFrom(databaseMetaData.getClass())) { return true; } return databaseMetaData.isWrapperFor(iface); } @Override public boolean locatorsUpdateCopy() throws SQLException { try { return databaseMetaData.locatorsUpdateCopy(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean nullPlusNonNullIsNull() throws SQLException { try { return databaseMetaData.nullPlusNonNullIsNull(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean nullsAreSortedAtEnd() throws SQLException { try { return databaseMetaData.nullsAreSortedAtEnd(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean nullsAreSortedAtStart() throws SQLException { try { return databaseMetaData.nullsAreSortedAtStart(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean nullsAreSortedHigh() throws SQLException { try { return databaseMetaData.nullsAreSortedHigh(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean nullsAreSortedLow() throws SQLException { try { return databaseMetaData.nullsAreSortedLow(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean othersDeletesAreVisible(final int type) throws SQLException { try { return databaseMetaData.othersDeletesAreVisible(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean othersInsertsAreVisible(final int type) throws SQLException { try { return databaseMetaData.othersInsertsAreVisible(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean othersUpdatesAreVisible(final int type) throws SQLException { try { return databaseMetaData.othersUpdatesAreVisible(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean ownDeletesAreVisible(final int type) throws SQLException { try { return databaseMetaData.ownDeletesAreVisible(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean ownInsertsAreVisible(final int type) throws SQLException { try { return databaseMetaData.ownInsertsAreVisible(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean ownUpdatesAreVisible(final int type) throws SQLException { try { return databaseMetaData.ownUpdatesAreVisible(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean storesLowerCaseIdentifiers() throws SQLException { try { return databaseMetaData.storesLowerCaseIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { try { return databaseMetaData.storesLowerCaseQuotedIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean storesMixedCaseIdentifiers() throws SQLException { try { return databaseMetaData.storesMixedCaseIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { try { return databaseMetaData.storesMixedCaseQuotedIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean storesUpperCaseIdentifiers() throws SQLException { try { return databaseMetaData.storesUpperCaseIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { try { return databaseMetaData.storesUpperCaseQuotedIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsAlterTableWithAddColumn() throws SQLException { try { return databaseMetaData.supportsAlterTableWithAddColumn(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsAlterTableWithDropColumn() throws SQLException { try { return databaseMetaData.supportsAlterTableWithDropColumn(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsANSI92EntryLevelSQL() throws SQLException { try { return databaseMetaData.supportsANSI92EntryLevelSQL(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsANSI92FullSQL() throws SQLException { try { return databaseMetaData.supportsANSI92FullSQL(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsANSI92IntermediateSQL() throws SQLException { try { return databaseMetaData.supportsANSI92IntermediateSQL(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsBatchUpdates() throws SQLException { try { return databaseMetaData.supportsBatchUpdates(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsCatalogsInDataManipulation() throws SQLException { try { return databaseMetaData.supportsCatalogsInDataManipulation(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsCatalogsInIndexDefinitions() throws SQLException { try { return databaseMetaData.supportsCatalogsInIndexDefinitions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { try { return databaseMetaData.supportsCatalogsInPrivilegeDefinitions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsCatalogsInProcedureCalls() throws SQLException { try { return databaseMetaData.supportsCatalogsInProcedureCalls(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsCatalogsInTableDefinitions() throws SQLException { try { return databaseMetaData.supportsCatalogsInTableDefinitions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsColumnAliasing() throws SQLException { try { return databaseMetaData.supportsColumnAliasing(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsConvert() throws SQLException { try { return databaseMetaData.supportsConvert(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsConvert(final int fromType, final int toType) throws SQLException { try { return databaseMetaData.supportsConvert(fromType, toType); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsCoreSQLGrammar() throws SQLException { try { return databaseMetaData.supportsCoreSQLGrammar(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsCorrelatedSubqueries() throws SQLException { try { return databaseMetaData.supportsCorrelatedSubqueries(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { try { return databaseMetaData.supportsDataDefinitionAndDataManipulationTransactions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsDataManipulationTransactionsOnly() throws SQLException { try { return databaseMetaData.supportsDataManipulationTransactionsOnly(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsDifferentTableCorrelationNames() throws SQLException { try { return databaseMetaData.supportsDifferentTableCorrelationNames(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsExpressionsInOrderBy() throws SQLException { try { return databaseMetaData.supportsExpressionsInOrderBy(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsExtendedSQLGrammar() throws SQLException { try { return databaseMetaData.supportsExtendedSQLGrammar(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsFullOuterJoins() throws SQLException { try { return databaseMetaData.supportsFullOuterJoins(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsGetGeneratedKeys() throws SQLException { try { return databaseMetaData.supportsGetGeneratedKeys(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsGroupBy() throws SQLException { try { return databaseMetaData.supportsGroupBy(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsGroupByBeyondSelect() throws SQLException { try { return databaseMetaData.supportsGroupByBeyondSelect(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsGroupByUnrelated() throws SQLException { try { return databaseMetaData.supportsGroupByUnrelated(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsIntegrityEnhancementFacility() throws SQLException { try { return databaseMetaData.supportsIntegrityEnhancementFacility(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsLikeEscapeClause() throws SQLException { try { return databaseMetaData.supportsLikeEscapeClause(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsLimitedOuterJoins() throws SQLException { try { return databaseMetaData.supportsLimitedOuterJoins(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsMinimumSQLGrammar() throws SQLException { try { return databaseMetaData.supportsMinimumSQLGrammar(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsMixedCaseIdentifiers() throws SQLException { try { return databaseMetaData.supportsMixedCaseIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { try { return databaseMetaData.supportsMixedCaseQuotedIdentifiers(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsMultipleOpenResults() throws SQLException { try { return databaseMetaData.supportsMultipleOpenResults(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsMultipleResultSets() throws SQLException { try { return databaseMetaData.supportsMultipleResultSets(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsMultipleTransactions() throws SQLException { try { return databaseMetaData.supportsMultipleTransactions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsNamedParameters() throws SQLException { try { return databaseMetaData.supportsNamedParameters(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsNonNullableColumns() throws SQLException { try { return databaseMetaData.supportsNonNullableColumns(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsOpenCursorsAcrossCommit() throws SQLException { try { return databaseMetaData.supportsOpenCursorsAcrossCommit(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsOpenCursorsAcrossRollback() throws SQLException { try { return databaseMetaData.supportsOpenCursorsAcrossRollback(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsOpenStatementsAcrossCommit() throws SQLException { try { return databaseMetaData.supportsOpenStatementsAcrossCommit(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsOpenStatementsAcrossRollback() throws SQLException { try { return databaseMetaData.supportsOpenStatementsAcrossRollback(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsOrderByUnrelated() throws SQLException { try { return databaseMetaData.supportsOrderByUnrelated(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsOuterJoins() throws SQLException { try { return databaseMetaData.supportsOuterJoins(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsPositionedDelete() throws SQLException { try { return databaseMetaData.supportsPositionedDelete(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsPositionedUpdate() throws SQLException { try { return databaseMetaData.supportsPositionedUpdate(); } catch (final SQLException e) { handleException(e); return false; } } /** * @since 2.5.0 */ @Override public boolean supportsRefCursors() throws SQLException { try { return databaseMetaData.supportsRefCursors(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsResultSetConcurrency(final int type, final int concurrency) throws SQLException { try { return databaseMetaData.supportsResultSetConcurrency(type, concurrency); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsResultSetHoldability(final int holdability) throws SQLException { try { return databaseMetaData.supportsResultSetHoldability(holdability); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsResultSetType(final int type) throws SQLException { try { return databaseMetaData.supportsResultSetType(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSavepoints() throws SQLException { try { return databaseMetaData.supportsSavepoints(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSchemasInDataManipulation() throws SQLException { try { return databaseMetaData.supportsSchemasInDataManipulation(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSchemasInIndexDefinitions() throws SQLException { try { return databaseMetaData.supportsSchemasInIndexDefinitions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { try { return databaseMetaData.supportsSchemasInPrivilegeDefinitions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSchemasInProcedureCalls() throws SQLException { try { return databaseMetaData.supportsSchemasInProcedureCalls(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSchemasInTableDefinitions() throws SQLException { try { return databaseMetaData.supportsSchemasInTableDefinitions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSelectForUpdate() throws SQLException { try { return databaseMetaData.supportsSelectForUpdate(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsStatementPooling() throws SQLException { try { return databaseMetaData.supportsStatementPooling(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { try { return databaseMetaData.supportsStoredFunctionsUsingCallSyntax(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsStoredProcedures() throws SQLException { try { return databaseMetaData.supportsStoredProcedures(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSubqueriesInComparisons() throws SQLException { try { return databaseMetaData.supportsSubqueriesInComparisons(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSubqueriesInExists() throws SQLException { try { return databaseMetaData.supportsSubqueriesInExists(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSubqueriesInIns() throws SQLException { try { return databaseMetaData.supportsSubqueriesInIns(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsSubqueriesInQuantifieds() throws SQLException { try { return databaseMetaData.supportsSubqueriesInQuantifieds(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsTableCorrelationNames() throws SQLException { try { return databaseMetaData.supportsTableCorrelationNames(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsTransactionIsolationLevel(final int level) throws SQLException { try { return databaseMetaData.supportsTransactionIsolationLevel(level); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsTransactions() throws SQLException { try { return databaseMetaData.supportsTransactions(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsUnion() throws SQLException { try { return databaseMetaData.supportsUnion(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean supportsUnionAll() throws SQLException { try { return databaseMetaData.supportsUnionAll(); } catch (final SQLException e) { handleException(e); return false; } } @Override public T unwrap(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return iface.cast(this); } if (iface.isAssignableFrom(databaseMetaData.getClass())) { return iface.cast(databaseMetaData); } return databaseMetaData.unwrap(iface); } @Override public boolean updatesAreDetected(final int type) throws SQLException { try { return databaseMetaData.updatesAreDetected(type); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean usesLocalFilePerTable() throws SQLException { try { return databaseMetaData.usesLocalFilePerTable(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean usesLocalFiles() throws SQLException { try { return databaseMetaData.usesLocalFiles(); } catch (final SQLException e) { handleException(e); return false; } } } DelegatingPreparedStatement.java000066400000000000000000000557741447311732500346530ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Date; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLType; import java.sql.SQLXML; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.List; /** * A base delegating implementation of {@link PreparedStatement}. *

* All of the methods from the {@link PreparedStatement} interface simply check to see that the * {@link PreparedStatement} is active, and call the corresponding method on the "delegate" provided in my constructor. *

* Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the * Statement ensures that the Connection which created it can close any open Statement's on Connection close. * * @since 2.0 */ public class DelegatingPreparedStatement extends DelegatingStatement implements PreparedStatement { /** * Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code * which created it. * * @param statement * the {@link PreparedStatement} to delegate all calls to. * @param connection * the {@link DelegatingConnection} that created this statement. */ public DelegatingPreparedStatement(final DelegatingConnection connection, final PreparedStatement statement) { super(connection, statement); } @Override public void addBatch() throws SQLException { checkOpen(); try { getDelegatePreparedStatement().addBatch(); } catch (final SQLException e) { handleException(e); } } @Override public void clearParameters() throws SQLException { checkOpen(); try { getDelegatePreparedStatement().clearParameters(); } catch (final SQLException e) { handleException(e); } } @Override public boolean execute() throws SQLException { checkOpen(); if (getConnectionInternal() != null) { getConnectionInternal().setLastUsed(); } try { return getDelegatePreparedStatement().execute(); } catch (final SQLException e) { handleException(e); return false; } } /** * @since 2.5.0 */ @Override public long executeLargeUpdate() throws SQLException { checkOpen(); try { return getDelegatePreparedStatement().executeLargeUpdate(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public ResultSet executeQuery() throws SQLException { checkOpen(); if (getConnectionInternal() != null) { getConnectionInternal().setLastUsed(); } try { return DelegatingResultSet.wrapResultSet(this, getDelegatePreparedStatement().executeQuery()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public int executeUpdate() throws SQLException { checkOpen(); if (getConnectionInternal() != null) { getConnectionInternal().setLastUsed(); } try { return getDelegatePreparedStatement().executeUpdate(); } catch (final SQLException e) { handleException(e); return 0; } } private PreparedStatement getDelegatePreparedStatement() { return (PreparedStatement) getDelegate(); } @Override public ResultSetMetaData getMetaData() throws SQLException { checkOpen(); try { return getDelegatePreparedStatement().getMetaData(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public java.sql.ParameterMetaData getParameterMetaData() throws SQLException { checkOpen(); try { return getDelegatePreparedStatement().getParameterMetaData(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public void setArray(final int i, final Array x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setArray(i, x); } catch (final SQLException e) { handleException(e); } } @Override public void setAsciiStream(final int parameterIndex, final InputStream inputStream) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setAsciiStream(parameterIndex, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void setAsciiStream(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBigDecimal(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setBinaryStream(final int parameterIndex, final InputStream inputStream) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBinaryStream(parameterIndex, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBinaryStream(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBlob(final int i, final Blob x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBlob(i, x); } catch (final SQLException e) { handleException(e); } } @Override public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBlob(parameterIndex, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void setBlob(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBlob(parameterIndex, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void setBoolean(final int parameterIndex, final boolean x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBoolean(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setByte(final int parameterIndex, final byte x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setByte(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setBytes(final int parameterIndex, final byte[] x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setBytes(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setCharacterStream(final int parameterIndex, final Reader reader, final int length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setCharacterStream(final int parameterIndex, final Reader reader, final long length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setClob(final int i, final Clob x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setClob(i, x); } catch (final SQLException e) { handleException(e); } } @Override public void setClob(final int parameterIndex, final Reader reader) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setClob(parameterIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setClob(parameterIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setDate(final int parameterIndex, final Date x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setDate(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setDate(parameterIndex, x, cal); } catch (final SQLException e) { handleException(e); } } @Override public void setDouble(final int parameterIndex, final double x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setDouble(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setFloat(final int parameterIndex, final float x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setFloat(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setInt(final int parameterIndex, final int x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setInt(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setLong(final int parameterIndex, final long x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setLong(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setNCharacterStream(final int parameterIndex, final Reader reader) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNCharacterStream(parameterIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setNCharacterStream(final int parameterIndex, final Reader value, final long length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNCharacterStream(parameterIndex, value, length); } catch (final SQLException e) { handleException(e); } } @Override public void setNClob(final int parameterIndex, final NClob value) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNClob(parameterIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void setNClob(final int parameterIndex, final Reader reader) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNClob(parameterIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNClob(parameterIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void setNString(final int parameterIndex, final String value) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNString(parameterIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void setNull(final int parameterIndex, final int sqlType) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNull(parameterIndex, sqlType); } catch (final SQLException e) { handleException(e); } } @Override public void setNull(final int paramIndex, final int sqlType, final String typeName) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setNull(paramIndex, sqlType, typeName); } catch (final SQLException e) { handleException(e); } } @Override public void setObject(final int parameterIndex, final Object x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setObject(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType); } catch (final SQLException e) { handleException(e); } } @Override public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scale); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scaleOrLength); } catch (final SQLException e) { handleException(e); } } @Override public void setRef(final int i, final Ref x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setRef(i, x); } catch (final SQLException e) { handleException(e); } } @Override public void setRowId(final int parameterIndex, final RowId value) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setRowId(parameterIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void setShort(final int parameterIndex, final short x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setShort(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setSQLXML(final int parameterIndex, final SQLXML value) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setSQLXML(parameterIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void setString(final int parameterIndex, final String x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setString(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setTime(final int parameterIndex, final Time x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setTime(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setTime(parameterIndex, x, cal); } catch (final SQLException e) { handleException(e); } } @Override public void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setTimestamp(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setTimestamp(parameterIndex, x, cal); } catch (final SQLException e) { handleException(e); } } /** @deprecated Use setAsciiStream(), setCharacterStream() or setNCharacterStream() */ @Deprecated @Override public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setUnicodeStream(parameterIndex, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void setURL(final int parameterIndex, final java.net.URL x) throws SQLException { checkOpen(); try { getDelegatePreparedStatement().setURL(parameterIndex, x); } catch (final SQLException e) { handleException(e); } } /** * Returns a String representation of this object. * * @return String */ @SuppressWarnings("resource") @Override public synchronized String toString() { final Statement statement = getDelegate(); return statement == null ? "NULL" : statement.toString(); } protected void prepareToReturn() throws SQLException { setClosedInternal(true); removeThisTrace(getConnectionInternal()); // The JDBC spec requires that a statement close any open // ResultSet's when it is closed. // FIXME The PreparedStatement we're wrapping should handle this for us. // See DBCP-10 for what could happen when ResultSets are closed twice. final List traceList = getTrace(); if (traceList != null) { final List thrownList = new ArrayList<>(); traceList.forEach(trace -> trace.close(thrownList::add)); clearTrace(); if (!thrownList.isEmpty()) { throw new SQLExceptionList(thrownList); } } super.passivate(); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/DelegatingResultSet.java000066400000000000000000001636651447311732500332340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; import java.sql.Date; import java.sql.NClob; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLType; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; import java.util.Map; /** * A base delegating implementation of {@link ResultSet}. *

* All of the methods from the {@link ResultSet} interface simply call the corresponding method on the "delegate" * provided in my constructor. *

*

* Extends AbandonedTrace to implement result set tracking and logging of code which created the ResultSet. Tracking the * ResultSet ensures that the Statement which created it can close any open ResultSet's on Statement close. *

* * @since 2.0 */ public final class DelegatingResultSet extends AbandonedTrace implements ResultSet { /** * Wraps the given result set in a delegate. * * @param connection * The Connection which created the ResultSet. * @param resultSet * The ResultSet to wrap. * @return a new delegate. */ public static ResultSet wrapResultSet(final Connection connection, final ResultSet resultSet) { if (null == resultSet) { return null; } return new DelegatingResultSet(connection, resultSet); } /** * Wraps the given result set in a delegate. * * @param statement * The Statement which created the ResultSet. * @param resultSet * The ResultSet to wrap. * @return a new delegate. */ public static ResultSet wrapResultSet(final Statement statement, final ResultSet resultSet) { if (null == resultSet) { return null; } return new DelegatingResultSet(statement, resultSet); } /** My delegate. **/ private final ResultSet resultSet; /** The Statement that created me, if any. **/ private Statement statement; /** The Connection that created me, if any. **/ private Connection connection; /** * Creates a wrapper for the ResultSet which traces this ResultSet to the Connection which created it (via, for * example DatabaseMetadata), and the code which created it. *

* Private to ensure all construction is {@link #wrapResultSet(Connection, ResultSet)} *

* * @param connection * Connection which created this ResultSet * @param resultSet * ResultSet to wrap */ private DelegatingResultSet(final Connection connection, final ResultSet resultSet) { super((AbandonedTrace) connection); this.connection = connection; this.resultSet = resultSet; } /** * Creates a wrapper for the ResultSet which traces this ResultSet to the Statement which created it and the code * which created it. *

* Private to ensure all construction is {@link #wrapResultSet(Statement, ResultSet)} *

* * @param statement * The Statement which created the ResultSet. * @param resultSet * The ResultSet to wrap. */ private DelegatingResultSet(final Statement statement, final ResultSet resultSet) { super((AbandonedTrace) statement); this.statement = statement; this.resultSet = resultSet; } @Override public boolean absolute(final int row) throws SQLException { try { return resultSet.absolute(row); } catch (final SQLException e) { handleException(e); return false; } } @Override public void afterLast() throws SQLException { try { resultSet.afterLast(); } catch (final SQLException e) { handleException(e); } } @Override public void beforeFirst() throws SQLException { try { resultSet.beforeFirst(); } catch (final SQLException e) { handleException(e); } } @Override public void cancelRowUpdates() throws SQLException { try { resultSet.cancelRowUpdates(); } catch (final SQLException e) { handleException(e); } } @Override public void clearWarnings() throws SQLException { try { resultSet.clearWarnings(); } catch (final SQLException e) { handleException(e); } } /** * Wrapper for close of ResultSet which removes this result set from being traced then calls close on the original * ResultSet. */ @Override public void close() throws SQLException { try { if (statement != null) { removeThisTrace(statement); statement = null; } if (connection != null) { removeThisTrace(connection); connection = null; } resultSet.close(); } catch (final SQLException e) { handleException(e); } } @Override public void deleteRow() throws SQLException { try { resultSet.deleteRow(); } catch (final SQLException e) { handleException(e); } } @Override public int findColumn(final String columnName) throws SQLException { try { return resultSet.findColumn(columnName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public boolean first() throws SQLException { try { return resultSet.first(); } catch (final SQLException e) { handleException(e); return false; } } @Override public Array getArray(final int i) throws SQLException { try { return resultSet.getArray(i); } catch (final SQLException e) { handleException(e); return null; } } @Override public Array getArray(final String colName) throws SQLException { try { return resultSet.getArray(colName); } catch (final SQLException e) { handleException(e); return null; } } @Override public InputStream getAsciiStream(final int columnIndex) throws SQLException { try { return resultSet.getAsciiStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public InputStream getAsciiStream(final String columnName) throws SQLException { try { return resultSet.getAsciiStream(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public BigDecimal getBigDecimal(final int columnIndex) throws SQLException { try { return resultSet.getBigDecimal(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } /** @deprecated Use {@link #getBigDecimal(int)} */ @Deprecated @Override public BigDecimal getBigDecimal(final int columnIndex, final int scale) throws SQLException { try { return resultSet.getBigDecimal(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public BigDecimal getBigDecimal(final String columnName) throws SQLException { try { return resultSet.getBigDecimal(columnName); } catch (final SQLException e) { handleException(e); return null; } } /** @deprecated Use {@link #getBigDecimal(String)} */ @Deprecated @Override public BigDecimal getBigDecimal(final String columnName, final int scale) throws SQLException { try { return resultSet.getBigDecimal(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public InputStream getBinaryStream(final int columnIndex) throws SQLException { try { return resultSet.getBinaryStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public InputStream getBinaryStream(final String columnName) throws SQLException { try { return resultSet.getBinaryStream(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Blob getBlob(final int i) throws SQLException { try { return resultSet.getBlob(i); } catch (final SQLException e) { handleException(e); return null; } } @Override public Blob getBlob(final String colName) throws SQLException { try { return resultSet.getBlob(colName); } catch (final SQLException e) { handleException(e); return null; } } @Override public boolean getBoolean(final int columnIndex) throws SQLException { try { return resultSet.getBoolean(columnIndex); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean getBoolean(final String columnName) throws SQLException { try { return resultSet.getBoolean(columnName); } catch (final SQLException e) { handleException(e); return false; } } @Override public byte getByte(final int columnIndex) throws SQLException { try { return resultSet.getByte(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public byte getByte(final String columnName) throws SQLException { try { return resultSet.getByte(columnName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public byte[] getBytes(final int columnIndex) throws SQLException { try { return resultSet.getBytes(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public byte[] getBytes(final String columnName) throws SQLException { try { return resultSet.getBytes(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Reader getCharacterStream(final int columnIndex) throws SQLException { try { return resultSet.getCharacterStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Reader getCharacterStream(final String columnName) throws SQLException { try { return resultSet.getCharacterStream(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Clob getClob(final int i) throws SQLException { try { return resultSet.getClob(i); } catch (final SQLException e) { handleException(e); return null; } } @Override public Clob getClob(final String colName) throws SQLException { try { return resultSet.getClob(colName); } catch (final SQLException e) { handleException(e); return null; } } @Override public int getConcurrency() throws SQLException { try { return resultSet.getConcurrency(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public String getCursorName() throws SQLException { try { return resultSet.getCursorName(); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final int columnIndex) throws SQLException { try { return resultSet.getDate(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final int columnIndex, final Calendar cal) throws SQLException { try { return resultSet.getDate(columnIndex, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final String columnName) throws SQLException { try { return resultSet.getDate(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Date getDate(final String columnName, final Calendar cal) throws SQLException { try { return resultSet.getDate(columnName, cal); } catch (final SQLException e) { handleException(e); return null; } } /** * Gets my delegate. * * @return my delegate. */ public ResultSet getDelegate() { return resultSet; } @Override public double getDouble(final int columnIndex) throws SQLException { try { return resultSet.getDouble(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public double getDouble(final String columnName) throws SQLException { try { return resultSet.getDouble(columnName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getFetchDirection() throws SQLException { try { return resultSet.getFetchDirection(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getFetchSize() throws SQLException { try { return resultSet.getFetchSize(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public float getFloat(final int columnIndex) throws SQLException { try { return resultSet.getFloat(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public float getFloat(final String columnName) throws SQLException { try { return resultSet.getFloat(columnName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getHoldability() throws SQLException { try { return resultSet.getHoldability(); } catch (final SQLException e) { handleException(e); return 0; } } /** * If my underlying {@link ResultSet} is not a {@code DelegatingResultSet}, returns it, otherwise recursively * invokes this method on my delegate. *

* Hence this method will return the first delegate that is not a {@code DelegatingResultSet}, or {@code null} when * no non-{@code DelegatingResultSet} delegate can be found by traversing this chain. *

*

* This method is useful when you may have nested {@code DelegatingResultSet}s, and you want to make sure to obtain * a "genuine" {@link ResultSet}. *

* * @return the innermost delegate. */ @SuppressWarnings("resource") public ResultSet getInnermostDelegate() { ResultSet r = resultSet; while (r instanceof DelegatingResultSet) { r = ((DelegatingResultSet) r).getDelegate(); if (this == r) { return null; } } return r; } @Override public int getInt(final int columnIndex) throws SQLException { try { return resultSet.getInt(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getInt(final String columnName) throws SQLException { try { return resultSet.getInt(columnName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public long getLong(final int columnIndex) throws SQLException { try { return resultSet.getLong(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public long getLong(final String columnName) throws SQLException { try { return resultSet.getLong(columnName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public ResultSetMetaData getMetaData() throws SQLException { try { return resultSet.getMetaData(); } catch (final SQLException e) { handleException(e); return null; } } @Override public Reader getNCharacterStream(final int columnIndex) throws SQLException { try { return resultSet.getNCharacterStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Reader getNCharacterStream(final String columnLabel) throws SQLException { try { return resultSet.getNCharacterStream(columnLabel); } catch (final SQLException e) { handleException(e); return null; } } @Override public NClob getNClob(final int columnIndex) throws SQLException { try { return resultSet.getNClob(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public NClob getNClob(final String columnLabel) throws SQLException { try { return resultSet.getNClob(columnLabel); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getNString(final int columnIndex) throws SQLException { try { return resultSet.getNString(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getNString(final String columnLabel) throws SQLException { try { return resultSet.getNString(columnLabel); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final int columnIndex) throws SQLException { try { return resultSet.getObject(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public T getObject(final int columnIndex, final Class type) throws SQLException { try { return Jdbc41Bridge.getObject(resultSet, columnIndex, type); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final int i, final Map> map) throws SQLException { try { return resultSet.getObject(i, map); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final String columnName) throws SQLException { try { return resultSet.getObject(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public T getObject(final String columnLabel, final Class type) throws SQLException { try { return Jdbc41Bridge.getObject(resultSet, columnLabel, type); } catch (final SQLException e) { handleException(e); return null; } } @Override public Object getObject(final String colName, final Map> map) throws SQLException { try { return resultSet.getObject(colName, map); } catch (final SQLException e) { handleException(e); return null; } } @Override public Ref getRef(final int i) throws SQLException { try { return resultSet.getRef(i); } catch (final SQLException e) { handleException(e); return null; } } @Override public Ref getRef(final String colName) throws SQLException { try { return resultSet.getRef(colName); } catch (final SQLException e) { handleException(e); return null; } } @Override public int getRow() throws SQLException { try { return resultSet.getRow(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public RowId getRowId(final int columnIndex) throws SQLException { try { return resultSet.getRowId(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public RowId getRowId(final String columnLabel) throws SQLException { try { return resultSet.getRowId(columnLabel); } catch (final SQLException e) { handleException(e); return null; } } @Override public short getShort(final int columnIndex) throws SQLException { try { return resultSet.getShort(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } } @Override public short getShort(final String columnName) throws SQLException { try { return resultSet.getShort(columnName); } catch (final SQLException e) { handleException(e); return 0; } } @Override public SQLXML getSQLXML(final int columnIndex) throws SQLException { try { return resultSet.getSQLXML(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public SQLXML getSQLXML(final String columnLabel) throws SQLException { try { return resultSet.getSQLXML(columnLabel); } catch (final SQLException e) { handleException(e); return null; } } @Override public Statement getStatement() throws SQLException { return statement; } @Override public String getString(final int columnIndex) throws SQLException { try { return resultSet.getString(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public String getString(final String columnName) throws SQLException { try { return resultSet.getString(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final int columnIndex) throws SQLException { try { return resultSet.getTime(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final int columnIndex, final Calendar cal) throws SQLException { try { return resultSet.getTime(columnIndex, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final String columnName) throws SQLException { try { return resultSet.getTime(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Time getTime(final String columnName, final Calendar cal) throws SQLException { try { return resultSet.getTime(columnName, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final int columnIndex) throws SQLException { try { return resultSet.getTimestamp(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final int columnIndex, final Calendar cal) throws SQLException { try { return resultSet.getTimestamp(columnIndex, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final String columnName) throws SQLException { try { return resultSet.getTimestamp(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public Timestamp getTimestamp(final String columnName, final Calendar cal) throws SQLException { try { return resultSet.getTimestamp(columnName, cal); } catch (final SQLException e) { handleException(e); return null; } } @Override public int getType() throws SQLException { try { return resultSet.getType(); } catch (final SQLException e) { handleException(e); return 0; } } /** @deprecated Use {@link #getCharacterStream(int)} */ @Deprecated @Override public InputStream getUnicodeStream(final int columnIndex) throws SQLException { try { return resultSet.getUnicodeStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } /** @deprecated Use {@link #getCharacterStream(String)} */ @Deprecated @Override public InputStream getUnicodeStream(final String columnName) throws SQLException { try { return resultSet.getUnicodeStream(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public java.net.URL getURL(final int columnIndex) throws SQLException { try { return resultSet.getURL(columnIndex); } catch (final SQLException e) { handleException(e); return null; } } @Override public java.net.URL getURL(final String columnName) throws SQLException { try { return resultSet.getURL(columnName); } catch (final SQLException e) { handleException(e); return null; } } @Override public SQLWarning getWarnings() throws SQLException { try { return resultSet.getWarnings(); } catch (final SQLException e) { handleException(e); return null; } } protected void handleException(final SQLException e) throws SQLException { if (statement instanceof DelegatingStatement) { ((DelegatingStatement) statement).handleException(e); } else if (connection instanceof DelegatingConnection) { ((DelegatingConnection) connection).handleException(e); } else { throw e; } } @Override public void insertRow() throws SQLException { try { resultSet.insertRow(); } catch (final SQLException e) { handleException(e); } } @Override public boolean isAfterLast() throws SQLException { try { return resultSet.isAfterLast(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isBeforeFirst() throws SQLException { try { return resultSet.isBeforeFirst(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isClosed() throws SQLException { try { return resultSet.isClosed(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isFirst() throws SQLException { try { return resultSet.isFirst(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isLast() throws SQLException { try { return resultSet.isLast(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isWrapperFor(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return true; } if (iface.isAssignableFrom(resultSet.getClass())) { return true; } return resultSet.isWrapperFor(iface); } @Override public boolean last() throws SQLException { try { return resultSet.last(); } catch (final SQLException e) { handleException(e); return false; } } @Override public void moveToCurrentRow() throws SQLException { try { resultSet.moveToCurrentRow(); } catch (final SQLException e) { handleException(e); } } @Override public void moveToInsertRow() throws SQLException { try { resultSet.moveToInsertRow(); } catch (final SQLException e) { handleException(e); } } @Override public boolean next() throws SQLException { try { return resultSet.next(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean previous() throws SQLException { try { return resultSet.previous(); } catch (final SQLException e) { handleException(e); return false; } } @Override public void refreshRow() throws SQLException { try { resultSet.refreshRow(); } catch (final SQLException e) { handleException(e); } } @Override public boolean relative(final int rows) throws SQLException { try { return resultSet.relative(rows); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean rowDeleted() throws SQLException { try { return resultSet.rowDeleted(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean rowInserted() throws SQLException { try { return resultSet.rowInserted(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean rowUpdated() throws SQLException { try { return resultSet.rowUpdated(); } catch (final SQLException e) { handleException(e); return false; } } @Override public void setFetchDirection(final int direction) throws SQLException { try { resultSet.setFetchDirection(direction); } catch (final SQLException e) { handleException(e); } } @Override public void setFetchSize(final int rows) throws SQLException { try { resultSet.setFetchSize(rows); } catch (final SQLException e) { handleException(e); } } @Override public synchronized String toString() { return super.toString() + "[resultSet=" + resultSet + ", statement=" + statement + ", connection=" + connection + "]"; } @Override public T unwrap(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return iface.cast(this); } if (iface.isAssignableFrom(resultSet.getClass())) { return iface.cast(resultSet); } return resultSet.unwrap(iface); } @Override public void updateArray(final int columnIndex, final Array x) throws SQLException { try { resultSet.updateArray(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateArray(final String columnName, final Array x) throws SQLException { try { resultSet.updateArray(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateAsciiStream(final int columnIndex, final InputStream inputStream) throws SQLException { try { resultSet.updateAsciiStream(columnIndex, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void updateAsciiStream(final int columnIndex, final InputStream x, final int length) throws SQLException { try { resultSet.updateAsciiStream(columnIndex, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateAsciiStream(final int columnIndex, final InputStream inputStream, final long length) throws SQLException { try { resultSet.updateAsciiStream(columnIndex, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateAsciiStream(final String columnLabel, final InputStream inputStream) throws SQLException { try { resultSet.updateAsciiStream(columnLabel, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void updateAsciiStream(final String columnName, final InputStream x, final int length) throws SQLException { try { resultSet.updateAsciiStream(columnName, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateAsciiStream(final String columnLabel, final InputStream inputStream, final long length) throws SQLException { try { resultSet.updateAsciiStream(columnLabel, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateBigDecimal(final int columnIndex, final BigDecimal x) throws SQLException { try { resultSet.updateBigDecimal(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateBigDecimal(final String columnName, final BigDecimal x) throws SQLException { try { resultSet.updateBigDecimal(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateBinaryStream(final int columnIndex, final InputStream inputStream) throws SQLException { try { resultSet.updateBinaryStream(columnIndex, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void updateBinaryStream(final int columnIndex, final InputStream x, final int length) throws SQLException { try { resultSet.updateBinaryStream(columnIndex, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateBinaryStream(final int columnIndex, final InputStream inputStream, final long length) throws SQLException { try { resultSet.updateBinaryStream(columnIndex, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateBinaryStream(final String columnLabel, final InputStream inputStream) throws SQLException { try { resultSet.updateBinaryStream(columnLabel, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void updateBinaryStream(final String columnName, final InputStream x, final int length) throws SQLException { try { resultSet.updateBinaryStream(columnName, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateBinaryStream(final String columnLabel, final InputStream inputStream, final long length) throws SQLException { try { resultSet.updateBinaryStream(columnLabel, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateBlob(final int columnIndex, final Blob x) throws SQLException { try { resultSet.updateBlob(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateBlob(final int columnIndex, final InputStream inputStream) throws SQLException { try { resultSet.updateBlob(columnIndex, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void updateBlob(final int columnIndex, final InputStream inputStream, final long length) throws SQLException { try { resultSet.updateBlob(columnIndex, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateBlob(final String columnName, final Blob x) throws SQLException { try { resultSet.updateBlob(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateBlob(final String columnLabel, final InputStream inputStream) throws SQLException { try { resultSet.updateBlob(columnLabel, inputStream); } catch (final SQLException e) { handleException(e); } } @Override public void updateBlob(final String columnLabel, final InputStream inputStream, final long length) throws SQLException { try { resultSet.updateBlob(columnLabel, inputStream, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateBoolean(final int columnIndex, final boolean x) throws SQLException { try { resultSet.updateBoolean(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateBoolean(final String columnName, final boolean x) throws SQLException { try { resultSet.updateBoolean(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateByte(final int columnIndex, final byte x) throws SQLException { try { resultSet.updateByte(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateByte(final String columnName, final byte x) throws SQLException { try { resultSet.updateByte(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateBytes(final int columnIndex, final byte[] x) throws SQLException { try { resultSet.updateBytes(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateBytes(final String columnName, final byte[] x) throws SQLException { try { resultSet.updateBytes(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateCharacterStream(final int columnIndex, final Reader reader) throws SQLException { try { resultSet.updateCharacterStream(columnIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateCharacterStream(final int columnIndex, final Reader x, final int length) throws SQLException { try { resultSet.updateCharacterStream(columnIndex, x, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateCharacterStream(final int columnIndex, final Reader reader, final long length) throws SQLException { try { resultSet.updateCharacterStream(columnIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateCharacterStream(final String columnLabel, final Reader reader) throws SQLException { try { resultSet.updateCharacterStream(columnLabel, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateCharacterStream(final String columnName, final Reader reader, final int length) throws SQLException { try { resultSet.updateCharacterStream(columnName, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateCharacterStream(final String columnLabel, final Reader reader, final long length) throws SQLException { try { resultSet.updateCharacterStream(columnLabel, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateClob(final int columnIndex, final Clob x) throws SQLException { try { resultSet.updateClob(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateClob(final int columnIndex, final Reader reader) throws SQLException { try { resultSet.updateClob(columnIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateClob(final int columnIndex, final Reader reader, final long length) throws SQLException { try { resultSet.updateClob(columnIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateClob(final String columnName, final Clob x) throws SQLException { try { resultSet.updateClob(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateClob(final String columnLabel, final Reader reader) throws SQLException { try { resultSet.updateClob(columnLabel, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateClob(final String columnLabel, final Reader reader, final long length) throws SQLException { try { resultSet.updateClob(columnLabel, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateDate(final int columnIndex, final Date x) throws SQLException { try { resultSet.updateDate(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateDate(final String columnName, final Date x) throws SQLException { try { resultSet.updateDate(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateDouble(final int columnIndex, final double x) throws SQLException { try { resultSet.updateDouble(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateDouble(final String columnName, final double x) throws SQLException { try { resultSet.updateDouble(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateFloat(final int columnIndex, final float x) throws SQLException { try { resultSet.updateFloat(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateFloat(final String columnName, final float x) throws SQLException { try { resultSet.updateFloat(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateInt(final int columnIndex, final int x) throws SQLException { try { resultSet.updateInt(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateInt(final String columnName, final int x) throws SQLException { try { resultSet.updateInt(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateLong(final int columnIndex, final long x) throws SQLException { try { resultSet.updateLong(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateLong(final String columnName, final long x) throws SQLException { try { resultSet.updateLong(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateNCharacterStream(final int columnIndex, final Reader reader) throws SQLException { try { resultSet.updateNCharacterStream(columnIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateNCharacterStream(final int columnIndex, final Reader reader, final long length) throws SQLException { try { resultSet.updateNCharacterStream(columnIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateNCharacterStream(final String columnLabel, final Reader reader) throws SQLException { try { resultSet.updateNCharacterStream(columnLabel, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateNCharacterStream(final String columnLabel, final Reader reader, final long length) throws SQLException { try { resultSet.updateNCharacterStream(columnLabel, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateNClob(final int columnIndex, final NClob value) throws SQLException { try { resultSet.updateNClob(columnIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateNClob(final int columnIndex, final Reader reader) throws SQLException { try { resultSet.updateNClob(columnIndex, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateNClob(final int columnIndex, final Reader reader, final long length) throws SQLException { try { resultSet.updateNClob(columnIndex, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateNClob(final String columnLabel, final NClob value) throws SQLException { try { resultSet.updateNClob(columnLabel, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateNClob(final String columnLabel, final Reader reader) throws SQLException { try { resultSet.updateNClob(columnLabel, reader); } catch (final SQLException e) { handleException(e); } } @Override public void updateNClob(final String columnLabel, final Reader reader, final long length) throws SQLException { try { resultSet.updateNClob(columnLabel, reader, length); } catch (final SQLException e) { handleException(e); } } @Override public void updateNString(final int columnIndex, final String value) throws SQLException { try { resultSet.updateNString(columnIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateNString(final String columnLabel, final String value) throws SQLException { try { resultSet.updateNString(columnLabel, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateNull(final int columnIndex) throws SQLException { try { resultSet.updateNull(columnIndex); } catch (final SQLException e) { handleException(e); } } @Override public void updateNull(final String columnName) throws SQLException { try { resultSet.updateNull(columnName); } catch (final SQLException e) { handleException(e); } } @Override public void updateObject(final int columnIndex, final Object x) throws SQLException { try { resultSet.updateObject(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateObject(final int columnIndex, final Object x, final int scale) throws SQLException { try { resultSet.updateObject(columnIndex, x); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void updateObject(final int columnIndex, final Object x, final SQLType targetSqlType) throws SQLException { try { resultSet.updateObject(columnIndex, x, targetSqlType); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void updateObject(final int columnIndex, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { try { resultSet.updateObject(columnIndex, x, targetSqlType, scaleOrLength); } catch (final SQLException e) { handleException(e); } } @Override public void updateObject(final String columnName, final Object x) throws SQLException { try { resultSet.updateObject(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateObject(final String columnName, final Object x, final int scale) throws SQLException { try { resultSet.updateObject(columnName, x); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void updateObject(final String columnLabel, final Object x, final SQLType targetSqlType) throws SQLException { try { resultSet.updateObject(columnLabel, x, targetSqlType); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void updateObject(final String columnLabel, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { try { resultSet.updateObject(columnLabel, x, targetSqlType, scaleOrLength); } catch (final SQLException e) { handleException(e); } } @Override public void updateRef(final int columnIndex, final Ref x) throws SQLException { try { resultSet.updateRef(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateRef(final String columnName, final Ref x) throws SQLException { try { resultSet.updateRef(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateRow() throws SQLException { try { resultSet.updateRow(); } catch (final SQLException e) { handleException(e); } } @Override public void updateRowId(final int columnIndex, final RowId value) throws SQLException { try { resultSet.updateRowId(columnIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateRowId(final String columnLabel, final RowId value) throws SQLException { try { resultSet.updateRowId(columnLabel, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateShort(final int columnIndex, final short x) throws SQLException { try { resultSet.updateShort(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateShort(final String columnName, final short x) throws SQLException { try { resultSet.updateShort(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateSQLXML(final int columnIndex, final SQLXML value) throws SQLException { try { resultSet.updateSQLXML(columnIndex, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateSQLXML(final String columnLabel, final SQLXML value) throws SQLException { try { resultSet.updateSQLXML(columnLabel, value); } catch (final SQLException e) { handleException(e); } } @Override public void updateString(final int columnIndex, final String x) throws SQLException { try { resultSet.updateString(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateString(final String columnName, final String x) throws SQLException { try { resultSet.updateString(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateTime(final int columnIndex, final Time x) throws SQLException { try { resultSet.updateTime(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateTime(final String columnName, final Time x) throws SQLException { try { resultSet.updateTime(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateTimestamp(final int columnIndex, final Timestamp x) throws SQLException { try { resultSet.updateTimestamp(columnIndex, x); } catch (final SQLException e) { handleException(e); } } @Override public void updateTimestamp(final String columnName, final Timestamp x) throws SQLException { try { resultSet.updateTimestamp(columnName, x); } catch (final SQLException e) { handleException(e); } } @Override public boolean wasNull() throws SQLException { try { return resultSet.wasNull(); } catch (final SQLException e) { handleException(e); return false; } } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/DelegatingStatement.java000066400000000000000000000563771447311732500332470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; import java.util.ArrayList; import java.util.List; /** * A base delegating implementation of {@link Statement}. *

* All of the methods from the {@link Statement} interface simply check to see that the {@link Statement} is active, and * call the corresponding method on the "delegate" provided in my constructor. *

* Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the * Statement ensures that the Connection which created it can close any open Statement's on Connection close. * * @since 2.0 */ public class DelegatingStatement extends AbandonedTrace implements Statement { /** My delegate. */ private Statement statement; /** The connection that created me. **/ private DelegatingConnection connection; private boolean closed; /** * Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code * which created it. * * @param statement * the {@link Statement} to delegate all calls to. * @param connection * the {@link DelegatingConnection} that created this statement. */ public DelegatingStatement(final DelegatingConnection connection, final Statement statement) { super(connection); this.statement = statement; this.connection = connection; } /** * * @throws SQLException * thrown by the delegating statement. * @since 2.4.0 made public, was protected in 2.3.0. */ public void activate() throws SQLException { if (statement instanceof DelegatingStatement) { ((DelegatingStatement) statement).activate(); } } @Override public void addBatch(final String sql) throws SQLException { checkOpen(); try { statement.addBatch(sql); } catch (final SQLException e) { handleException(e); } } @Override public void cancel() throws SQLException { checkOpen(); try { statement.cancel(); } catch (final SQLException e) { handleException(e); } } protected void checkOpen() throws SQLException { if (isClosed()) { throw new SQLException(this.getClass().getName() + " with address: \"" + this.toString() + "\" is closed."); } } @Override public void clearBatch() throws SQLException { checkOpen(); try { statement.clearBatch(); } catch (final SQLException e) { handleException(e); } } @Override public void clearWarnings() throws SQLException { checkOpen(); try { statement.clearWarnings(); } catch (final SQLException e) { handleException(e); } } /** * Close this DelegatingStatement, and close any ResultSets that were not explicitly closed. */ @Override public void close() throws SQLException { if (isClosed()) { return; } final List thrownList = new ArrayList<>(); try { if (connection != null) { connection.removeTrace(this); connection = null; } // The JDBC spec requires that a statement close any open // ResultSet's when it is closed. // FIXME The PreparedStatement we're wrapping should handle this for us. // See bug 17301 for what could happen when ResultSets are closed twice. final List traceList = getTrace(); if (traceList != null) { traceList.forEach(trace -> trace.close(e -> { if (connection != null) { // Does not rethrow e. connection.handleExceptionNoThrow(e); } thrownList.add(e); })); clearTrace(); } Utils.close(statement, e -> { if (connection != null) { // Does not rethrow e. connection.handleExceptionNoThrow(e); } thrownList.add(e); }); } finally { closed = true; statement = null; if (!thrownList.isEmpty()) { throw new SQLExceptionList(thrownList); } } } @Override public void closeOnCompletion() throws SQLException { checkOpen(); try { Jdbc41Bridge.closeOnCompletion(statement); } catch (final SQLException e) { handleException(e); } } @Override public boolean execute(final String sql) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.execute(sql); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.execute(sql, autoGeneratedKeys); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean execute(final String sql, final int[] columnIndexes) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.execute(sql, columnIndexes); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean execute(final String sql, final String[] columnNames) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.execute(sql, columnNames); } catch (final SQLException e) { handleException(e); return false; } } @Override public int[] executeBatch() throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeBatch(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } /** * @since 2.5.0 */ @Override public long[] executeLargeBatch() throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeLargeBatch(); } catch (final SQLException e) { handleException(e); return null; } } /** * @since 2.5.0 */ @Override public long executeLargeUpdate(final String sql) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeLargeUpdate(sql); } catch (final SQLException e) { handleException(e); return 0; } } /** * @since 2.5.0 */ @Override public long executeLargeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeLargeUpdate(sql, autoGeneratedKeys); } catch (final SQLException e) { handleException(e); return 0; } } /** * @since 2.5.0 */ @Override public long executeLargeUpdate(final String sql, final int[] columnIndexes) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeLargeUpdate(sql, columnIndexes); } catch (final SQLException e) { handleException(e); return 0; } } /** * @since 2.5.0 */ @Override public long executeLargeUpdate(final String sql, final String[] columnNames) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeLargeUpdate(sql, columnNames); } catch (final SQLException e) { handleException(e); return 0; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public ResultSet executeQuery(final String sql) throws SQLException { checkOpen(); setLastUsedInParent(); try { return DelegatingResultSet.wrapResultSet(this, statement.executeQuery(sql)); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public int executeUpdate(final String sql) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeUpdate(sql); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeUpdate(sql, autoGeneratedKeys); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeUpdate(sql, columnIndexes); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int executeUpdate(final String sql, final String[] columnNames) throws SQLException { checkOpen(); setLastUsedInParent(); try { return statement.executeUpdate(sql, columnNames); } catch (final SQLException e) { handleException(e); return 0; } } @Override protected void finalize() throws Throwable { // This is required because of statement pooling. The poolable // statements will always be strongly held by the statement pool. If the // delegating statements that wrap the poolable statement are not // strongly held they will be garbage collected but at that point the // poolable statements need to be returned to the pool else there will // be a leak of statements from the pool. Closing this statement will // close all the wrapped statements and return any poolable statements // to the pool. close(); super.finalize(); } @Override public Connection getConnection() throws SQLException { checkOpen(); return getConnectionInternal(); // return the delegating connection that created this } protected DelegatingConnection getConnectionInternal() { return connection; } /** * Returns my underlying {@link Statement}. * * @return my underlying {@link Statement}. * @see #getInnermostDelegate */ public Statement getDelegate() { return statement; } @Override public int getFetchDirection() throws SQLException { checkOpen(); try { return statement.getFetchDirection(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getFetchSize() throws SQLException { checkOpen(); try { return statement.getFetchSize(); } catch (final SQLException e) { handleException(e); return 0; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public ResultSet getGeneratedKeys() throws SQLException { checkOpen(); try { return DelegatingResultSet.wrapResultSet(this, statement.getGeneratedKeys()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } /** * If my underlying {@link Statement} is not a {@code DelegatingStatement}, returns it, otherwise recursively * invokes this method on my delegate. *

* Hence this method will return the first delegate that is not a {@code DelegatingStatement} or {@code null} when * no non-{@code DelegatingStatement} delegate can be found by traversing this chain. *

*

* This method is useful when you may have nested {@code DelegatingStatement}s, and you want to make sure to obtain * a "genuine" {@link Statement}. *

* * @return The innermost delegate. * * @see #getDelegate */ @SuppressWarnings("resource") public Statement getInnermostDelegate() { Statement s = statement; while (s instanceof DelegatingStatement) { s = ((DelegatingStatement) s).getDelegate(); if (this == s) { return null; } } return s; } /** * @since 2.5.0 */ @Override public long getLargeMaxRows() throws SQLException { checkOpen(); try { return statement.getLargeMaxRows(); } catch (final SQLException e) { handleException(e); return 0; } } /** * @since 2.5.0 */ @Override public long getLargeUpdateCount() throws SQLException { checkOpen(); try { return statement.getLargeUpdateCount(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxFieldSize() throws SQLException { checkOpen(); try { return statement.getMaxFieldSize(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getMaxRows() throws SQLException { checkOpen(); try { return statement.getMaxRows(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public boolean getMoreResults() throws SQLException { checkOpen(); try { return statement.getMoreResults(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean getMoreResults(final int current) throws SQLException { checkOpen(); try { return statement.getMoreResults(current); } catch (final SQLException e) { handleException(e); return false; } } @Override public int getQueryTimeout() throws SQLException { checkOpen(); try { return statement.getQueryTimeout(); } catch (final SQLException e) { handleException(e); return 0; } } @SuppressWarnings("resource") // Caller is responsible for closing the resource. @Override public ResultSet getResultSet() throws SQLException { checkOpen(); try { return DelegatingResultSet.wrapResultSet(this, statement.getResultSet()); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } @Override public int getResultSetConcurrency() throws SQLException { checkOpen(); try { return statement.getResultSetConcurrency(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getResultSetHoldability() throws SQLException { checkOpen(); try { return statement.getResultSetHoldability(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getResultSetType() throws SQLException { checkOpen(); try { return statement.getResultSetType(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public int getUpdateCount() throws SQLException { checkOpen(); try { return statement.getUpdateCount(); } catch (final SQLException e) { handleException(e); return 0; } } @Override public SQLWarning getWarnings() throws SQLException { checkOpen(); try { return statement.getWarnings(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } } protected void handleException(final SQLException e) throws SQLException { if (connection == null) { throw e; } connection.handleException(e); } /* * Note: This method was protected prior to JDBC 4. */ @Override public boolean isClosed() throws SQLException { return closed; } protected boolean isClosedInternal() { return closed; } @Override public boolean isCloseOnCompletion() throws SQLException { checkOpen(); try { return Jdbc41Bridge.isCloseOnCompletion(statement); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isPoolable() throws SQLException { checkOpen(); try { return statement.isPoolable(); } catch (final SQLException e) { handleException(e); return false; } } @Override public boolean isWrapperFor(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return true; } if (iface.isAssignableFrom(statement.getClass())) { return true; } return statement.isWrapperFor(iface); } /** * * @throws SQLException * thrown by the delegating statement. * @since 2.4.0 made public, was protected in 2.3.0. */ public void passivate() throws SQLException { if (statement instanceof DelegatingStatement) { ((DelegatingStatement) statement).passivate(); } } protected void setClosedInternal(final boolean closed) { this.closed = closed; } @Override public void setCursorName(final String name) throws SQLException { checkOpen(); try { statement.setCursorName(name); } catch (final SQLException e) { handleException(e); } } /** * Sets my delegate. * * @param statement * my delegate. */ public void setDelegate(final Statement statement) { this.statement = statement; } @Override public void setEscapeProcessing(final boolean enable) throws SQLException { checkOpen(); try { statement.setEscapeProcessing(enable); } catch (final SQLException e) { handleException(e); } } @Override public void setFetchDirection(final int direction) throws SQLException { checkOpen(); try { statement.setFetchDirection(direction); } catch (final SQLException e) { handleException(e); } } @Override public void setFetchSize(final int rows) throws SQLException { checkOpen(); try { statement.setFetchSize(rows); } catch (final SQLException e) { handleException(e); } } /** * @since 2.5.0 */ @Override public void setLargeMaxRows(final long max) throws SQLException { checkOpen(); try { statement.setLargeMaxRows(max); } catch (final SQLException e) { handleException(e); } } private void setLastUsedInParent() { if (connection != null) { connection.setLastUsed(); } } @Override public void setMaxFieldSize(final int max) throws SQLException { checkOpen(); try { statement.setMaxFieldSize(max); } catch (final SQLException e) { handleException(e); } } @Override public void setMaxRows(final int max) throws SQLException { checkOpen(); try { statement.setMaxRows(max); } catch (final SQLException e) { handleException(e); } } @Override public void setPoolable(final boolean poolable) throws SQLException { checkOpen(); try { statement.setPoolable(poolable); } catch (final SQLException e) { handleException(e); } } @Override public void setQueryTimeout(final int seconds) throws SQLException { checkOpen(); try { statement.setQueryTimeout(seconds); } catch (final SQLException e) { handleException(e); } } /** * Returns a String representation of this object. * * @return String */ @Override public synchronized String toString() { return statement == null ? "NULL" : statement.toString(); } @Override public T unwrap(final Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return iface.cast(this); } if (iface.isAssignableFrom(statement.getClass())) { return iface.cast(statement); } return statement.unwrap(iface); } } DriverConnectionFactory.java000066400000000000000000000046351447311732500340310ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; import java.util.Properties; /** * A {@link Driver}-based implementation of {@link ConnectionFactory}. * * @since 2.0 */ public class DriverConnectionFactory implements ConnectionFactory { private final String connectionString; private final Driver driver; private final Properties properties; /** * Constructs a connection factory for a given Driver. * * @param driver The Driver. * @param connectString The connection string. * @param properties The connection properties. */ public DriverConnectionFactory(final Driver driver, final String connectString, final Properties properties) { this.driver = driver; this.connectionString = connectString; this.properties = properties; } @Override public Connection createConnection() throws SQLException { return driver.connect(connectionString, properties); } /** * @return The connection String. * @since 2.6.0 */ public String getConnectionString() { return connectionString; } /** * @return The Driver. * @since 2.6.0 */ public Driver getDriver() { return driver; } /** * @return The Properties. * @since 2.6.0 */ public Properties getProperties() { return properties; } @Override public String toString() { return this.getClass().getName() + " [" + driver + ";" + connectionString + ";" + Utils.cloneWithoutCredentials(properties) + "]"; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/DriverFactory.java000066400000000000000000000066671447311732500320770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; /* * Creates {@link Driver} instances. * * @since 2.7.0 */ final class DriverFactory { static Driver createDriver(final BasicDataSource basicDataSource) throws SQLException { // Load the JDBC driver class Driver driverToUse = basicDataSource.getDriver(); final String driverClassName = basicDataSource.getDriverClassName(); final ClassLoader driverClassLoader = basicDataSource.getDriverClassLoader(); final String url = basicDataSource.getUrl(); if (driverToUse == null) { Class driverFromCCL = null; if (driverClassName != null) { try { try { if (driverClassLoader == null) { driverFromCCL = Class.forName(driverClassName); } else { driverFromCCL = Class.forName(driverClassName, true, driverClassLoader); } } catch (final ClassNotFoundException cnfe) { driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName); } } catch (final Exception t) { final String message = "Cannot load JDBC driver class '" + driverClassName + "'"; basicDataSource.log(message, t); throw new SQLException(message, t); } } try { if (driverFromCCL == null) { driverToUse = DriverManager.getDriver(url); } else { // Usage of DriverManager is not possible, as it does not // respect the ContextClassLoader // N.B. This cast may cause ClassCastException which is // handled below driverToUse = (Driver) driverFromCCL.getConstructor().newInstance(); if (!driverToUse.acceptsURL(url)) { throw new SQLException("No suitable driver", "08001"); } } } catch (final Exception t) { final String message = "Cannot create JDBC driver of class '" + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'"; basicDataSource.log(message, t); throw new SQLException(message, t); } } return driverToUse; } } DriverManagerConnectionFactory.java000066400000000000000000000117451447311732500353240ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; /** * A {@link DriverManager}-based implementation of {@link ConnectionFactory}. * * @since 2.0 */ public class DriverManagerConnectionFactory implements ConnectionFactory { static { // Related to DBCP-212 // Driver manager does not sync loading of drivers that use the service // provider interface. This will cause issues is multi-threaded // environments. This hack makes sure the drivers are loaded before // DBCP tries to use them. DriverManager.getDrivers(); } private final String connectionUri; private final String userName; private final char[] userPassword; private final Properties properties; /** * Constructor for DriverManagerConnectionFactory. * * @param connectionUri * a database connection string of the form {@code jdbc:subprotocol:subname} * @since 2.2 */ public DriverManagerConnectionFactory(final String connectionUri) { this.connectionUri = connectionUri; this.properties = new Properties(); this.userName = null; this.userPassword = null; } /** * Constructor for DriverManagerConnectionFactory. * * @param connectionUri * a database connection string of the form {@code jdbc:subprotocol:subname} * @param properties * a list of arbitrary string tag/value pairs as connection arguments; normally at least a "user" and * "password" property should be included. */ public DriverManagerConnectionFactory(final String connectionUri, final Properties properties) { this.connectionUri = connectionUri; this.properties = properties; this.userName = null; this.userPassword = null; } /** * Constructor for DriverManagerConnectionFactory. * * @param connectionUri * a database connection string of the form {@code jdbc:subprotocol:subname} * @param userName * the database user * @param userPassword * the user's password */ public DriverManagerConnectionFactory(final String connectionUri, final String userName, final char[] userPassword) { this.connectionUri = connectionUri; this.userName = userName; this.userPassword = Utils.clone(userPassword); this.properties = null; } /** * Constructor for DriverManagerConnectionFactory. * * @param connectionUri * a database connection string of the form {@code jdbc:subprotocol:subname} * @param userName * the database user * @param userPassword * the user's password */ public DriverManagerConnectionFactory(final String connectionUri, final String userName, final String userPassword) { this.connectionUri = connectionUri; this.userName = userName; this.userPassword = Utils.toCharArray(userPassword); this.properties = null; } @Override public Connection createConnection() throws SQLException { if (null == properties) { if (userName == null && userPassword == null) { return DriverManager.getConnection(connectionUri); } return DriverManager.getConnection(connectionUri, userName, Utils.toString(userPassword)); } return DriverManager.getConnection(connectionUri, properties); } /** * @return The connection URI. * @since 2.6.0 */ public String getConnectionUri() { return connectionUri; } /** * @return The Properties. * @since 2.6.0 */ public Properties getProperties() { return properties; } /** * @return The user name. * @since 2.6.0 */ public String getUserName() { return userName; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/Jdbc41Bridge.java000066400000000000000000000462201447311732500314250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.Date; import java.sql.Ref; import java.sql.ResultSet; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLXML; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.util.concurrent.Executor; import java.util.logging.Logger; import javax.sql.CommonDataSource; /** * Defines bridge methods to JDBC 4.1 (Java 7) methods to allow call sites to operate safely (without * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 (Java 6). *

* There should be no need to this kind of code for JDBC 4.2 in Java 8 due to JDBC's use of default methods. *

*

* This should probably be moved or at least copied in some form to Apache Commons DbUtils. *

* * @since 2.6.0 */ public class Jdbc41Bridge { /** * Delegates to {@link Connection#abort(Executor)} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link Connection#abort(Executor)}, then call {@link Connection#close()}. *

* * @param connection * the receiver * @param executor * See {@link Connection#abort(Executor)}. * @throws SQLException * See {@link Connection#abort(Executor)}. * @see Connection#abort(Executor) */ public static void abort(final Connection connection, final Executor executor) throws SQLException { try { connection.abort(executor); } catch (final AbstractMethodError e) { connection.close(); } } /** * Delegates to {@link Statement#closeOnCompletion()} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection * is closed to then throw an SQLException. *

* * @param statement * See {@link Statement#closeOnCompletion()} * @throws SQLException * See {@link Statement#closeOnCompletion()} * @see Statement#closeOnCompletion() */ public static void closeOnCompletion(final Statement statement) throws SQLException { try { statement.closeOnCompletion(); } catch (final AbstractMethodError e) { if (statement.isClosed()) { throw new SQLException("Statement closed"); } } } /** * Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a * {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link DatabaseMetaData#generatedKeyAlwaysReturned()}, then return false. *

* * @param databaseMetaData * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} * @return See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} * @throws SQLException * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} * @see DatabaseMetaData#generatedKeyAlwaysReturned() */ public static boolean generatedKeyAlwaysReturned(final DatabaseMetaData databaseMetaData) throws SQLException { try { return databaseMetaData.generatedKeyAlwaysReturned(); } catch (final AbstractMethodError e) { // do nothing return false; } } /** * Delegates to {@link Connection#getNetworkTimeout()} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link Connection#getNetworkTimeout()}, then return 0. *

* * @param connection * the receiver * @return See {@link Connection#getNetworkTimeout()} * @throws SQLException * See {@link Connection#getNetworkTimeout()} * @see Connection#getNetworkTimeout() */ public static int getNetworkTimeout(final Connection connection) throws SQLException { try { return connection.getNetworkTimeout(); } catch (final AbstractMethodError e) { return 0; } } /** * Delegates to {@link ResultSet#getObject(int, Class)} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link ResultSet#getObject(int, Class)}, then return 0. *

* * @param * See {@link ResultSet#getObject(int, Class)} * @param resultSet * See {@link ResultSet#getObject(int, Class)} * @param columnIndex * See {@link ResultSet#getObject(int, Class)} * @param type * See {@link ResultSet#getObject(int, Class)} * @return See {@link ResultSet#getObject(int, Class)} * @throws SQLException * See {@link ResultSet#getObject(int, Class)} * @see ResultSet#getObject(int, Class) */ @SuppressWarnings("unchecked") public static T getObject(final ResultSet resultSet, final int columnIndex, final Class type) throws SQLException { try { return resultSet.getObject(columnIndex, type); } catch (final AbstractMethodError e) { if (type == String.class) { return (T) resultSet.getString(columnIndex); } // Numbers if (type == Integer.class) { return (T) Integer.valueOf(resultSet.getInt(columnIndex)); } if (type == Long.class) { return (T) Long.valueOf(resultSet.getLong(columnIndex)); } if (type == Double.class) { return (T) Double.valueOf(resultSet.getDouble(columnIndex)); } if (type == Float.class) { return (T) Float.valueOf(resultSet.getFloat(columnIndex)); } if (type == Short.class) { return (T) Short.valueOf(resultSet.getShort(columnIndex)); } if (type == BigDecimal.class) { return (T) resultSet.getBigDecimal(columnIndex); } if (type == Byte.class) { return (T) Byte.valueOf(resultSet.getByte(columnIndex)); } // Dates if (type == Date.class) { return (T) resultSet.getDate(columnIndex); } if (type == Time.class) { return (T) resultSet.getTime(columnIndex); } if (type == Timestamp.class) { return (T) resultSet.getTimestamp(columnIndex); } // Streams if (type == InputStream.class) { return (T) resultSet.getBinaryStream(columnIndex); } if (type == Reader.class) { return (T) resultSet.getCharacterStream(columnIndex); } // Other if (type == Object.class) { return (T) resultSet.getObject(columnIndex); } if (type == Boolean.class) { return (T) Boolean.valueOf(resultSet.getBoolean(columnIndex)); } if (type == Array.class) { return (T) resultSet.getArray(columnIndex); } if (type == Blob.class) { return (T) resultSet.getBlob(columnIndex); } if (type == Clob.class) { return (T) resultSet.getClob(columnIndex); } if (type == Ref.class) { return (T) resultSet.getRef(columnIndex); } if (type == RowId.class) { return (T) resultSet.getRowId(columnIndex); } if (type == SQLXML.class) { return (T) resultSet.getSQLXML(columnIndex); } if (type == URL.class) { return (T) resultSet.getURL(columnIndex); } throw new SQLFeatureNotSupportedException( String.format("resultSet=%s, columnIndex=%,d, type=%s", resultSet, columnIndex, type)); } } /** * Delegates to {@link ResultSet#getObject(String, Class)} without throwing an {@link AbstractMethodError}. * * @param * See {@link ResultSet#getObject(String, Class)} * @param resultSet * See {@link ResultSet#getObject(String, Class)} * @param columnLabel * See {@link ResultSet#getObject(String, Class)} * @param type * See {@link ResultSet#getObject(String, Class)} * @return See {@link ResultSet#getObject(String, Class)} * @throws SQLException * See {@link ResultSet#getObject(String, Class)} * @see ResultSet#getObject(int, Class) */ @SuppressWarnings("unchecked") public static T getObject(final ResultSet resultSet, final String columnLabel, final Class type) throws SQLException { try { return resultSet.getObject(columnLabel, type); } catch (final AbstractMethodError e) { // Numbers if (type == Integer.class) { return (T) Integer.valueOf(resultSet.getInt(columnLabel)); } if (type == Long.class) { return (T) Long.valueOf(resultSet.getLong(columnLabel)); } if (type == Double.class) { return (T) Double.valueOf(resultSet.getDouble(columnLabel)); } if (type == Float.class) { return (T) Float.valueOf(resultSet.getFloat(columnLabel)); } if (type == Short.class) { return (T) Short.valueOf(resultSet.getShort(columnLabel)); } if (type == BigDecimal.class) { return (T) resultSet.getBigDecimal(columnLabel); } if (type == Byte.class) { return (T) Byte.valueOf(resultSet.getByte(columnLabel)); } // Dates if (type == Date.class) { return (T) resultSet.getDate(columnLabel); } if (type == Time.class) { return (T) resultSet.getTime(columnLabel); } if (type == Timestamp.class) { return (T) resultSet.getTimestamp(columnLabel); } // Streams if (type == InputStream.class) { return (T) resultSet.getBinaryStream(columnLabel); } if (type == Reader.class) { return (T) resultSet.getCharacterStream(columnLabel); } // Other if (type == Object.class) { return (T) resultSet.getObject(columnLabel); } if (type == Boolean.class) { return (T) Boolean.valueOf(resultSet.getBoolean(columnLabel)); } if (type == Array.class) { return (T) resultSet.getArray(columnLabel); } if (type == Blob.class) { return (T) resultSet.getBlob(columnLabel); } if (type == Clob.class) { return (T) resultSet.getClob(columnLabel); } if (type == Ref.class) { return (T) resultSet.getRef(columnLabel); } if (type == RowId.class) { return (T) resultSet.getRowId(columnLabel); } if (type == SQLXML.class) { return (T) resultSet.getSQLXML(columnLabel); } if (type == URL.class) { return (T) resultSet.getURL(columnLabel); } throw new SQLFeatureNotSupportedException( String.format("resultSet=%s, columnLabel=%s, type=%s", resultSet, columnLabel, type)); } } /** * Delegates to {@link CommonDataSource#getParentLogger()} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null. *

* * @param commonDataSource * See {@link CommonDataSource#getParentLogger()} * @return See {@link CommonDataSource#getParentLogger()} * @throws SQLFeatureNotSupportedException * See {@link CommonDataSource#getParentLogger()} */ public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException { try { return commonDataSource.getParentLogger(); } catch (final AbstractMethodError e) { throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()"); } } /** * Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a * {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}, * then return null. *

* * @param databaseMetaData * the receiver * @param catalog * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} * @param schemaPattern * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} * @param tableNamePattern * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} * @param columnNamePattern * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} * @return See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} * @throws SQLException * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} * @see DatabaseMetaData#getPseudoColumns(String, String, String, String) */ public static ResultSet getPseudoColumns(final DatabaseMetaData databaseMetaData, final String catalog, final String schemaPattern, final String tableNamePattern, final String columnNamePattern) throws SQLException { try { return databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); } catch (final AbstractMethodError e) { // do nothing return null; } } /** * Delegates to {@link Connection#getSchema()} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link Connection#getSchema()}, then return null. *

* * @param connection * the receiver * @return null for a JDBC 4 driver or a value per {@link Connection#getSchema()}. * @throws SQLException * See {@link Connection#getSchema()}. * @see Connection#getSchema() */ public static String getSchema(final Connection connection) throws SQLException { try { return connection.getSchema(); } catch (final AbstractMethodError e) { // do nothing return null; } } /** * Delegates to {@link Statement#isCloseOnCompletion()} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the * connection is closed to then throw an SQLException. *

* * @param statement * See {@link Statement#isCloseOnCompletion()} * @return See {@link Statement#isCloseOnCompletion()} * @throws SQLException * See {@link Statement#isCloseOnCompletion()} * @see Statement#closeOnCompletion() */ public static boolean isCloseOnCompletion(final Statement statement) throws SQLException { try { return statement.isCloseOnCompletion(); } catch (final AbstractMethodError e) { if (statement.isClosed()) { throw new SQLException("Statement closed"); } return false; } } /** * Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing. *

* * @param connection * the receiver * @param executor * See {@link Connection#setNetworkTimeout(Executor, int)} * @param milliseconds * {@link Connection#setNetworkTimeout(Executor, int)} * @throws SQLException * {@link Connection#setNetworkTimeout(Executor, int)} * @see Connection#setNetworkTimeout(Executor, int) */ public static void setNetworkTimeout(final Connection connection, final Executor executor, final int milliseconds) throws SQLException { try { connection.setNetworkTimeout(executor, milliseconds); } catch (final AbstractMethodError ignored) { // do nothing } } /** * Delegates to {@link Connection#setSchema(String)} without throwing an {@link AbstractMethodError}. *

* If the JDBC driver does not implement {@link Connection#setSchema(String)}, then do nothing. *

* * @param connection * the receiver * @param schema * See {@link Connection#setSchema(String)}. * @throws SQLException * See {@link Connection#setSchema(String)}. * @see Connection#setSchema(String) */ public static void setSchema(final Connection connection, final String schema) throws SQLException { try { connection.setSchema(schema); } catch (final AbstractMethodError ignored) { // do nothing } } } LifetimeExceededException.java000066400000000000000000000026761447311732500342750ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.SQLException; /** * Exception thrown when a connection's maximum lifetime has been exceeded. * * @since 2.1 */ final class LifetimeExceededException extends SQLException { private static final long serialVersionUID = -3783783104516492659L; /** * Constructs a new instance. */ public LifetimeExceededException() { } /** * Constructs a new instance with the given message. * * @param reason a description of the exception */ public LifetimeExceededException(final String reason) { super(reason); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/ListException.java000066400000000000000000000035071447311732500320740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.util.List; /** * An exception wrapping a list of exceptions. * * @since 2.4.0 */ public class ListException extends Exception { private static final long serialVersionUID = 1L; private final List exceptionList; /** * 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. The detail message is saved for later retrieval by the {@link #getMessage()} * method. * @param exceptionList * a list of exceptions. */ public ListException(final String message, final List exceptionList) { super(message); this.exceptionList = exceptionList; } /** * Gets the list of exceptions. * * @return the list of exceptions. */ public List getExceptionList() { return exceptionList; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/ObjectNameWrapper.java000066400000000000000000000065351447311732500326560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.lang.management.ManagementFactory; import java.util.Objects; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Internal wrapper class that allows JMX to be a noop if absent or disabled. * * @since 2.2.1 */ final class ObjectNameWrapper { private static final Log log = LogFactory.getLog(ObjectNameWrapper.class); private static final MBeanServer MBEAN_SERVER = getPlatformMBeanServer(); private static MBeanServer getPlatformMBeanServer() { try { return ManagementFactory.getPlatformMBeanServer(); } catch (final LinkageError | Exception e) { // ignore - JMX not available log.debug("Failed to get platform MBeanServer", e); return null; } } public static ObjectName unwrap(final ObjectNameWrapper wrapper) { return wrapper == null ? null : wrapper.unwrap(); } public static ObjectNameWrapper wrap(final ObjectName objectName) { return new ObjectNameWrapper(objectName); } public static ObjectNameWrapper wrap(final String name) throws MalformedObjectNameException { return wrap(new ObjectName(name)); } private final ObjectName objectName; public ObjectNameWrapper(final ObjectName objectName) { this.objectName = objectName; } public void registerMBean(final Object object) { if (MBEAN_SERVER == null || objectName == null) { return; } try { MBEAN_SERVER.registerMBean(object, objectName); } catch (final LinkageError | Exception e) { log.warn("Failed to complete JMX registration for " + objectName, e); } } /** * @since 2.7.0 */ @Override public String toString() { return Objects.toString(objectName); } public void unregisterMBean() { if (MBEAN_SERVER == null || objectName == null) { return; } if (MBEAN_SERVER.isRegistered(objectName)) { try { MBEAN_SERVER.unregisterMBean(objectName); } catch (final LinkageError | Exception e) { log.warn("Failed to complete JMX unregistration for " + objectName, e); } } } public ObjectName unwrap() { return objectName; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/PStmtKey.java000066400000000000000000000704071447311732500310250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.Objects; import java.util.function.Function; import org.apache.commons.dbcp2.PoolingConnection.StatementType; /** * A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s. * * @since 2.0 */ public class PStmtKey { /** * Interface for Prepared or Callable Statement. */ @FunctionalInterface private interface StatementBuilder { Statement createStatement(Connection connection, PStmtKey key) throws SQLException; } private static final StatementBuilder CallConcurrency = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency); private static final StatementBuilder CallHoldability = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency, k.resultSetHoldability); private static final StatementBuilder CallSQL = (c, k) -> c.prepareCall(k.sql); private static final StatementBuilder StatementAutoGeneratedKeys = (c, k) -> c.prepareStatement(k.sql, k.autoGeneratedKeys); private static final StatementBuilder StatementColumnIndexes = (c, k) -> c.prepareStatement(k.sql, k.columnIndexes); private static final StatementBuilder StatementColumnNames = (c, k) -> c.prepareStatement(k.sql, k.columnNames); private static final StatementBuilder StatementConcurrency = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency); private static final StatementBuilder StatementHoldability = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency, k.resultSetHoldability); private static final StatementBuilder StatementSQL = (c, k) -> c.prepareStatement(k.sql); private static StatementBuilder match(final StatementType statementType, final StatementBuilder prep, final StatementBuilder call) { switch (Objects.requireNonNull(statementType, "statementType")) { case PREPARED_STATEMENT: return prep; case CALLABLE_STATEMENT: return call; default: throw new IllegalArgumentException(statementType.toString()); } } /** * SQL defining Prepared or Callable Statement */ private final String sql; /** * Result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or * {@code ResultSet.TYPE_SCROLL_SENSITIVE}. */ private final Integer resultSetType; /** * Result set concurrency. A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. */ private final Integer resultSetConcurrency; /** * Result set holdability. One of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. */ private final Integer resultSetHoldability; /** * Database catalog. */ private final String catalog; /** * Database schema. */ private final String schema; /** * A flag indicating whether auto-generated keys should be returned; one of {@code Statement.RETURN_GENERATED_KEYS} or * {@code Statement.NO_GENERATED_KEYS}. */ private final Integer autoGeneratedKeys; /** * An array of column indexes indicating the columns that should be returned from the inserted row or rows. */ private final int[] columnIndexes; /** * An array of column names indicating the columns that should be returned from the inserted row or rows. */ private final String[] columnNames; /** * Statement builder. */ private final transient StatementBuilder statementBuilder; /** * Statement type, prepared or callable. */ private final StatementType statementType; /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @deprecated Use {@link #PStmtKey(String, String, String)}. */ @Deprecated public PStmtKey(final String sql) { this(sql, null, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @deprecated Use {@link #PStmtKey(String, String, String, int, int)}. */ @Deprecated public PStmtKey(final String sql, final int resultSetType, final int resultSetConcurrency) { this(sql, null, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @deprecated Use {@link #PStmtKey(String, String, String)}. */ @Deprecated public PStmtKey(final String sql, final String catalog) { this(sql, catalog, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * @deprecated Use {@link #PStmtKey(String, String, String, int)}. */ @Deprecated public PStmtKey(final String sql, final String catalog, final int autoGeneratedKeys) { this(sql, catalog, StatementType.PREPARED_STATEMENT, autoGeneratedKeys); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @deprecated Use {@link #PStmtKey(String, String, String, int, int)}. */ @Deprecated public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency) { this(sql, catalog, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param resultSetType a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE} * @param resultSetHoldability One of the following {@code ResultSet} constants: * {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @deprecated Use {@link #PStmtKey(String, String, String, int, int, int)}. */ @Deprecated public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { this(sql, catalog, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param resultSetType a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE} * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param resultSetHoldability One of the following {@code ResultSet} constants: * {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @param statementType The SQL statement type, prepared or callable. * @deprecated Use {@link #PStmtKey(String, String, String, int, int, int, PoolingConnection.StatementType)} */ @Deprecated public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final StatementType statementType) { this(sql, catalog, null, resultSetType, resultSetConcurrency, resultSetHoldability, null, null, null, statementType, k -> match(statementType, StatementHoldability, CallHoldability)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param statementType The SQL statement type, prepared or callable. * @deprecated Use {@link #PStmtKey(String, String, String, int, int, PoolingConnection.StatementType)}. */ @Deprecated public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final StatementType statementType) { this(sql, catalog, null, resultSetType, resultSetConcurrency, null, null, null, null, statementType, k -> match(statementType, StatementConcurrency, CallConcurrency)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param columnIndexes An array of column indexes indicating the columns that should be returned from the inserted row * or rows. * @deprecated Use {@link #PStmtKey(String, String, String, int[])}. */ @Deprecated public PStmtKey(final String sql, final String catalog, final int[] columnIndexes) { this(sql, catalog, null, null, null, null, null, columnIndexes, null, StatementType.PREPARED_STATEMENT, StatementColumnIndexes); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param statementType The SQL statement type, prepared or callable. * @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType)}. */ @Deprecated public PStmtKey(final String sql, final String catalog, final StatementType statementType) { this(sql, catalog, null, null, null, null, null, null, null, statementType, k -> match(statementType, StatementSQL, CallSQL)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param statementType The SQL statement type, prepared or callable. * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType, Integer)} */ @Deprecated public PStmtKey(final String sql, final String catalog, final StatementType statementType, final Integer autoGeneratedKeys) { this(sql, catalog, null, null, null, null, autoGeneratedKeys, null, null, statementType, k -> match(statementType, StatementAutoGeneratedKeys, CallSQL)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema) { this(sql, catalog, schema, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema, final int autoGeneratedKeys) { this(sql, catalog, schema, StatementType.PREPARED_STATEMENT, autoGeneratedKeys); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. */ public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency) { this(sql, catalog, schema, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema * @param resultSetType a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE} * @param resultSetHoldability One of the following {@code ResultSet} constants: * {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { this(sql, catalog, schema, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema. * @param resultSetType a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE} * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param resultSetHoldability One of the following {@code ResultSet} constants: * {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @param statementType The SQL statement type, prepared or callable. * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final StatementType statementType) { this(sql, catalog, schema, resultSetType, resultSetConcurrency, resultSetHoldability, null, null, null, statementType, k -> match(statementType, StatementHoldability, CallHoldability)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema. * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param statementType The SQL statement type, prepared or callable. * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency, final StatementType statementType) { this(sql, catalog, schema, resultSetType, resultSetConcurrency, null, null, null, null, statementType, k -> match(statementType, StatementConcurrency, CallConcurrency)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema. * @param columnIndexes An array of column indexes indicating the columns that should be returned from the inserted row * or rows. */ public PStmtKey(final String sql, final String catalog, final String schema, final int[] columnIndexes) { this(sql, catalog, schema, null, null, null, null, columnIndexes, null, StatementType.PREPARED_STATEMENT, StatementColumnIndexes); } private PStmtKey(final String sql, final String catalog, final String schema, final Integer resultSetType, final Integer resultSetConcurrency, final Integer resultSetHoldability, final Integer autoGeneratedKeys, final int[] columnIndexes, final String[] columnNames, final StatementType statementType, final Function statementBuilder) { this.sql = Objects.requireNonNull(sql, "sql").trim(); this.catalog = catalog; this.schema = schema; this.resultSetType = resultSetType; this.resultSetConcurrency = resultSetConcurrency; this.resultSetHoldability = resultSetHoldability; this.autoGeneratedKeys = autoGeneratedKeys; this.columnIndexes = clone(columnIndexes); this.columnNames = clone(columnNames); this.statementBuilder = Objects.requireNonNull(Objects.requireNonNull(statementBuilder, "statementBuilder").apply(this), "statementBuilder"); this.statementType = statementType; } // Root constructor. private PStmtKey(final String sql, final String catalog, final String schema, final Integer resultSetType, final Integer resultSetConcurrency, final Integer resultSetHoldability, final Integer autoGeneratedKeys, final int[] columnIndexes, final String[] columnNames, final StatementType statementType, final StatementBuilder statementBuilder) { this.sql = sql; this.catalog = catalog; this.schema = schema; this.resultSetType = resultSetType; this.resultSetConcurrency = resultSetConcurrency; this.resultSetHoldability = resultSetHoldability; this.autoGeneratedKeys = autoGeneratedKeys; this.columnIndexes = clone(columnIndexes); this.columnNames = clone(columnNames); this.statementBuilder = Objects.requireNonNull(statementBuilder, "statementBuilder"); this.statementType = statementType; } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema. * @param statementType The SQL statement type, prepared or callable. * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType) { this(sql, catalog, schema, null, null, null, null, null, null, statementType, k -> match(statementType, StatementSQL, CallSQL)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema. * @param statementType The SQL statement type, prepared or callable. * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType, final Integer autoGeneratedKeys) { this(sql, catalog, schema, null, null, null, autoGeneratedKeys, null, null, statementType, k -> match(statementType, StatementAutoGeneratedKeys, CallSQL)); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param schema The schema. * @param columnNames An array of column names indicating the columns that should be returned from the inserted row or * rows. * @since 2.5.0 */ public PStmtKey(final String sql, final String catalog, final String schema, final String[] columnNames) { this(sql, catalog, schema, null, null, null, null, null, columnNames, StatementType.PREPARED_STATEMENT, StatementColumnNames); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql The SQL statement. * @param catalog The catalog. * @param columnNames An array of column names indicating the columns that should be returned from the inserted row or * rows. * @deprecated Use {@link #PStmtKey(String, String, String, String[])}. */ @Deprecated public PStmtKey(final String sql, final String catalog, final String[] columnNames) { this(sql, catalog, null, null, null, null, null, null, columnNames, StatementType.PREPARED_STATEMENT, StatementColumnNames); } private int[] clone(final int[] array) { return array == null ? null : array.clone(); } private String[] clone(final String[] array) { return array == null ? null : array.clone(); } /** * Creates a new Statement from the given Connection. * * @param connection The Connection to use to create the statement. * @return The statement. * @throws SQLException Thrown when there is a problem creating the statement. */ public Statement createStatement(final Connection connection) throws SQLException { return statementBuilder.createStatement(connection, this); } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final PStmtKey other = (PStmtKey) obj; if (!Objects.equals(autoGeneratedKeys, other.autoGeneratedKeys)) { return false; } if (!Objects.equals(catalog, other.catalog)) { return false; } if (!Arrays.equals(columnIndexes, other.columnIndexes)) { return false; } if (!Arrays.equals(columnNames, other.columnNames)) { return false; } if (!Objects.equals(resultSetConcurrency, other.resultSetConcurrency)) { return false; } if (!Objects.equals(resultSetHoldability, other.resultSetHoldability)) { return false; } if (!Objects.equals(resultSetType, other.resultSetType)) { return false; } if (!Objects.equals(schema, other.schema)) { return false; } if (!Objects.equals(sql, other.sql)) { return false; } return statementType == other.statementType; } /** * Gets a flag indicating whether auto-generated keys should be returned; one of {@code Statement.RETURN_GENERATED_KEYS} * or {@code Statement.NO_GENERATED_KEYS}. * * @return a flag indicating whether auto-generated keys should be returned. */ public Integer getAutoGeneratedKeys() { return autoGeneratedKeys; } /** * Gets the catalog. * * @return The catalog. */ public String getCatalog() { return catalog; } /** * Gets an array of column indexes indicating the columns that should be returned from the inserted row or rows. * * @return An array of column indexes. */ public int[] getColumnIndexes() { return clone(columnIndexes); } /** * Gets an array of column names indicating the columns that should be returned from the inserted row or rows. * * @return An array of column names. */ public String[] getColumnNames() { return clone(columnNames); } /** * Gets the result set concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * * @return The result set concurrency type. */ public Integer getResultSetConcurrency() { return resultSetConcurrency; } /** * Gets the result set holdability, one of the following {@code ResultSet} constants: * {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * * @return The result set holdability. */ public Integer getResultSetHoldability() { return resultSetHoldability; } /** * Gets the result set type, one of {@code ResultSet.TYPE_FORWARD_ONLY}, {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or * {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * * @return the result set type. */ public Integer getResultSetType() { return resultSetType; } /** * Gets the schema. * * @return The catalog. */ public String getSchema() { return schema; } /** * Gets the SQL statement. * * @return the SQL statement. */ public String getSql() { return sql; } /** * Gets the SQL statement type. * * @return The SQL statement type. */ public StatementType getStmtType() { return statementType; } @Override public int hashCode() { return Objects.hash(autoGeneratedKeys, catalog, Arrays.hashCode(columnIndexes), Arrays.hashCode(columnNames), resultSetConcurrency, resultSetHoldability, resultSetType, schema, sql, statementType); } @Override public String toString() { final StringBuilder buf = new StringBuilder(); buf.append("PStmtKey: sql="); buf.append(sql); buf.append(", catalog="); buf.append(catalog); buf.append(", schema="); buf.append(schema); buf.append(", resultSetType="); buf.append(resultSetType); buf.append(", resultSetConcurrency="); buf.append(resultSetConcurrency); buf.append(", resultSetHoldability="); buf.append(resultSetHoldability); buf.append(", autoGeneratedKeys="); buf.append(autoGeneratedKeys); buf.append(", columnIndexes="); buf.append(Arrays.toString(columnIndexes)); buf.append(", columnNames="); buf.append(Arrays.toString(columnNames)); buf.append(", statementType="); buf.append(statementType); return buf.toString(); } } PoolableCallableStatement.java000066400000000000000000000075671447311732500342770ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.pool2.KeyedObjectPool; /** * A {@link DelegatingCallableStatement} that cooperates with {@link PoolingConnection} to implement a pool of * {@link CallableStatement}s. *

* The {@link #close} method returns this statement to its containing pool. (See {@link PoolingConnection}.) * * @see PoolingConnection * @since 2.0 */ public class PoolableCallableStatement extends DelegatingCallableStatement { /** * The {@link KeyedObjectPool} from which this CallableStatement was obtained. */ private final KeyedObjectPool pool; /** * Key for this statement in the containing {@link KeyedObjectPool}. */ private final PStmtKey key; /** * Constructor. * * @param callableStatement * the underlying {@link CallableStatement} * @param key * the key for this statement in the {@link KeyedObjectPool} * @param pool * the {@link KeyedObjectPool} from which this CallableStatement was obtained * @param connection * the {@link DelegatingConnection} that created this CallableStatement */ public PoolableCallableStatement(final CallableStatement callableStatement, final PStmtKey key, final KeyedObjectPool pool, final DelegatingConnection connection) { super(connection, callableStatement); this.pool = pool; this.key = key; // Remove from trace now because this statement will be // added by the activate method. removeThisTrace(connection); } /** * Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection that created * it. * * @since 2.4.0 made public, was protected in 2.3.0. */ @Override public void activate() throws SQLException { setClosedInternal(false); AbandonedTrace.add(getConnectionInternal(), this); super.activate(); } /** * Returns the CallableStatement to the pool. If {{@link #isClosed()}, this is a No-op. */ @Override public void close() throws SQLException { // calling close twice should have no effect if (!isClosed()) { try { pool.returnObject(key, this); } catch (final SQLException | RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot close CallableStatement (return to pool failed)", e); } } } /** * Passivates to prepare for return to the pool. Removes the trace associated with this CallableStatement from the * Connection that created it. Also closes any associated ResultSets. * * @since 2.4.0 made public, was protected in 2.3.0. */ @Override public void passivate() throws SQLException { prepareToReturn(); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java000066400000000000000000000372501447311732500330610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.lang.management.ManagementFactory; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.time.Duration; import java.util.Collection; import java.util.concurrent.Executor; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import org.apache.commons.pool2.ObjectPool; /** * A delegating connection that, rather than closing the underlying connection, returns itself to an {@link ObjectPool} * when closed. * * @since 2.0 */ public class PoolableConnection extends DelegatingConnection implements PoolableConnectionMXBean { private static MBeanServer MBEAN_SERVER; static { try { MBEAN_SERVER = ManagementFactory.getPlatformMBeanServer(); } catch (final NoClassDefFoundError | Exception ignored) { // ignore - JMX not available } } /** The pool to which I should return. */ private final ObjectPool pool; private final ObjectNameWrapper jmxObjectName; // Use a prepared statement for validation, retaining the last used SQL to // check if the validation query has changed. private PreparedStatement validationPreparedStatement; private String lastValidationSql; /** * Indicate that unrecoverable SQLException was thrown when using this connection. Such a connection should be * considered broken and not pass validation in the future. */ private boolean fatalSqlExceptionThrown; /** * SQL_STATE codes considered to signal fatal conditions. Overrides the defaults in * {@link Utils#getDisconnectionSqlCodes()} (plus anything starting with {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). */ private final Collection disconnectionSqlCodes; /** Whether or not to fast fail validation after fatal connection errors */ private final boolean fastFailValidation; /** * * @param conn * my underlying connection * @param pool * the pool to which I should return when closed * @param jmxName * JMX name */ public PoolableConnection(final Connection conn, final ObjectPool pool, final ObjectName jmxName) { this(conn, pool, jmxName, null, true); } /** * * @param conn * my underlying connection * @param pool * the pool to which I should return when closed * @param jmxObjectName * JMX name * @param disconnectSqlCodes * SQL_STATE codes considered fatal disconnection errors * @param fastFailValidation * true means fatal disconnection errors cause subsequent validations to fail immediately (no attempt to * run query or isValid) */ public PoolableConnection(final Connection conn, final ObjectPool pool, final ObjectName jmxObjectName, final Collection disconnectSqlCodes, final boolean fastFailValidation) { super(conn); this.pool = pool; this.jmxObjectName = ObjectNameWrapper.wrap(jmxObjectName); this.disconnectionSqlCodes = disconnectSqlCodes; this.fastFailValidation = fastFailValidation; if (jmxObjectName != null) { try { MBEAN_SERVER.registerMBean(this, jmxObjectName); } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException ignored) { // For now, simply skip registration } } } /** * Abort my underlying {@link Connection}. * * @since 2.9.0 */ @Override public void abort(final Executor executor) throws SQLException { if (jmxObjectName != null) { jmxObjectName.unregisterMBean(); } super.abort(executor); } /** * Returns me to my pool. */ @Override public synchronized void close() throws SQLException { if (isClosedInternal()) { // already closed return; } boolean isUnderlyingConnectionClosed; try { isUnderlyingConnectionClosed = getDelegateInternal().isClosed(); } catch (final SQLException e) { try { pool.invalidateObject(this); } catch (final IllegalStateException ise) { // pool is closed, so close the connection passivate(); getInnermostDelegate().close(); } catch (final Exception ignored) { // DO NOTHING the original exception will be rethrown } throw new SQLException("Cannot close connection (isClosed check failed)", e); } /* * Can't set close before this code block since the connection needs to be open when validation runs. Can't set * close after this code block since by then the connection will have been returned to the pool and may have * been borrowed by another thread. Therefore, the close flag is set in passivate(). */ if (isUnderlyingConnectionClosed) { // Abnormal close: underlying connection closed unexpectedly, so we // must destroy this proxy try { pool.invalidateObject(this); } catch (final IllegalStateException e) { // pool is closed, so close the connection passivate(); getInnermostDelegate().close(); } catch (final Exception e) { throw new SQLException("Cannot close connection (invalidating pooled object failed)", e); } } else { // Normal close: underlying connection is still open, so we // simply need to return this proxy to the pool try { pool.returnObject(this); } catch (final IllegalStateException e) { // pool is closed, so close the connection passivate(); getInnermostDelegate().close(); } catch (final SQLException | RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot close connection (return to pool failed)", e); } } } /** * @return The disconnection SQL codes. * @since 2.6.0 */ public Collection getDisconnectionSqlCodes() { return disconnectionSqlCodes; } /** * Expose the {@link #toString()} method via a bean getter, so it can be read as a property via JMX. */ @Override public String getToString() { return toString(); } @Override protected void handleException(final SQLException e) throws SQLException { fatalSqlExceptionThrown |= isFatalException(e); super.handleException(e); } /** * {@inheritDoc} *

* This method should not be used by a client to determine whether or not a connection should be return to the * connection pool (by calling {@link #close()}). Clients should always attempt to return a connection to the pool * once it is no longer required. */ @Override public boolean isClosed() throws SQLException { if (isClosedInternal()) { return true; } if (getDelegateInternal().isClosed()) { // Something has gone wrong. The underlying connection has been // closed without the connection being returned to the pool. Return // it now. close(); return true; } return false; } /** * Checks the SQLState of the input exception. *

* If {@link #disconnectionSqlCodes} has been set, sql states are compared to those in the configured list of fatal * exception codes. If this property is not set, codes are compared against the default codes in * {@link Utils#getDisconnectionSqlCodes()} and in this case anything starting with #{link * Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection. *

* * @param e SQLException to be examined * @return true if the exception signals a disconnection */ boolean isDisconnectionSqlException(final SQLException e) { boolean fatalException = false; final String sqlState = e.getSQLState(); if (sqlState != null) { fatalException = disconnectionSqlCodes == null ? sqlState.startsWith(Utils.DISCONNECTION_SQL_CODE_PREFIX) || Utils.getDisconnectionSqlCodes().contains(sqlState) : disconnectionSqlCodes.contains(sqlState); } return fatalException; } /** * Checks the SQLState of the input exception and any nested SQLExceptions it wraps. *

* If {@link #disconnectionSqlCodes} has been set, sql states are compared to those in the * configured list of fatal exception codes. If this property is not set, codes are compared against the default * codes in {@link Utils#getDisconnectionSqlCodes()} and in this case anything starting with #{link * Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection. *

* * @param e * SQLException to be examined * @return true if the exception signals a disconnection */ boolean isFatalException(final SQLException e) { boolean fatalException = isDisconnectionSqlException(e); if (!fatalException) { SQLException parentException = e; SQLException nextException = e.getNextException(); while (nextException != null && nextException != parentException && !fatalException) { fatalException = isDisconnectionSqlException(nextException); parentException = nextException; nextException = parentException.getNextException(); } } return fatalException; } /** * @return Whether to fail-fast. * @since 2.6.0 */ public boolean isFastFailValidation() { return fastFailValidation; } @Override protected void passivate() throws SQLException { super.passivate(); setClosedInternal(true); if (getDelegateInternal() instanceof PoolingConnection) { ((PoolingConnection) getDelegateInternal()).connectionReturnedToPool(); } } /** * Actually close my underlying {@link Connection}. */ @Override public void reallyClose() throws SQLException { if (jmxObjectName != null) { jmxObjectName.unregisterMBean(); } if (validationPreparedStatement != null) { Utils.closeQuietly((AutoCloseable) validationPreparedStatement); } super.closeInternal(); } /** * Validates the connection, using the following algorithm: *
    *
  1. If {@code fastFailValidation} (constructor argument) is {@code true} and this connection has previously * thrown a fatal disconnection exception, a {@code SQLException} is thrown.
  2. *
  3. If {@code sql} is null, the driver's #{@link Connection#isValid(int) isValid(timeout)} is called. If it * returns {@code false}, {@code SQLException} is thrown; otherwise, this method returns successfully.
  4. *
  5. If {@code sql} is not null, it is executed as a query and if the resulting {@code ResultSet} contains at * least one row, this method returns successfully. If not, {@code SQLException} is thrown.
  6. *
* * @param sql * The validation SQL query. * @param timeoutSeconds * The validation timeout in seconds. * @throws SQLException * Thrown when validation fails or an SQLException occurs during validation * @deprecated Use {@link #validate(String, Duration)}. */ @Deprecated public void validate(final String sql, final int timeoutSeconds) throws SQLException { validate(sql, Duration.ofSeconds(timeoutSeconds)); } /** * Validates the connection, using the following algorithm: *
    *
  1. If {@code fastFailValidation} (constructor argument) is {@code true} and this connection has previously * thrown a fatal disconnection exception, a {@code SQLException} is thrown.
  2. *
  3. If {@code sql} is null, the driver's #{@link Connection#isValid(int) isValid(timeout)} is called. If it * returns {@code false}, {@code SQLException} is thrown; otherwise, this method returns successfully.
  4. *
  5. If {@code sql} is not null, it is executed as a query and if the resulting {@code ResultSet} contains at * least one row, this method returns successfully. If not, {@code SQLException} is thrown.
  6. *
* * @param sql * The validation SQL query. * @param timeoutDuration * The validation timeout in seconds. * @throws SQLException * Thrown when validation fails or an SQLException occurs during validation * @since 2.10.0 */ public void validate(final String sql, Duration timeoutDuration) throws SQLException { if (fastFailValidation && fatalSqlExceptionThrown) { throw new SQLException(Utils.getMessage("poolableConnection.validate.fastFail")); } if (sql == null || sql.isEmpty()) { if (timeoutDuration.isNegative()) { timeoutDuration = Duration.ZERO; } if (!isValid(timeoutDuration)) { throw new SQLException("isValid() returned false"); } return; } if (!sql.equals(lastValidationSql)) { lastValidationSql = sql; // Has to be the innermost delegate else the prepared statement will // be closed when the pooled connection is passivated. validationPreparedStatement = getInnermostDelegateInternal().prepareStatement(sql); } if (timeoutDuration.compareTo(Duration.ZERO) > 0) { validationPreparedStatement.setQueryTimeout((int) timeoutDuration.getSeconds()); } try (ResultSet rs = validationPreparedStatement.executeQuery()) { if (!rs.next()) { throw new SQLException("validationQuery didn't return a row"); } } catch (final SQLException sqle) { throw sqle; } } } PoolableConnectionFactory.java000066400000000000000000000637341447311732500343400ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import java.util.Collection; import java.util.Objects; import java.util.concurrent.atomic.AtomicLong; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.DestroyMode; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; /** * A {@link PooledObjectFactory} that creates {@link PoolableConnection}s. * * @since 2.0 */ public class PoolableConnectionFactory implements PooledObjectFactory { private static final Log log = LogFactory.getLog(PoolableConnectionFactory.class); /** * Internal constant to indicate the level is not set. */ static final int UNKNOWN_TRANSACTION_ISOLATION = -1; private final ConnectionFactory connectionFactory; private final ObjectName dataSourceJmxObjectName; private volatile String validationQuery; private volatile Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1); private Collection connectionInitSqls; private Collection disconnectionSqlCodes; private boolean fastFailValidation = true; private volatile ObjectPool pool; private Boolean defaultReadOnly; private Boolean defaultAutoCommit; private boolean autoCommitOnReturn = true; private boolean rollbackOnReturn = true; private int defaultTransactionIsolation = UNKNOWN_TRANSACTION_ISOLATION; private String defaultCatalog; private String defaultSchema; private boolean cacheState; private boolean poolStatements; private boolean clearStatementPoolOnReturn; private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; private Duration maxConnDuration = Duration.ofMillis(-1); private final AtomicLong connectionIndex = new AtomicLong(); private Duration defaultQueryTimeoutDuration; /** * Creates a new {@code PoolableConnectionFactory}. * * @param connFactory * the {@link ConnectionFactory} from which to obtain base {@link Connection}s * @param dataSourceJmxObjectName * The JMX object name, may be null. */ public PoolableConnectionFactory(final ConnectionFactory connFactory, final ObjectName dataSourceJmxObjectName) { this.connectionFactory = connFactory; this.dataSourceJmxObjectName = dataSourceJmxObjectName; } @Override public void activateObject(final PooledObject p) throws SQLException { validateLifetime(p); final PoolableConnection pConnection = p.getObject(); pConnection.activate(); if (defaultAutoCommit != null && pConnection.getAutoCommit() != defaultAutoCommit) { pConnection.setAutoCommit(defaultAutoCommit); } if (defaultTransactionIsolation != UNKNOWN_TRANSACTION_ISOLATION && pConnection.getTransactionIsolation() != defaultTransactionIsolation) { pConnection.setTransactionIsolation(defaultTransactionIsolation); } if (defaultReadOnly != null && pConnection.isReadOnly() != defaultReadOnly) { pConnection.setReadOnly(defaultReadOnly); } if (defaultCatalog != null && !defaultCatalog.equals(pConnection.getCatalog())) { pConnection.setCatalog(defaultCatalog); } if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(pConnection))) { Jdbc41Bridge.setSchema(pConnection, defaultSchema); } pConnection.setDefaultQueryTimeout(defaultQueryTimeoutDuration); } @Override public void destroyObject(final PooledObject p) throws SQLException { p.getObject().reallyClose(); } /** * @since 2.9.0 */ @Override public void destroyObject(final PooledObject p, final DestroyMode mode) throws SQLException { if (mode == DestroyMode.ABANDONED) { p.getObject().getInnermostDelegate().abort(Runnable::run); } else { p.getObject().reallyClose(); } } /** * Gets the cache state. * * @return The cache state. * @since 2.6.0. */ public boolean getCacheState() { return cacheState; } /** * Gets the connection factory. * * @return The connection factory. * @since 2.6.0. */ public ConnectionFactory getConnectionFactory() { return connectionFactory; } protected AtomicLong getConnectionIndex() { return connectionIndex; } /** * @return The collection of initialization SQL statements. * @since 2.6.0 */ public Collection getConnectionInitSqls() { return connectionInitSqls; } /** * @return The data source JMX ObjectName * @since 2.6.0. */ public ObjectName getDataSourceJmxName() { return dataSourceJmxObjectName; } /** * @return The data source JMS ObjectName. * @since 2.6.0 */ public ObjectName getDataSourceJmxObjectName() { return dataSourceJmxObjectName; } /** * @return Default auto-commit value. * @since 2.6.0 */ public Boolean getDefaultAutoCommit() { return defaultAutoCommit; } /** * @return Default catalog. * @since 2.6.0 */ public String getDefaultCatalog() { return defaultCatalog; } /** * @return Default query timeout in seconds. * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}. */ @Deprecated public Integer getDefaultQueryTimeout() { return getDefaultQueryTimeoutSeconds(); } /** * Gets the default query timeout Duration. * * @return Default query timeout Duration. * @since 2.10.0 */ public Duration getDefaultQueryTimeoutDuration() { return defaultQueryTimeoutDuration; } /** * @return Default query timeout in seconds. * @since 2.6.0 * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}. */ @Deprecated public Integer getDefaultQueryTimeoutSeconds() { return defaultQueryTimeoutDuration == null ? null : (int) defaultQueryTimeoutDuration.getSeconds(); } /** * @return Default read-only-value. * @since 2.6.0 */ public Boolean getDefaultReadOnly() { return defaultReadOnly; } /** * @return Default schema. * @since 2.6.0 */ public String getDefaultSchema() { return defaultSchema; } /** * @return Default transaction isolation. * @since 2.6.0 */ public int getDefaultTransactionIsolation() { return defaultTransactionIsolation; } /** * SQL_STATE codes considered to signal fatal conditions. *

* Overrides the defaults in {@link Utils#getDisconnectionSqlCodes()} (plus anything starting with * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #isFastFailValidation()} is * {@code true}, whenever connections created by this factory generate exceptions with SQL_STATE codes in this list, * they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at isValid or * validation query). *

*

* If {@link #isFastFailValidation()} is {@code false} setting this property has no effect. *

* * @return SQL_STATE codes overriding defaults * @since 2.1 */ public Collection getDisconnectionSqlCodes() { return disconnectionSqlCodes; } /** * Gets the Maximum connection duration. * * @return Maximum connection duration. * @since 2.10.0 */ public Duration getMaxConnDuration() { return maxConnDuration; } /** * Gets the Maximum connection lifetime in milliseconds. * * @return Maximum connection lifetime in milliseconds. * @since 2.6.0 */ public long getMaxConnLifetimeMillis() { return maxConnDuration.toMillis(); } protected int getMaxOpenPreparedStatements() { return maxOpenPreparedStatements; } /** * Returns the {@link ObjectPool} in which {@link Connection}s are pooled. * * @return the connection pool */ public synchronized ObjectPool getPool() { return pool; } /** * @return Whether to pool statements. * @since 2.6.0. */ public boolean getPoolStatements() { return poolStatements; } /** * @return Validation query. * @since 2.6.0 */ public String getValidationQuery() { return validationQuery; } /** * Gets the query timeout in seconds. * * @return Validation query timeout in seconds. * @since 2.10.0 */ public Duration getValidationQueryTimeoutDuration() { return validationQueryTimeoutDuration; } /** * Gets the query timeout in seconds. * * @return Validation query timeout in seconds. * @since 2.6.0 * @deprecated Use {@link #getValidationQueryTimeoutDuration()}. */ @Deprecated public int getValidationQueryTimeoutSeconds() { return (int) validationQueryTimeoutDuration.getSeconds(); } protected void initializeConnection(final Connection conn) throws SQLException { final Collection sqls = connectionInitSqls; if (conn.isClosed()) { throw new SQLException("initializeConnection: connection closed"); } if (!Utils.isEmpty(sqls)) { try (Statement statement = conn.createStatement()) { for (final String sql : sqls) { statement.execute(Objects.requireNonNull(sql, "null connectionInitSqls element")); } } } } /** * @return Whether to auto-commit on return. * @since 2.6.0 */ public boolean isAutoCommitOnReturn() { return autoCommitOnReturn; } /** * @return Whether to auto-commit on return. * @deprecated Use {@link #isAutoCommitOnReturn()}. */ @Deprecated public boolean isEnableAutoCommitOnReturn() { return autoCommitOnReturn; } /** * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with * SQL_STATE indicating fatal disconnection errors. * * @return true if connections created by this factory will fast fail validation. * @see #setDisconnectionSqlCodes(Collection) * @since 2.1 * @since 2.5.0 Defaults to true, previous versions defaulted to false. */ public boolean isFastFailValidation() { return fastFailValidation; } /** * @return Whether to rollback on return. */ public boolean isRollbackOnReturn() { return rollbackOnReturn; } @Override public PooledObject makeObject() throws SQLException { Connection conn = connectionFactory.createConnection(); if (conn == null) { throw new IllegalStateException("Connection factory returned null from createConnection"); } try { initializeConnection(conn); } catch (final SQLException e) { // Make sure the connection is closed Utils.closeQuietly((AutoCloseable) conn); // Rethrow original exception so it is visible to caller throw e; } final long connIndex = connectionIndex.getAndIncrement(); if (poolStatements) { conn = new PoolingConnection(conn); final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig<>(); config.setMaxTotalPerKey(-1); config.setBlockWhenExhausted(false); config.setMaxWait(Duration.ZERO); config.setMaxIdlePerKey(1); config.setMaxTotal(maxOpenPreparedStatements); if (dataSourceJmxObjectName != null) { final StringBuilder base = new StringBuilder(dataSourceJmxObjectName.toString()); base.append(Constants.JMX_CONNECTION_BASE_EXT); base.append(connIndex); config.setJmxNameBase(base.toString()); config.setJmxNamePrefix(Constants.JMX_STATEMENT_POOL_PREFIX); } else { config.setJmxEnabled(false); } final PoolingConnection poolingConn = (PoolingConnection) conn; final KeyedObjectPool stmtPool = new GenericKeyedObjectPool<>(poolingConn, config); poolingConn.setStatementPool(stmtPool); poolingConn.setClearStatementPoolOnReturn(clearStatementPoolOnReturn); poolingConn.setCacheState(cacheState); } // Register this connection with JMX final ObjectName connJmxName; if (dataSourceJmxObjectName == null) { connJmxName = null; } else { final String name = dataSourceJmxObjectName.toString() + Constants.JMX_CONNECTION_BASE_EXT + connIndex; try { connJmxName = new ObjectName(name); } catch (MalformedObjectNameException e) { Utils.closeQuietly((AutoCloseable) conn); throw new SQLException(name, e); } } final PoolableConnection pc = new PoolableConnection(conn, pool, connJmxName, disconnectionSqlCodes, fastFailValidation); pc.setCacheState(cacheState); return new DefaultPooledObject<>(pc); } @Override public void passivateObject(final PooledObject p) throws SQLException { validateLifetime(p); final PoolableConnection conn = p.getObject(); Boolean connAutoCommit = null; if (rollbackOnReturn) { connAutoCommit = conn.getAutoCommit(); if (!connAutoCommit && !conn.isReadOnly()) { conn.rollback(); } } conn.clearWarnings(); // DBCP-97 / DBCP-399 / DBCP-351 Idle connections in the pool should // have autoCommit enabled if (autoCommitOnReturn) { if (connAutoCommit == null) { connAutoCommit = conn.getAutoCommit(); } if (!connAutoCommit) { conn.setAutoCommit(true); } } conn.passivate(); } public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) { this.autoCommitOnReturn = autoCommitOnReturn; } public void setCacheState(final boolean cacheState) { this.cacheState = cacheState; } /** * Sets whether the pool of statements (which was enabled with {@link #setPoolStatements(boolean)}) should * be cleared when the connection is returned to its pool. Default is false. * * @param clearStatementPoolOnReturn clear or not * @since 2.8.0 */ public void setClearStatementPoolOnReturn(final boolean clearStatementPoolOnReturn) { this.clearStatementPoolOnReturn = clearStatementPoolOnReturn; } /** * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off * connection initialization. * * @param connectionInitSqls * SQL statement to initialize {@link Connection}s. */ public void setConnectionInitSql(final Collection connectionInitSqls) { this.connectionInitSqls = connectionInitSqls; } /** * Sets the default "auto commit" setting for borrowed {@link Connection}s * * @param defaultAutoCommit * the default "auto commit" setting for borrowed {@link Connection}s */ public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { this.defaultAutoCommit = defaultAutoCommit; } /** * Sets the default "catalog" setting for borrowed {@link Connection}s * * @param defaultCatalog * the default "catalog" setting for borrowed {@link Connection}s */ public void setDefaultCatalog(final String defaultCatalog) { this.defaultCatalog = defaultCatalog; } /** * Sets the query timeout Duration. * * @param defaultQueryTimeoutDuration the query timeout Duration. * @since 2.10.0 */ public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) { this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration; } /** * Sets the query timeout in seconds. * * @param defaultQueryTimeoutSeconds the query timeout in seconds. * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}. */ @Deprecated public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds); } /** * Sets the default "read only" setting for borrowed {@link Connection}s * * @param defaultReadOnly * the default "read only" setting for borrowed {@link Connection}s */ public void setDefaultReadOnly(final Boolean defaultReadOnly) { this.defaultReadOnly = defaultReadOnly; } /** * Sets the default "schema" setting for borrowed {@link Connection}s * * @param defaultSchema * the default "schema" setting for borrowed {@link Connection}s * @since 2.5.0 */ public void setDefaultSchema(final String defaultSchema) { this.defaultSchema = defaultSchema; } /** * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s * * @param defaultTransactionIsolation * the default "Transaction Isolation" setting for returned {@link Connection}s */ public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { this.defaultTransactionIsolation = defaultTransactionIsolation; } /** * @param disconnectionSqlCodes * The disconnection SQL codes. * @see #getDisconnectionSqlCodes() * @since 2.1 */ public void setDisconnectionSqlCodes(final Collection disconnectionSqlCodes) { this.disconnectionSqlCodes = disconnectionSqlCodes; } /** * @param autoCommitOnReturn Whether to auto-commit on return. * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}. */ @Deprecated public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) { this.autoCommitOnReturn = autoCommitOnReturn; } /** * @see #isFastFailValidation() * @param fastFailValidation * true means connections created by this factory will fast fail validation * @since 2.1 */ public void setFastFailValidation(final boolean fastFailValidation) { this.fastFailValidation = fastFailValidation; } /** * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation, * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1. * * @param maxConnDuration * The maximum lifetime in milliseconds. * @since 2.10.0 */ public void setMaxConn(final Duration maxConnDuration) { this.maxConnDuration = maxConnDuration; } /** * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation, * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1. * * @param maxConnLifetimeMillis * The maximum lifetime in milliseconds. * @deprecated Use {@link #setMaxConn(Duration)}. */ @Deprecated public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { this.maxConnDuration = Duration.ofMillis(maxConnLifetimeMillis); } /** * Sets the maximum number of open prepared statements. * * @param maxOpenPreparedStatements * The maximum number of open prepared statements. */ public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) { this.maxOpenPreparedStatements = maxOpenPreparedStatements; } /** * Deprecated due to typo in method name. * * @param maxOpenPreparedStatements * The maximum number of open prepared statements. * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}. */ @Deprecated // Due to typo in method name. public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) { setMaxOpenPreparedStatements(maxOpenPreparedStatements); } /** * Sets the {@link ObjectPool} in which to pool {@link Connection}s. * * @param pool * the {@link ObjectPool} in which to pool those {@link Connection}s */ public synchronized void setPool(final ObjectPool pool) { if (null != this.pool && pool != this.pool) { Utils.closeQuietly(this.pool); } this.pool = pool; } public void setPoolStatements(final boolean poolStatements) { this.poolStatements = poolStatements; } public void setRollbackOnReturn(final boolean rollbackOnReturn) { this.rollbackOnReturn = rollbackOnReturn; } /** * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If * not specified, {@link Connection#isValid(int)} will be used to validate connections. * * @param validationQuery * a query to use to {@link #validateObject validate} {@link Connection}s. */ public void setValidationQuery(final String validationQuery) { this.validationQuery = validationQuery; } /** * Sets the validation query timeout, the amount of time, that connection validation will wait for a response from the * database when executing a validation query. Use a value less than or equal to 0 for no timeout. * * @param validationQueryTimeoutDuration new validation query timeout duration. * @since 2.10.0 */ public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) { this.validationQueryTimeoutDuration = validationQueryTimeoutDuration; } /** * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout. * * @param validationQueryTimeoutSeconds * new validation query timeout value in seconds * @deprecated {@link #setValidationQueryTimeout(Duration)}. */ @Deprecated public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds); } /** * Validates the given connection if it is open. * * @param conn the connection to validate. * @throws SQLException if the connection is closed or validate fails. */ public void validateConnection(final PoolableConnection conn) throws SQLException { if (conn.isClosed()) { throw new SQLException("validateConnection: connection closed"); } conn.validate(validationQuery, validationQueryTimeoutDuration); } private void validateLifetime(final PooledObject p) throws LifetimeExceededException { Utils.validateLifetime(p, maxConnDuration); } @Override public boolean validateObject(final PooledObject p) { try { validateLifetime(p); validateConnection(p.getObject()); return true; } catch (final Exception e) { if (log.isDebugEnabled()) { log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e); } return false; } } } PoolableConnectionMXBean.java000066400000000000000000000037411447311732500340330ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.SQLException; /** * Defines the attributes and methods that will be exposed via JMX for {@link PoolableConnection} instances. * * @since 2.0 */ public interface PoolableConnectionMXBean { void clearCachedState(); void clearWarnings() throws SQLException; void close() throws SQLException; boolean getAutoCommit() throws SQLException; boolean getCacheState(); String getCatalog() throws SQLException; int getHoldability() throws SQLException; String getSchema() throws SQLException; String getToString(); int getTransactionIsolation() throws SQLException; boolean isClosed() throws SQLException; boolean isReadOnly() throws SQLException; void reallyClose() throws SQLException; void setAutoCommit(boolean autoCommit) throws SQLException; void setCacheState(boolean cacheState); void setCatalog(String catalog) throws SQLException; void setHoldability(int holdability) throws SQLException; void setReadOnly(boolean readOnly) throws SQLException; void setSchema(String schema) throws SQLException; void setTransactionIsolation(int level) throws SQLException; } PoolablePreparedStatement.java000066400000000000000000000073021447311732500343250ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.PreparedStatement; import java.sql.SQLException; import org.apache.commons.pool2.KeyedObjectPool; /** * A {@link DelegatingPreparedStatement} that cooperates with {@link PoolingConnection} to implement a pool of * {@link PreparedStatement}s. *

* My {@link #close} method returns me to my containing pool. (See {@link PoolingConnection}.) *

* * @param * the key type * * @see PoolingConnection * @since 2.0 */ public class PoolablePreparedStatement extends DelegatingPreparedStatement { /** * The {@link KeyedObjectPool} from which I was obtained. */ private final KeyedObjectPool> pool; /** * My "key" as used by {@link KeyedObjectPool}. */ private final K key; private volatile boolean batchAdded; /** * Constructor. * * @param stmt * my underlying {@link PreparedStatement} * @param key * my key as used by {@link KeyedObjectPool} * @param pool * the {@link KeyedObjectPool} from which I was obtained. * @param conn * the {@link java.sql.Connection Connection} from which I was created */ public PoolablePreparedStatement(final PreparedStatement stmt, final K key, final KeyedObjectPool> pool, final DelegatingConnection conn) { super(conn, stmt); this.pool = pool; this.key = key; // Remove from trace now because this statement will be // added by the activate method. removeThisTrace(conn); } @Override public void activate() throws SQLException { setClosedInternal(false); AbandonedTrace.add(getConnectionInternal(), this); super.activate(); } /** * Add batch. */ @Override public void addBatch() throws SQLException { super.addBatch(); batchAdded = true; } /** * Clear Batch. */ @Override public void clearBatch() throws SQLException { batchAdded = false; super.clearBatch(); } /** * Return me to my pool. */ @Override public void close() throws SQLException { // calling close twice should have no effect if (!isClosed()) { try { pool.returnObject(key, this); } catch (final SQLException | RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot close preparedstatement (return to pool failed)", e); } } } @Override public void passivate() throws SQLException { // DBCP-372. clearBatch with throw an exception if called when the // connection is marked as closed. if (batchAdded) { clearBatch(); } prepareToReturn(); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/PoolingConnection.java000066400000000000000000000547731447311732500327440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.NoSuchElementException; import java.util.Objects; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.KeyedPooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; /** * A {@link DelegatingConnection} that pools {@link PreparedStatement}s. *

* The {@link #prepareStatement} and {@link #prepareCall} methods, rather than creating a new PreparedStatement each * time, may actually pull the statement from a pool of unused statements. The {@link PreparedStatement#close} method of * the returned statement doesn't actually close the statement, but rather returns it to the pool. (See * {@link PoolablePreparedStatement}, {@link PoolableCallableStatement}.) *

* * @see PoolablePreparedStatement * @since 2.0 */ public class PoolingConnection extends DelegatingConnection implements KeyedPooledObjectFactory { /** * Statement types. * * @since 2.0 protected enum. * @since 2.4.0 public enum. */ public enum StatementType { /** * Callable statement. */ CALLABLE_STATEMENT, /** * Prepared statement. */ PREPARED_STATEMENT } /** Pool of {@link PreparedStatement}s. and {@link CallableStatement}s */ private KeyedObjectPool pStmtPool; private boolean clearStatementPoolOnReturn; /** * Constructor. * * @param connection * the underlying {@link Connection}. */ public PoolingConnection(final Connection connection) { super(connection); } /** * {@link KeyedPooledObjectFactory} method for activating pooled statements. * * @param key * ignored * @param pooledObject * wrapped pooled statement to be activated */ @Override public void activateObject(final PStmtKey key, final PooledObject pooledObject) throws SQLException { pooledObject.getObject().activate(); } /** * Closes and frees all {@link PreparedStatement}s or {@link CallableStatement}s from the pool, and close the * underlying connection. */ @Override public synchronized void close() throws SQLException { try { if (null != pStmtPool) { final KeyedObjectPool oldPool = pStmtPool; pStmtPool = null; try { oldPool.close(); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot close connection", e); } } } finally { try { getDelegateInternal().close(); } finally { setClosedInternal(true); } } } /** * Notification from {@link PoolableConnection} that we returned to the pool. * * @throws SQLException when {@code clearStatementPoolOnReturn} is true and the statement pool could not be * cleared * @since 2.8.0 */ public void connectionReturnedToPool() throws SQLException { if (pStmtPool != null && clearStatementPoolOnReturn) { try { pStmtPool.clear(); } catch (final Exception e) { throw new SQLException("Error clearing statement pool", e); } } } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull()); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param autoGeneratedKeys * A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), autoGeneratedKeys); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * @param resultSetHoldability * result set holdability * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, resultSetHoldability); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * @param resultSetHoldability * result set holdability * @param statementType * statement type * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final StatementType statementType) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, resultSetHoldability, statementType); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * @param statementType * statement type * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final StatementType statementType) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, statementType); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param columnIndexes * An array of column indexes indicating the columns that should be returned from the inserted row or * rows. * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final int[] columnIndexes) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param statementType * statement type * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final StatementType statementType) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), statementType, null); } /** * Creates a PStmtKey for the given arguments. * * @param sql * the SQL string used to define the statement * @param columnNames * column names * * @return the PStmtKey created for the given arguments. */ protected PStmtKey createKey(final String sql, final String[] columnNames) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnNames); } /** * {@link KeyedPooledObjectFactory} method for destroying PoolablePreparedStatements and PoolableCallableStatements. * Closes the underlying statement. * * @param key * ignored * @param pooledObject * the wrapped pooled statement to be destroyed. */ @Override public void destroyObject(final PStmtKey key, final PooledObject pooledObject) throws SQLException { pooledObject.getObject().getInnermostDelegate().close(); } private String getCatalogOrNull() { try { return getCatalog(); } catch (final SQLException ignored) { return null; } } private String getSchemaOrNull() { try { return getSchema(); } catch (final SQLException ignored) { return null; } } /** * Gets the prepared statement pool. * * @return statement pool * @since 2.8.0 */ public KeyedObjectPool getStatementPool() { return pStmtPool; } /** * {@link KeyedPooledObjectFactory} method for creating {@link PoolablePreparedStatement}s or * {@link PoolableCallableStatement}s. The {@code stmtType} field in the key determines whether a * PoolablePreparedStatement or PoolableCallableStatement is created. * * @param key * the key for the {@link PreparedStatement} to be created * @see #createKey(String, int, int, StatementType) */ @SuppressWarnings("resource") @Override public PooledObject makeObject(final PStmtKey key) throws SQLException { if (null == key) { throw new IllegalArgumentException("Prepared statement key is null or invalid."); } if (key.getStmtType() == StatementType.PREPARED_STATEMENT) { final PreparedStatement statement = (PreparedStatement) key.createStatement(getDelegate()); @SuppressWarnings({"rawtypes", "unchecked" }) // Unable to find way to avoid this final PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, pStmtPool, this); return new DefaultPooledObject<>(pps); } final CallableStatement statement = (CallableStatement) key.createStatement(getDelegate()); final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, pStmtPool, this); return new DefaultPooledObject<>(pcs); } /** * Normalizes the given SQL statement, producing a canonical form that is semantically equivalent to the original. * * @param sql The statement to be normalized. * * @return The canonical form of the supplied SQL statement. */ protected String normalizeSQL(final String sql) { return sql.trim(); } /** * {@link KeyedPooledObjectFactory} method for passivating {@link PreparedStatement}s or {@link CallableStatement}s. * Invokes {@link PreparedStatement#clearParameters}. * * @param key * ignored * @param pooledObject * a wrapped {@link PreparedStatement} */ @Override public void passivateObject(final PStmtKey key, final PooledObject pooledObject) throws SQLException { @SuppressWarnings("resource") final DelegatingPreparedStatement dps = pooledObject.getObject(); dps.clearParameters(); dps.passivate(); } /** * Creates or obtains a {@link CallableStatement} from the pool. * * @param key * a {@link PStmtKey} for the given arguments * @return a {@link PoolableCallableStatement} * @throws SQLException * Wraps an underlying exception. */ private CallableStatement prepareCall(final PStmtKey key) throws SQLException { return (CallableStatement) prepareStatement(key); } /** * Creates or obtains a {@link CallableStatement} from the pool. * * @param sql * the SQL string used to define the CallableStatement * @return a {@link PoolableCallableStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public CallableStatement prepareCall(final String sql) throws SQLException { return prepareCall(createKey(sql, StatementType.CALLABLE_STATEMENT)); } /** * Creates or obtains a {@link CallableStatement} from the pool. * * @param sql * the SQL string used to define the CallableStatement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * @return a {@link PoolableCallableStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { return prepareCall(createKey(sql, resultSetType, resultSetConcurrency, StatementType.CALLABLE_STATEMENT)); } /** * Creates or obtains a {@link CallableStatement} from the pool. * * @param sql * the SQL string used to define the CallableStatement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * @param resultSetHoldability * result set holdability * @return a {@link PoolableCallableStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { return prepareCall(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.CALLABLE_STATEMENT)); } /** * Creates or obtains a {@link PreparedStatement} from the pool. * * @param key * a {@link PStmtKey} for the given arguments * @return a {@link PoolablePreparedStatement} * @throws SQLException * Wraps an underlying exception. */ private PreparedStatement prepareStatement(final PStmtKey key) throws SQLException { if (null == pStmtPool) { throw new SQLException("Statement pool is null - closed or invalid PoolingConnection."); } try { return pStmtPool.borrowObject(key); } catch (final NoSuchElementException e) { throw new SQLException("MaxOpenPreparedStatements limit reached", e); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareStatement from pool failed", e); } } /** * Creates or obtains a {@link PreparedStatement} from the pool. * * @param sql * the SQL string used to define the PreparedStatement * @return a {@link PoolablePreparedStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public PreparedStatement prepareStatement(final String sql) throws SQLException { return prepareStatement(createKey(sql)); } /* * Creates or obtains a {@link PreparedStatement} from the pool. * * @param sql * the SQL string used to define the PreparedStatement * @param autoGeneratedKeys * A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * @return a {@link PoolablePreparedStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { return prepareStatement(createKey(sql, autoGeneratedKeys)); } /** * Creates or obtains a {@link PreparedStatement} from the pool. * * @param sql * the SQL string used to define the PreparedStatement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * @return a {@link PoolablePreparedStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { return prepareStatement(createKey(sql, resultSetType, resultSetConcurrency)); } /** * Creates or obtains a {@link PreparedStatement} from the pool. * * @param sql * the SQL string used to define the PreparedStatement * @param resultSetType * result set type * @param resultSetConcurrency * result set concurrency * @param resultSetHoldability * result set holdability * @return a {@link PoolablePreparedStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { return prepareStatement(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); } /** * Creates or obtains a {@link PreparedStatement} from the pool. * * @param sql * the SQL string used to define the PreparedStatement * @param columnIndexes * An array of column indexes indicating the columns that should be returned from the inserted row or * rows. * @return a {@link PoolablePreparedStatement} * @throws SQLException * Wraps an underlying exception. * */ @Override public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { return prepareStatement(createKey(sql, columnIndexes)); } /** * Creates or obtains a {@link PreparedStatement} from the pool. * * @param sql * the SQL string used to define the PreparedStatement * @param columnNames * column names * @return a {@link PoolablePreparedStatement} * @throws SQLException * Wraps an underlying exception. */ @Override public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { return prepareStatement(createKey(sql, columnNames)); } /** * Sets whether the pool of statements should be cleared when the connection is returned to its pool. * Default is false. * * @param clearStatementPoolOnReturn clear or not * @since 2.8.0 */ public void setClearStatementPoolOnReturn(final boolean clearStatementPoolOnReturn) { this.clearStatementPoolOnReturn = clearStatementPoolOnReturn; } /** * Sets the prepared statement pool. * * @param pool * the prepared statement pool. */ public void setStatementPool(final KeyedObjectPool pool) { pStmtPool = pool; } @Override public synchronized String toString() { return "PoolingConnection: " + Objects.toString(pStmtPool); } /** * {@link KeyedPooledObjectFactory} method for validating pooled statements. Currently, always returns true. * * @param key * ignored * @param pooledObject * ignored * @return {@code true} */ @Override public boolean validateObject(final PStmtKey key, final PooledObject pooledObject) { return true; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/PoolingDataSource.java000066400000000000000000000203411447311732500326570ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.NoSuchElementException; import java.util.Objects; import java.util.logging.Logger; import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; /** * A simple {@link DataSource} implementation that obtains {@link Connection}s from the specified {@link ObjectPool}. * * @param * The connection type * * @since 2.0 */ public class PoolingDataSource implements DataSource, AutoCloseable { /** * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore. * * @since 2.0 */ private class PoolGuardConnectionWrapper extends DelegatingConnection { PoolGuardConnectionWrapper(final D delegate) { super(delegate); } @Override public void close() throws SQLException { if (getDelegateInternal() != null) { super.close(); super.setDelegate(null); } } /** * @see org.apache.commons.dbcp2.DelegatingConnection#getDelegate() */ @Override public D getDelegate() { return isAccessToUnderlyingConnectionAllowed() ? super.getDelegate() : null; } /** * @see org.apache.commons.dbcp2.DelegatingConnection#getInnermostDelegate() */ @Override public Connection getInnermostDelegate() { return isAccessToUnderlyingConnectionAllowed() ? super.getInnermostDelegate() : null; } @Override public boolean isClosed() throws SQLException { return getDelegateInternal() == null || super.isClosed(); } } private static final Log log = LogFactory.getLog(PoolingDataSource.class); /** Controls access to the underlying connection */ private boolean accessToUnderlyingConnectionAllowed; /** My log writer. */ private PrintWriter logWriter; private final ObjectPool pool; /** * Constructs a new instance backed by the given connection pool. * * @param pool * the given connection pool. */ public PoolingDataSource(final ObjectPool pool) { Objects.requireNonNull(pool, "Pool must not be null."); this.pool = pool; // Verify that pool's factory refers back to it. If not, log a warning and try to fix. if (this.pool instanceof GenericObjectPool) { final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ((GenericObjectPool) this.pool) .getFactory(); Objects.requireNonNull(pcf, "PoolableConnectionFactory must not be null."); if (pcf.getPool() != this.pool) { log.warn(Utils.getMessage("poolingDataSource.factoryConfig")); @SuppressWarnings("unchecked") // PCF must have a pool of PCs final ObjectPool p = (ObjectPool) this.pool; pcf.setPool(p); } } } /** * Closes and free all {@link Connection}s from the pool. * * @since 2.1 */ @Override public void close() throws SQLException { try { pool.close(); } catch (final Exception e) { throw new SQLException(Utils.getMessage("pool.close.fail"), e); } } /** * Returns a {@link java.sql.Connection} from my pool, according to the contract specified by * {@link ObjectPool#borrowObject}. */ @Override public Connection getConnection() throws SQLException { try { final C conn = pool.borrowObject(); if (conn == null) { return null; } return new PoolGuardConnectionWrapper<>(conn); } catch (final NoSuchElementException e) { throw new SQLException("Cannot get a connection, pool error " + e.getMessage(), e); } catch (final SQLException | RuntimeException e) { throw e; } catch (final InterruptedException e) { // Reset the interrupt status so it is visible to callers Thread.currentThread().interrupt(); throw new SQLException("Cannot get a connection, general error", e); } catch (final Exception e) { throw new SQLException("Cannot get a connection, general error", e); } } /** * Throws {@link UnsupportedOperationException} * * @throws UnsupportedOperationException * always thrown */ @Override public Connection getConnection(final String uname, final String passwd) throws SQLException { throw new UnsupportedOperationException(); } // --- DataSource methods ----------------------------------------- /** * Throws {@link UnsupportedOperationException}. * * @throws UnsupportedOperationException * As this implementation does not support this feature. */ @Override public int getLoginTimeout() { throw new UnsupportedOperationException("Login timeout is not supported."); } /** * Returns my log writer. * * @return my log writer * @see DataSource#getLogWriter */ @Override public PrintWriter getLogWriter() { return logWriter; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } protected ObjectPool getPool() { return pool; } /** * Returns the value of the accessToUnderlyingConnectionAllowed property. * * @return true if access to the underlying {@link Connection} is allowed, false otherwise. */ public boolean isAccessToUnderlyingConnectionAllowed() { return this.accessToUnderlyingConnectionAllowed; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { return iface != null && iface.isInstance(this); } /** * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to * the underlying connection. (Default: false) * * @param allow * Access to the underlying connection is granted when true. */ public void setAccessToUnderlyingConnectionAllowed(final boolean allow) { this.accessToUnderlyingConnectionAllowed = allow; } /** * Throws {@link UnsupportedOperationException}. * * @throws UnsupportedOperationException * As this implementation does not support this feature. */ @Override public void setLoginTimeout(final int seconds) { throw new UnsupportedOperationException("Login timeout is not supported."); } /** * Sets my log writer. * * @see DataSource#setLogWriter */ @Override public void setLogWriter(final PrintWriter out) { logWriter = out; } @Override public T unwrap(final Class iface) throws SQLException { if (isWrapperFor(iface)) { return iface.cast(this); } throw new SQLException(this + " is not a wrapper for " + iface); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/PoolingDriver.java000066400000000000000000000210651447311732500320640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.HashMap; import java.util.NoSuchElementException; import java.util.Properties; import java.util.logging.Logger; import org.apache.commons.pool2.ObjectPool; /** * A {@link Driver} implementation that obtains {@link Connection}s from a registered {@link ObjectPool}. * * @since 2.0 */ public class PoolingDriver implements Driver { /** * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore. * * @since 2.0 */ private class PoolGuardConnectionWrapper extends DelegatingConnection { private final ObjectPool pool; PoolGuardConnectionWrapper(final ObjectPool pool, final Connection delegate) { super(delegate); this.pool = pool; } /** * @see org.apache.commons.dbcp2.DelegatingConnection#getDelegate() */ @Override public Connection getDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return super.getDelegate(); } return null; } /** * @see org.apache.commons.dbcp2.DelegatingConnection#getInnermostDelegate() */ @Override public Connection getInnermostDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return super.getInnermostDelegate(); } return null; } } private static final DriverPropertyInfo[] EMPTY_DRIVER_PROPERTY_INFO_ARRAY = {}; /* Register myself with the {@link DriverManager}. */ static { try { DriverManager.registerDriver(new PoolingDriver()); } catch (final Exception ignored) { // Ignored } } /** The map of registered pools. */ protected static final HashMap> pools = new HashMap<>(); /** My URL prefix */ public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:"; protected static final int URL_PREFIX_LEN = URL_PREFIX.length(); // version numbers protected static final int MAJOR_VERSION = 1; protected static final int MINOR_VERSION = 0; /** Controls access to the underlying connection */ private final boolean accessToUnderlyingConnectionAllowed; /** * Constructs a new driver with {@code accessToUnderlyingConnectionAllowed} enabled. */ public PoolingDriver() { this(true); } /** * For unit testing purposes. * * @param accessToUnderlyingConnectionAllowed * Do {@link DelegatingConnection}s created by this driver permit access to the delegate? */ protected PoolingDriver(final boolean accessToUnderlyingConnectionAllowed) { this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed; } @Override public boolean acceptsURL(final String url) throws SQLException { return url != null && url.startsWith(URL_PREFIX); } /** * Closes a named pool. * * @param name * The pool name. * @throws SQLException * Thrown when a problem is caught closing the pool. */ public synchronized void closePool(final String name) throws SQLException { @SuppressWarnings("resource") final ObjectPool pool = pools.get(name); if (pool != null) { pools.remove(name); try { pool.close(); } catch (final Exception e) { throw new SQLException("Error closing pool " + name, e); } } } @Override public Connection connect(final String url, final Properties info) throws SQLException { if (acceptsURL(url)) { final ObjectPool pool = getConnectionPool(url.substring(URL_PREFIX_LEN)); try { final Connection conn = pool.borrowObject(); if (conn == null) { return null; } return new PoolGuardConnectionWrapper(pool, conn); } catch (final NoSuchElementException e) { throw new SQLException("Cannot get a connection, pool error: " + e.getMessage(), e); } catch (final SQLException | RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot get a connection, general error: " + e.getMessage(), e); } } return null; } /** * Gets the connection pool for the given name. * * @param name * The pool name * @return The pool * @throws SQLException * Thrown when the named pool is not registered. */ public synchronized ObjectPool getConnectionPool(final String name) throws SQLException { final ObjectPool pool = pools.get(name); if (null == pool) { throw new SQLException("Pool not registered: " + name); } return pool; } @Override public int getMajorVersion() { return MAJOR_VERSION; } @Override public int getMinorVersion() { return MINOR_VERSION; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } /** * Gets the pool names. * * @return the pool names. */ public synchronized String[] getPoolNames() { return pools.keySet().toArray(Utils.EMPTY_STRING_ARRAY); } @Override public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) { return EMPTY_DRIVER_PROPERTY_INFO_ARRAY; } /** * Invalidates the given connection. * * @param conn * connection to invalidate * @throws SQLException * if the connection is not a {@code PoolGuardConnectionWrapper} or an error occurs invalidating * the connection */ public void invalidateConnection(final Connection conn) throws SQLException { if (!(conn instanceof PoolGuardConnectionWrapper)) { throw new SQLException("Invalid connection class"); } final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn; @SuppressWarnings("unchecked") final ObjectPool pool = (ObjectPool) pgconn.pool; try { pool.invalidateObject(pgconn.getDelegateInternal()); } catch (final Exception ignored) { // Ignored. } } /** * Returns the value of the accessToUnderlyingConnectionAllowed property. * * @return true if access to the underlying is allowed, false otherwise. */ protected boolean isAccessToUnderlyingConnectionAllowed() { return accessToUnderlyingConnectionAllowed; } @Override public boolean jdbcCompliant() { return true; } /** * Registers a named pool. * * @param name * The pool name. * @param pool * The pool. */ public synchronized void registerPool(final String name, final ObjectPool pool) { pools.put(name, pool); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/SQLExceptionList.java000066400000000000000000000036251447311732500324550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.SQLException; import java.util.List; /** * An SQLException based on a list of Throwable causes. *

* The first exception in the list is used as this exception's cause and is accessible with the usual * {@link #getCause()} while the complete list is accessible with {@link #getCauseList()}. *

* * @since 2.7.0 */ public class SQLExceptionList extends SQLException { private static final long serialVersionUID = 1L; private final List causeList; /** * Creates a new exception caused by a list of exceptions. * * @param causeList a list of cause exceptions. */ public SQLExceptionList(final List causeList) { super(String.format("%,d exceptions: %s", causeList == null ? 0 : causeList.size(), causeList), causeList == null ? null : causeList.get(0)); this.causeList = causeList; } /** * Gets the cause list. * * @return The list of causes. */ public List getCauseList() { return causeList; } } SwallowedExceptionLogger.java000066400000000000000000000041471447311732500342040ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import org.apache.commons.logging.Log; import org.apache.commons.pool2.SwallowedExceptionListener; /** * Class for logging swallowed exceptions. * * @since 2.0 */ public class SwallowedExceptionLogger implements SwallowedExceptionListener { private final Log log; private final boolean logExpiredConnections; /** * Create a SwallowedExceptionLogger with the given logger. By default, expired connection logging is turned on. * * @param log * logger */ public SwallowedExceptionLogger(final Log log) { this(log, true); } /** * Create a SwallowedExceptionLogger with the given logger and expired connection logging property. * * @param log * logger * @param logExpiredConnections * false suppresses logging of expired connection events */ public SwallowedExceptionLogger(final Log log, final boolean logExpiredConnections) { this.log = log; this.logExpiredConnections = logExpiredConnections; } @Override public void onSwallowException(final Exception e) { if (logExpiredConnections || !(e instanceof LifetimeExceededException)) { log.warn(Utils.getMessage("swallowedExceptionLogger.onSwallowedException"), e); } } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/Utils.java000066400000000000000000000207471447311732500304070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.text.MessageFormat; import java.time.Duration; import java.time.Instant; import java.util.Collection; import java.util.HashSet; import java.util.Properties; import java.util.ResourceBundle; import java.util.Set; import java.util.function.Consumer; import org.apache.commons.pool2.PooledObject; /** * Utility methods. * * @since 2.0 */ public final class Utils { private static final ResourceBundle messages = ResourceBundle .getBundle(Utils.class.getPackage().getName() + ".LocalStrings"); /** * Whether the security manager is enabled. * * @deprecated No replacement. */ @Deprecated public static final boolean IS_SECURITY_ENABLED = isSecurityEnabled(); /** Any SQL_STATE starting with this value is considered a fatal disconnect */ public static final String DISCONNECTION_SQL_CODE_PREFIX = "08"; /** * SQL codes of fatal connection errors. *
    *
  • 57P01 (Admin shutdown)
  • *
  • 57P02 (Crash shutdown)
  • *
  • 57P03 (Cannot connect now)
  • *
  • 01002 (SQL92 disconnect error)
  • *
  • JZ0C0 (Sybase disconnect error)
  • *
  • JZ0C1 (Sybase disconnect error)
  • *
* @deprecated Use {@link #getDisconnectionSqlCodes()}. */ @Deprecated public static final Set DISCONNECTION_SQL_CODES; static final ResultSet[] EMPTY_RESULT_SET_ARRAY = {}; static final String[] EMPTY_STRING_ARRAY = {}; static { DISCONNECTION_SQL_CODES = new HashSet<>(); DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown DISCONNECTION_SQL_CODES.add("57P02"); // Crash shutdown DISCONNECTION_SQL_CODES.add("57P03"); // Cannot connect now DISCONNECTION_SQL_CODES.add("01002"); // SQL92 disconnect error DISCONNECTION_SQL_CODES.add("JZ0C0"); // Sybase disconnect error DISCONNECTION_SQL_CODES.add("JZ0C1"); // Sybase disconnect error } /** * Clones the given char[] if not null. * * @param value may be null. * @return a cloned char[] or null. */ public static char[] clone(final char[] value) { return value == null ? null : value.clone(); } /** * Clones the given {@link Properties} without the standard "user" or "password" entries. * * @param properties may be null * @return a clone of the input without the standard "user" or "password" entries. * @since 2.8.0 */ public static Properties cloneWithoutCredentials(final Properties properties) { if (properties != null) { final Properties temp = (Properties) properties.clone(); temp.remove(Constants.KEY_USER); temp.remove(Constants.KEY_PASSWORD); return temp; } return properties; } /** * Closes the given {@link AutoCloseable} and if an exception is caught, then calls {@code exceptionHandler}. * * @param autoCloseable The resource to close. * @param exceptionHandler Consumes exception thrown closing this resource. * @since 2.10.0 */ public static void close(AutoCloseable autoCloseable, final Consumer exceptionHandler) { if (autoCloseable != null) { try { autoCloseable.close(); } catch (final Exception e) { if (exceptionHandler != null) { exceptionHandler.accept(e); } } } } /** * Closes the AutoCloseable (which may be null). * * @param autoCloseable an AutoCloseable, may be {@code null} * @since 2.6.0 */ public static void closeQuietly(final AutoCloseable autoCloseable) { close(autoCloseable, null); } /** * Closes the Connection (which may be null). * * @param connection a Connection, may be {@code null} * @deprecated Use {@link #closeQuietly(AutoCloseable)}. */ @Deprecated public static void closeQuietly(final Connection connection) { closeQuietly((AutoCloseable) connection); } /** * Closes the ResultSet (which may be null). * * @param resultSet a ResultSet, may be {@code null} * @deprecated Use {@link #closeQuietly(AutoCloseable)}. */ @Deprecated public static void closeQuietly(final ResultSet resultSet) { closeQuietly((AutoCloseable) resultSet); } /** * Closes the Statement (which may be null). * * @param statement a Statement, may be {@code null}. * @deprecated Use {@link #closeQuietly(AutoCloseable)}. */ @Deprecated public static void closeQuietly(final Statement statement) { closeQuietly((AutoCloseable) statement); } /** * Gets a copy of SQL codes of fatal connection errors. *
    *
  • 57P01 (Admin shutdown)
  • *
  • 57P02 (Crash shutdown)
  • *
  • 57P03 (Cannot connect now)
  • *
  • 01002 (SQL92 disconnect error)
  • *
  • JZ0C0 (Sybase disconnect error)
  • *
  • JZ0C1 (Sybase disconnect error)
  • *
* @return SQL codes of fatal connection errors. * @since 2.10.0 */ public static Set getDisconnectionSqlCodes() { return new HashSet<>(DISCONNECTION_SQL_CODES); } /** * Gets the correct i18n message for the given key. * * @param key The key to look up an i18n message. * @return The i18n message. */ public static String getMessage(final String key) { return getMessage(key, (Object[]) null); } /** * Gets the correct i18n message for the given key with placeholders replaced by the supplied arguments. * * @param key A message key. * @param args The message arguments. * @return An i18n message. */ public static String getMessage(final String key, final Object... args) { final String msg = messages.getString(key); if (args == null || args.length == 0) { return msg; } final MessageFormat mf = new MessageFormat(msg); return mf.format(args, new StringBuffer(), null).toString(); } static boolean isEmpty(final Collection collection) { return collection == null || collection.isEmpty(); } static boolean isSecurityEnabled() { return System.getSecurityManager() != null; } /** * Converts the given String to a char[]. * * @param value may be null. * @return a char[] or null. */ public static char[] toCharArray(final String value) { return value != null ? value.toCharArray() : null; } /** * Converts the given char[] to a String. * * @param value may be null. * @return a String or null. */ public static String toString(final char[] value) { return value == null ? null : String.valueOf(value); } public static void validateLifetime(final PooledObject p, final Duration maxDuration) throws LifetimeExceededException { if (maxDuration.compareTo(Duration.ZERO) > 0) { final Duration lifetimeDuration = Duration.between(p.getCreateInstant(), Instant.now()); if (lifetimeDuration.compareTo(maxDuration) > 0) { throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded", lifetimeDuration, maxDuration)); } } } private Utils() { // not instantiable } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/cpdsadapter/000077500000000000000000000000001447311732500307245ustar00rootroot00000000000000ConnectionImpl.java000066400000000000000000000313161447311732500344350ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/cpdsadapter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.cpdsadapter; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import org.apache.commons.dbcp2.DelegatingCallableStatement; import org.apache.commons.dbcp2.DelegatingConnection; import org.apache.commons.dbcp2.DelegatingPreparedStatement; /** * This class is the {@code Connection} that will be returned from * {@code PooledConnectionImpl.getConnection()}. Most methods are wrappers around the JDBC 1.x * {@code Connection}. A few exceptions include preparedStatement and close. In accordance with the JDBC * specification this Connection cannot be used after closed() is called. Any further usage will result in an * SQLException. *

* ConnectionImpl extends DelegatingConnection to enable access to the underlying connection. *

* * @since 2.0 */ final class ConnectionImpl extends DelegatingConnection { private final boolean accessToUnderlyingConnectionAllowed; /** The object that instantiated this object */ private final PooledConnectionImpl pooledConnection; /** * Creates a {@code ConnectionImpl}. * * @param pooledConnection * The PooledConnection that is calling the ctor. * @param connection * The JDBC 1.x Connection to wrap. * @param accessToUnderlyingConnectionAllowed * if true, then access is allowed to the underlying connection */ ConnectionImpl(final PooledConnectionImpl pooledConnection, final Connection connection, final boolean accessToUnderlyingConnectionAllowed) { super(connection); this.pooledConnection = pooledConnection; this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed; } /** * Marks the Connection as closed, and notifies the pool that the pooled connection is available. *

* In accordance with the JDBC specification this Connection cannot be used after closed() is called. Any further * usage will result in an SQLException. *

* * @throws SQLException * The database connection couldn't be closed. */ @Override public void close() throws SQLException { if (!isClosedInternal()) { try { passivate(); } finally { setClosedInternal(true); pooledConnection.notifyListeners(); } } } /** * Get the delegated connection, if allowed. * * @return the internal connection, or null if access is not allowed. * @see #isAccessToUnderlyingConnectionAllowed() */ @Override public Connection getDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return getDelegateInternal(); } return null; } /** * Get the innermost connection, if allowed. * * @return the innermost internal connection, or null if access is not allowed. * @see #isAccessToUnderlyingConnectionAllowed() */ @Override public Connection getInnermostDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return super.getInnermostDelegateInternal(); } return null; } /** * If false, getDelegate() and getInnermostDelegate() will return null. * * @return true if access is allowed to the underlying connection * @see ConnectionImpl */ public boolean isAccessToUnderlyingConnectionAllowed() { return accessToUnderlyingConnectionAllowed; } /** * If pooling of {@code CallableStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * an SQL statement that may contain one or more '?' parameter placeholders. Typically, this statement is * specified using JDBC call escape syntax. * @return a default {@code CallableStatement} object containing the pre-compiled SQL statement. * @throws SQLException * Thrown if a database access error occurs or this method is called on a closed connection. * @since 2.4.0 */ @Override public CallableStatement prepareCall(final String sql) throws SQLException { checkOpen(); try { return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } /** * If pooling of {@code CallableStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * a {@code String} object that is the SQL statement to be sent to the database; may contain on or * more '?' parameters. * @param resultSetType * a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * a concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @return a {@code CallableStatement} object containing the pre-compiled SQL statement that will produce * {@code ResultSet} objects with the given type and concurrency. * @throws SQLException * Thrown if a database access error occurs, this method is called on a closed connection or the given * parameters are not {@code ResultSet} constants indicating type and concurrency. * @since 2.4.0 */ @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); try { return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } /** * If pooling of {@code CallableStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * a {@code String} object that is the SQL statement to be sent to the database; may contain on or * more '?' parameters. * @param resultSetType * one of the following {@code ResultSet} constants: {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * one of the following {@code ResultSet} constants: {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param resultSetHoldability * one of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @return a new {@code CallableStatement} object, containing the pre-compiled SQL statement, that will * generate {@code ResultSet} objects with the given type, concurrency, and holdability. * @throws SQLException * Thrown if a database access error occurs, this method is called on a closed connection or the given * parameters are not {@code ResultSet} constants indicating type, concurrency, and holdability. * @since 2.4.0 */ @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); try { return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } /** * If pooling of {@code PreparedStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * SQL statement to be prepared * @return the prepared statement * @throws SQLException * if this connection is closed or an error occurs in the wrapped connection. */ @Override public PreparedStatement prepareStatement(final String sql) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } @Override public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, autoGeneratedKeys)); } catch (final SQLException e) { handleException(e); return null; } } /** * If pooling of {@code PreparedStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @throws SQLException * if this connection is closed or an error occurs in the wrapped connection. */ @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency)); } catch (final SQLException e) { handleException(e); return null; } } // // Methods for accessing the delegate connection // @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); } catch (final SQLException e) { handleException(e); return null; } } @Override public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnIndexes)); } catch (final SQLException e) { handleException(e); return null; } } @Override public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnNames)); } catch (final SQLException e) { handleException(e); return null; } } } DriverAdapterCPDS.java000066400000000000000000001007021447311732500347160ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/cpdsadapter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.cpdsadapter; import java.io.PrintWriter; import java.io.Serializable; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.time.Duration; import java.util.Hashtable; import java.util.Properties; import java.util.logging.Logger; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.Referenceable; import javax.naming.StringRefAddr; import javax.naming.spi.ObjectFactory; import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; import org.apache.commons.dbcp2.Constants; import org.apache.commons.dbcp2.DelegatingPreparedStatement; import org.apache.commons.dbcp2.PStmtKey; import org.apache.commons.dbcp2.Utils; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.impl.BaseObjectPoolConfig; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; /** *

* An adapter for JDBC drivers that do not include an implementation of {@link javax.sql.ConnectionPoolDataSource}, but * still include a {@link java.sql.DriverManager} implementation. {@code ConnectionPoolDataSource}s are not used * within general applications. They are used by {@code DataSource} implementations that pool * {@code Connection}s, such as {@link org.apache.commons.dbcp2.datasources.SharedPoolDataSource}. A J2EE container * will normally provide some method of initializing the {@code ConnectionPoolDataSource} whose attributes are * presented as bean getters/setters and then deploying it via JNDI. It is then available as a source of physical * connections to the database, when the pooling {@code DataSource} needs to create a new physical connection. *

*

* Although normally used within a JNDI environment, the DriverAdapterCPDS can be instantiated and initialized as any * bean and then attached directly to a pooling {@code DataSource}. {@code Jdbc2PoolDataSource} can use the * {@code ConnectionPoolDataSource} with or without the use of JNDI. *

*

* The DriverAdapterCPDS also provides {@code PreparedStatement} pooling which is not generally available in jdbc2 * {@code ConnectionPoolDataSource} implementation, but is addressed within the jdbc3 specification. The * {@code PreparedStatement} pool in DriverAdapterCPDS has been in the dbcp package for some time, but it has not * undergone extensive testing in the configuration used here. It should be considered experimental and can be toggled * with the poolPreparedStatements attribute. *

*

* The package documentation contains an example using catalina and JNDI. The * datasources package documentation shows how to use * {@code DriverAdapterCPDS} as a source for {@code Jdbc2PoolDataSource} without the use of JNDI. *

* * @since 2.0 */ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceable, Serializable, ObjectFactory { private static final long serialVersionUID = -4820523787212147844L; private static final String GET_CONNECTION_CALLED = "A PooledConnection was already requested from this source, " + "further initialization is not allowed."; static { // Attempt to prevent deadlocks - see DBCP - 272 DriverManager.getDrivers(); } /** Description */ private String description; /** Connection string */ private String connectionString; /** User name */ private String userName; /** User password */ private char[] userPassword; /** Driver class name */ private String driver; /** Login TimeOut in seconds */ private int loginTimeout; /** Log stream. NOT USED */ private transient PrintWriter logWriter; // PreparedStatement pool properties private boolean poolPreparedStatements; private int maxIdle = 10; private Duration durationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS; private int numTestsPerEvictionRun = -1; private Duration minEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION; private int maxPreparedStatements = -1; /** Whether or not getConnection has been called */ private volatile boolean getConnectionCalled; /** Connection properties passed to JDBC Driver */ private Properties connectionProperties; /** * Controls access to the underlying connection */ private boolean accessToUnderlyingConnectionAllowed; /** * Default no-argument constructor for Serialization */ public DriverAdapterCPDS() { } /** * Throws an IllegalStateException, if a PooledConnection has already been requested. */ private void assertInitializationAllowed() throws IllegalStateException { if (getConnectionCalled) { throw new IllegalStateException(GET_CONNECTION_CALLED); } } private boolean getBooleanContentString(final RefAddr ra) { return Boolean.parseBoolean(getStringContent(ra)); } /** * Gets the connection properties passed to the JDBC driver. * * @return the JDBC connection properties used when creating connections. */ public Properties getConnectionProperties() { return connectionProperties; } /** * Gets the value of description. This property is here for use by the code which will deploy this data source. It * is not used internally. * * @return value of description, may be null. * @see #setDescription(String) */ public String getDescription() { return description; } /** * Gets the driver class name. * * @return value of driver. */ public String getDriver() { return driver; } /** * Gets the duration to sleep between runs of the idle object evictor thread. When non-positive, no * idle object evictor thread will be run. * * @return the value of the evictor thread timer * @see #setDurationBetweenEvictionRuns(Duration) * @since 2.9.0 */ public Duration getDurationBetweenEvictionRuns() { return durationBetweenEvictionRuns; } private int getIntegerStringContent(final RefAddr ra) { return Integer.parseInt(getStringContent(ra)); } /** * Gets the maximum time in seconds that this data source can wait while attempting to connect to a database. NOT * USED. */ @Override public int getLoginTimeout() { return loginTimeout; } /** * Gets the log writer for this data source. NOT USED. */ @Override public PrintWriter getLogWriter() { return logWriter; } /** * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or * negative for no limit. * * @return the value of maxIdle */ public int getMaxIdle() { return maxIdle; } /** * Gets the maximum number of prepared statements. * * @return maxPrepartedStatements value */ public int getMaxPreparedStatements() { return maxPreparedStatements; } /** * Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the * idle object evictor (if any). * * @see #setMinEvictableIdleDuration * @see #setDurationBetweenEvictionRuns * @return the minimum amount of time a statement may sit idle in the pool. * @since 2.9.0 */ public Duration getMinEvictableIdleDuration() { return minEvictableIdleDuration; } /** * Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the * idle object evictor (if any). * * @see #setMinEvictableIdleTimeMillis * @see #setTimeBetweenEvictionRunsMillis * @return the minimum amount of time a statement may sit idle in the pool. * @deprecated USe {@link #getMinEvictableIdleDuration()}. */ @Deprecated public int getMinEvictableIdleTimeMillis() { return (int) minEvictableIdleDuration.toMillis(); } /** * Gets the number of statements to examine during each run of the idle object evictor thread (if any.) * * @see #setNumTestsPerEvictionRun * @see #setTimeBetweenEvictionRunsMillis * @return the number of statements to examine during each run of the idle object evictor thread (if any.) */ public int getNumTestsPerEvictionRun() { return numTestsPerEvictionRun; } /** * Implements {@link ObjectFactory} to create an instance of this class */ @Override public Object getObjectInstance(final Object refObj, final Name name, final Context context, final Hashtable env) throws ClassNotFoundException { // The spec says to return null if we can't create an instance // of the reference DriverAdapterCPDS cpds = null; if (refObj instanceof Reference) { final Reference ref = (Reference) refObj; if (ref.getClassName().equals(getClass().getName())) { RefAddr ra = ref.get("description"); if (isNotEmpty(ra)) { setDescription(getStringContent(ra)); } ra = ref.get("driver"); if (isNotEmpty(ra)) { setDriver(getStringContent(ra)); } ra = ref.get("url"); if (isNotEmpty(ra)) { setUrl(getStringContent(ra)); } ra = ref.get(Constants.KEY_USER); if (isNotEmpty(ra)) { setUser(getStringContent(ra)); } ra = ref.get(Constants.KEY_PASSWORD); if (isNotEmpty(ra)) { setPassword(getStringContent(ra)); } ra = ref.get("poolPreparedStatements"); if (isNotEmpty(ra)) { setPoolPreparedStatements(getBooleanContentString(ra)); } ra = ref.get("maxIdle"); if (isNotEmpty(ra)) { setMaxIdle(getIntegerStringContent(ra)); } ra = ref.get("timeBetweenEvictionRunsMillis"); if (isNotEmpty(ra)) { setTimeBetweenEvictionRunsMillis(getIntegerStringContent(ra)); } ra = ref.get("numTestsPerEvictionRun"); if (isNotEmpty(ra)) { setNumTestsPerEvictionRun(getIntegerStringContent(ra)); } ra = ref.get("minEvictableIdleTimeMillis"); if (isNotEmpty(ra)) { setMinEvictableIdleTimeMillis(getIntegerStringContent(ra)); } ra = ref.get("maxPreparedStatements"); if (isNotEmpty(ra)) { setMaxPreparedStatements(getIntegerStringContent(ra)); } ra = ref.get("accessToUnderlyingConnectionAllowed"); if (isNotEmpty(ra)) { setAccessToUnderlyingConnectionAllowed(getBooleanContentString(ra)); } cpds = this; } } return cpds; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } /** * Gets the value of password for the default user. * * @return value of password. */ public String getPassword() { return Utils.toString(userPassword); } /** * Gets the value of password for the default user. * * @return value of password. * @since 2.4.0 */ public char[] getPasswordCharArray() { return Utils.clone(userPassword); } /** * Attempts to establish a database connection using the default user and password. */ @Override public PooledConnection getPooledConnection() throws SQLException { return getPooledConnection(getUser(), getPassword()); } /** * Attempts to establish a database connection. * * @param pooledUserName name to be used for the connection * @param pooledUserPassword password to be used fur the connection */ @Override public PooledConnection getPooledConnection(final String pooledUserName, final String pooledUserPassword) throws SQLException { getConnectionCalled = true; PooledConnectionImpl pooledConnection = null; // Workaround for buggy WebLogic 5.1 class loader - ignore the exception upon first invocation. try { if (connectionProperties != null) { update(connectionProperties, Constants.KEY_USER, pooledUserName); update(connectionProperties, Constants.KEY_PASSWORD, pooledUserPassword); pooledConnection = new PooledConnectionImpl( DriverManager.getConnection(getUrl(), connectionProperties)); } else { pooledConnection = new PooledConnectionImpl( DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword)); } pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); } catch (final ClassCircularityError e) { if (connectionProperties != null) { pooledConnection = new PooledConnectionImpl( DriverManager.getConnection(getUrl(), connectionProperties)); } else { pooledConnection = new PooledConnectionImpl( DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword)); } pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); } KeyedObjectPool stmtPool = null; if (isPoolPreparedStatements()) { final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig<>(); config.setMaxTotalPerKey(Integer.MAX_VALUE); config.setBlockWhenExhausted(false); config.setMaxWait(Duration.ZERO); config.setMaxIdlePerKey(getMaxIdle()); if (getMaxPreparedStatements() <= 0) { // Since there is no limit, create a prepared statement pool with an eviction thread; // evictor settings are the same as the connection pool settings. config.setTimeBetweenEvictionRuns(getDurationBetweenEvictionRuns()); config.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun()); config.setMinEvictableIdleTime(getMinEvictableIdleDuration()); } else { // Since there is a limit, create a prepared statement pool without an eviction thread; // pool has LRU functionality so when the limit is reached, 15% of the pool is cleared. // see org.apache.commons.pool2.impl.GenericKeyedObjectPool.clearOldest method config.setMaxTotal(getMaxPreparedStatements()); config.setTimeBetweenEvictionRuns(Duration.ofMillis(-1)); config.setNumTestsPerEvictionRun(0); config.setMinEvictableIdleTime(Duration.ZERO); } stmtPool = new GenericKeyedObjectPool<>(pooledConnection, config); pooledConnection.setStatementPool(stmtPool); } return pooledConnection; } /** * Implements {@link Referenceable}. */ @Override public Reference getReference() throws NamingException { // this class implements its own factory final String factory = getClass().getName(); final Reference ref = new Reference(getClass().getName(), factory, null); ref.add(new StringRefAddr("description", getDescription())); ref.add(new StringRefAddr("driver", getDriver())); ref.add(new StringRefAddr("loginTimeout", String.valueOf(getLoginTimeout()))); ref.add(new StringRefAddr(Constants.KEY_PASSWORD, getPassword())); ref.add(new StringRefAddr(Constants.KEY_USER, getUser())); ref.add(new StringRefAddr("url", getUrl())); ref.add(new StringRefAddr("poolPreparedStatements", String.valueOf(isPoolPreparedStatements()))); ref.add(new StringRefAddr("maxIdle", String.valueOf(getMaxIdle()))); ref.add(new StringRefAddr("numTestsPerEvictionRun", String.valueOf(getNumTestsPerEvictionRun()))); ref.add(new StringRefAddr("maxPreparedStatements", String.valueOf(getMaxPreparedStatements()))); // // Pair of current and deprecated. ref.add(new StringRefAddr("durationBetweenEvictionRuns", String.valueOf(getDurationBetweenEvictionRuns()))); ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", String.valueOf(getTimeBetweenEvictionRunsMillis()))); // // Pair of current and deprecated. ref.add(new StringRefAddr("minEvictableIdleDuration", String.valueOf(getMinEvictableIdleDuration()))); ref.add(new StringRefAddr("minEvictableIdleTimeMillis", String.valueOf(getMinEvictableIdleTimeMillis()))); return ref; } private String getStringContent(final RefAddr ra) { return ra.getContent().toString(); } /** * Gets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no * idle object evictor thread will be run. * * @return the value of the evictor thread timer * @see #setDurationBetweenEvictionRuns(Duration) * @deprecated Use {@link #getDurationBetweenEvictionRuns()}. */ @Deprecated public long getTimeBetweenEvictionRunsMillis() { return durationBetweenEvictionRuns.toMillis(); } /** * Gets the value of connection string used to locate the database for this data source. * * @return value of connection string. */ public String getUrl() { return connectionString; } /** * Gets the value of default user (login or user name). * * @return value of user. */ public String getUser() { return userName; } /** * Returns the value of the accessToUnderlyingConnectionAllowed property. * * @return true if access to the underlying is allowed, false otherwise. */ public synchronized boolean isAccessToUnderlyingConnectionAllowed() { return this.accessToUnderlyingConnectionAllowed; } private boolean isNotEmpty(final RefAddr ra) { return ra != null && ra.getContent() != null; } /** * Whether to toggle the pooling of {@code PreparedStatement}s * * @return value of poolPreparedStatements. */ public boolean isPoolPreparedStatements() { return poolPreparedStatements; } /** * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to * the underlying connection. (Default: false) * * @param allow Access to the underlying connection is granted when true. */ public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { this.accessToUnderlyingConnectionAllowed = allow; } /** * Sets the connection properties passed to the JDBC driver. *

* If {@code props} contains "user" and/or "password" properties, the corresponding instance properties are * set. If these properties are not present, they are filled in using {@link #getUser()}, {@link #getPassword()} * when {@link #getPooledConnection()} is called, or using the actual parameters to the method call when * {@link #getPooledConnection(String, String)} is called. Calls to {@link #setUser(String)} or * {@link #setPassword(String)} overwrite the values of these properties if {@code connectionProperties} is not * null. *

* * @param props Connection properties to use when creating new connections. * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setConnectionProperties(final Properties props) { assertInitializationAllowed(); connectionProperties = props; if (connectionProperties != null) { final String user = connectionProperties.getProperty(Constants.KEY_USER); if (user != null) { setUser(user); } final String password = connectionProperties.getProperty(Constants.KEY_PASSWORD); if (password != null) { setPassword(password); } } } /** * Sets the value of description. This property is here for use by the code which will deploy this datasource. It is * not used internally. * * @param description Value to assign to description. */ public void setDescription(final String description) { this.description = description; } /** * Sets the driver class name. Setting the driver class name cause the driver to be registered with the * DriverManager. * * @param driver Value to assign to driver. * @throws IllegalStateException if {@link #getPooledConnection()} has been called * @throws ClassNotFoundException if the class cannot be located */ public void setDriver(final String driver) throws ClassNotFoundException { assertInitializationAllowed(); this.driver = driver; // make sure driver is registered Class.forName(driver); } /** * Sets the duration to sleep between runs of the idle object evictor thread. When non-positive, no * idle object evictor thread will be run. * * @param durationBetweenEvictionRuns The duration to sleep between runs of the idle object evictor * thread. When non-positive, no idle object evictor thread will be run. * @see #getDurationBetweenEvictionRuns() * @throws IllegalStateException if {@link #getPooledConnection()} has been called * @since 2.9.0 */ public void setDurationBetweenEvictionRuns(final Duration durationBetweenEvictionRuns) { assertInitializationAllowed(); this.durationBetweenEvictionRuns = durationBetweenEvictionRuns; } /** * Sets the maximum time in seconds that this data source will wait while attempting to connect to a database. NOT * USED. */ @Override public void setLoginTimeout(final int seconds) { this.loginTimeout = seconds; } /** * Sets the log writer for this data source. NOT USED. */ @Override public void setLogWriter(final PrintWriter logWriter) { this.logWriter = logWriter; } /** * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or * negative for no limit. * * @param maxIdle The maximum number of statements that can remain idle * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setMaxIdle(final int maxIdle) { assertInitializationAllowed(); this.maxIdle = maxIdle; } /** * Sets the maximum number of prepared statements. * * @param maxPreparedStatements the new maximum number of prepared statements */ public void setMaxPreparedStatements(final int maxPreparedStatements) { this.maxPreparedStatements = maxPreparedStatements; } /** * Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the * idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone. * * @param minEvictableIdleDuration minimum time to set in milliseconds. * @see #getMinEvictableIdleDuration() * @see #setDurationBetweenEvictionRuns(Duration) * @throws IllegalStateException if {@link #getPooledConnection()} has been called. * @since 2.9.0 */ public void setMinEvictableIdleDuration(final Duration minEvictableIdleDuration) { assertInitializationAllowed(); this.minEvictableIdleDuration = minEvictableIdleDuration; } /** * Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the * idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone. * * @param minEvictableIdleTimeMillis minimum time to set in milliseconds. * @see #getMinEvictableIdleDuration() * @see #setDurationBetweenEvictionRuns(Duration) * @throws IllegalStateException if {@link #getPooledConnection()} has been called * @deprecated Use {@link #setMinEvictableIdleDuration(Duration)}. */ @Deprecated public void setMinEvictableIdleTimeMillis(final int minEvictableIdleTimeMillis) { assertInitializationAllowed(); this.minEvictableIdleDuration = Duration.ofMillis(minEvictableIdleTimeMillis); } /** * Sets the number of statements to examine during each run of the idle object evictor thread (if any). *

* When a negative value is supplied, * {@code ceil({@link BasicDataSource#getNumIdle})/abs({@link #getNumTestsPerEvictionRun})} tests will be run. * I.e., when the value is -n, roughly one nth of the idle objects will be tested per run. *

* * @param numTestsPerEvictionRun number of statements to examine per run * @see #getNumTestsPerEvictionRun() * @see #setDurationBetweenEvictionRuns(Duration) * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { assertInitializationAllowed(); this.numTestsPerEvictionRun = numTestsPerEvictionRun; } /** * Sets the value of password for the default user. * * @param userPassword Value to assign to password. * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setPassword(final char[] userPassword) { assertInitializationAllowed(); this.userPassword = Utils.clone(userPassword); update(connectionProperties, Constants.KEY_PASSWORD, Utils.toString(this.userPassword)); } /** * Sets the value of password for the default user. * * @param userPassword Value to assign to password. * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setPassword(final String userPassword) { assertInitializationAllowed(); this.userPassword = Utils.toCharArray(userPassword); update(connectionProperties, Constants.KEY_PASSWORD, userPassword); } /** * Whether to toggle the pooling of {@code PreparedStatement}s * * @param poolPreparedStatements true to pool statements. * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setPoolPreparedStatements(final boolean poolPreparedStatements) { assertInitializationAllowed(); this.poolPreparedStatements = poolPreparedStatements; } /** * Sets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no * idle object evictor thread will be run. * * @param timeBetweenEvictionRunsMillis The number of milliseconds to sleep between runs of the idle object evictor * thread. When non-positive, no idle object evictor thread will be run. * @see #getDurationBetweenEvictionRuns() * @throws IllegalStateException if {@link #getPooledConnection()} has been called * @deprecated Use {@link #setDurationBetweenEvictionRuns(Duration)}. */ @Deprecated public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { assertInitializationAllowed(); this.durationBetweenEvictionRuns = Duration.ofMillis(timeBetweenEvictionRunsMillis); } /** * Sets the value of URL string used to locate the database for this data source. * * @param connectionString Value to assign to connection string. * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setUrl(final String connectionString) { assertInitializationAllowed(); this.connectionString = connectionString; } /** * Sets the value of default user (login or user name). * * @param userName Value to assign to user. * @throws IllegalStateException if {@link #getPooledConnection()} has been called */ public void setUser(final String userName) { assertInitializationAllowed(); this.userName = userName; update(connectionProperties, Constants.KEY_USER, userName); } /** * Does not print the userName and userPassword field nor the 'user' or 'password' in the connectionProperties. * * @since 2.6.0 */ @Override public synchronized String toString() { final StringBuilder builder = new StringBuilder(super.toString()); builder.append("[description="); builder.append(description); builder.append(", connectionString="); // TODO What if the connection string contains a 'user' or 'password' query parameter but that connection string // is not in a legal URL format? builder.append(connectionString); builder.append(", driver="); builder.append(driver); builder.append(", loginTimeout="); builder.append(loginTimeout); builder.append(", poolPreparedStatements="); builder.append(poolPreparedStatements); builder.append(", maxIdle="); builder.append(maxIdle); builder.append(", timeBetweenEvictionRunsMillis="); builder.append(durationBetweenEvictionRuns); builder.append(", numTestsPerEvictionRun="); builder.append(numTestsPerEvictionRun); builder.append(", minEvictableIdleTimeMillis="); builder.append(minEvictableIdleDuration); builder.append(", maxPreparedStatements="); builder.append(maxPreparedStatements); builder.append(", getConnectionCalled="); builder.append(getConnectionCalled); builder.append(", connectionProperties="); builder.append(Utils.cloneWithoutCredentials(connectionProperties)); builder.append(", accessToUnderlyingConnectionAllowed="); builder.append(accessToUnderlyingConnectionAllowed); builder.append("]"); return builder.toString(); } private void update(final Properties properties, final String key, final String value) { if (properties != null && key != null) { if (value == null) { properties.remove(key); } else { properties.setProperty(key, value); } } } } PStmtKeyCPDS.java000066400000000000000000000103431447311732500337030ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/cpdsadapter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.cpdsadapter; import org.apache.commons.dbcp2.PStmtKey; /** * A key uniquely identifying a {@link java.sql.PreparedStatement PreparedStatement}. * * @since 2.0 * @deprecated Use {@link PStmtKey}. */ @Deprecated public class PStmtKeyCPDS extends PStmtKey { /** * Constructs a key to uniquely identify a prepared statement. * * @param sql * The SQL statement. */ public PStmtKeyCPDS(final String sql) { super(sql); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql * The SQL statement. * @param autoGeneratedKeys * A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. */ public PStmtKeyCPDS(final String sql, final int autoGeneratedKeys) { super(sql, null, autoGeneratedKeys); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql * The SQL statement. * @param resultSetType * A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. */ public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency) { super(sql, resultSetType, resultSetConcurrency); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql * The SQL statement. * @param resultSetType * a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE} * @param resultSetHoldability * One of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. */ public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { super(sql, null, resultSetType, resultSetConcurrency, resultSetHoldability); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql * The SQL statement. * @param columnIndexes * An array of column indexes indicating the columns that should be returned from the inserted row or * rows. */ public PStmtKeyCPDS(final String sql, final int[] columnIndexes) { super(sql, null, columnIndexes); } /** * Constructs a key to uniquely identify a prepared statement. * * @param sql * The SQL statement. * @param columnNames * An array of column names indicating the columns that should be returned from the inserted row or rows. */ public PStmtKeyCPDS(final String sql, final String[] columnNames) { super(sql, null, columnNames); } } PooledConnectionImpl.java000066400000000000000000000753271447311732500356120ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/cpdsadapter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.cpdsadapter; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.PooledConnection; import javax.sql.StatementEventListener; import org.apache.commons.dbcp2.DelegatingConnection; import org.apache.commons.dbcp2.DelegatingPreparedStatement; import org.apache.commons.dbcp2.Jdbc41Bridge; import org.apache.commons.dbcp2.PStmtKey; import org.apache.commons.dbcp2.PoolableCallableStatement; import org.apache.commons.dbcp2.PoolablePreparedStatement; import org.apache.commons.dbcp2.PoolingConnection.StatementType; import org.apache.commons.dbcp2.Utils; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.KeyedPooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; /** * Implementation of {@link PooledConnection} that is returned by {@link DriverAdapterCPDS}. * * @since 2.0 */ final class PooledConnectionImpl implements PooledConnection, KeyedPooledObjectFactory { private static final String CLOSED = "Attempted to use PooledConnection after closed() was called."; /** * The JDBC database connection that represents the physical db connection. */ private Connection connection; /** * A DelegatingConnection used to create a PoolablePreparedStatementStub. */ private final DelegatingConnection delegatingConnection; /** * The JDBC database logical connection. */ private Connection logicalConnection; /** * ConnectionEventListeners. */ private final List eventListeners; /** * StatementEventListeners. */ private final List statementEventListeners = Collections.synchronizedList(new ArrayList<>()); /** * Flag set to true, once {@link #close()} is called. */ private boolean closed; /** My pool of {@link PreparedStatement}s. */ private KeyedObjectPool pStmtPool; /** * Controls access to the underlying connection. */ private boolean accessToUnderlyingConnectionAllowed; /** * Wraps the real connection. * * @param connection * the connection to be wrapped. */ PooledConnectionImpl(final Connection connection) { this.connection = connection; if (connection instanceof DelegatingConnection) { this.delegatingConnection = (DelegatingConnection) connection; } else { this.delegatingConnection = new DelegatingConnection<>(connection); } eventListeners = Collections.synchronizedList(new ArrayList<>()); closed = false; } /** * My {@link KeyedPooledObjectFactory} method for activating {@link PreparedStatement}s. * * @param pooledObject Activates the underlying object. */ @Override public void activateObject(final PStmtKey key, final PooledObject pooledObject) throws SQLException { pooledObject.getObject().activate(); } /** * {@inheritDoc} */ @Override public void addConnectionEventListener(final ConnectionEventListener listener) { if (!eventListeners.contains(listener)) { eventListeners.add(listener); } } @Override public void addStatementEventListener(final StatementEventListener listener) { if (!statementEventListeners.contains(listener)) { statementEventListeners.add(listener); } } /** * Throws an SQLException, if isClosed is true */ private void assertOpen() throws SQLException { if (closed || connection == null) { throw new SQLException(CLOSED); } } /** * Closes the physical connection and marks this {@code PooledConnection} so that it may not be used to * generate any more logical {@code Connection}s. * * @throws SQLException * Thrown when an error occurs or the connection is already closed. */ @Override public void close() throws SQLException { assertOpen(); closed = true; try { if (pStmtPool != null) { try { pStmtPool.close(); } finally { pStmtPool = null; } } } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot close connection (return to pool failed)", e); } finally { try { connection.close(); } finally { connection = null; } } } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @return a {@link PStmtKey} for the given arguments. */ protected PStmtKey createKey(final String sql) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull()); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param autoGeneratedKeys * A flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), autoGeneratedKeys); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param resultSetType * A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param resultSetType * a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE} * @param resultSetHoldability * One of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, resultSetHoldability); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param resultSetType * a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE} * @param resultSetConcurrency * A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param resultSetHoldability * One of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @param statementType * The SQL statement type, prepared or callable. * @return a key to uniquely identify a prepared statement. * @since 2.4.0 */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final StatementType statementType) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, resultSetHoldability, statementType); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param resultSetType * A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param statementType * The SQL statement type, prepared or callable. * @return a key to uniquely identify a prepared statement. * @since 2.4.0 */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final StatementType statementType) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, statementType); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param columnIndexes * An array of column indexes indicating the columns that should be returned from the inserted row or * rows. * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int[] columnIndexes) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), columnIndexes); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param statementType * The SQL statement type, prepared or callable. * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final StatementType statementType) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), statementType); } /** * Creates a {@link PStmtKey} for the given arguments. * * @param sql * The SQL statement. * @param columnNames * An array of column names indicating the columns that should be returned from the inserted row or rows. * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final String[] columnNames) { return new PStmtKey(sql, getCatalogOrNull(), getSchemaOrNull(), columnNames); } /** * My {@link KeyedPooledObjectFactory} method for destroying {@link PreparedStatement}s. * * @param key * ignored * @param pooledObject * the wrapped {@link PreparedStatement} to be destroyed. */ @Override public void destroyObject(final PStmtKey key, final PooledObject pooledObject) throws SQLException { pooledObject.getObject().getInnermostDelegate().close(); } /** * Closes the physical connection and checks that the logical connection was closed as well. */ @Override protected void finalize() throws Throwable { // Closing the Connection ensures that if anyone tries to use it, // an error will occur. Utils.close(connection, null); // make sure the last connection is marked as closed if (logicalConnection != null && !logicalConnection.isClosed()) { throw new SQLException("PooledConnection was gc'ed, without its last Connection being closed."); } } private String getCatalogOrNull() { try { return connection == null ? null : connection.getCatalog(); } catch (final SQLException e) { return null; } } /** * Returns a JDBC connection. * * @return The database connection. * @throws SQLException * if the connection is not open or the previous logical connection is still open */ @Override public Connection getConnection() throws SQLException { assertOpen(); // make sure the last connection is marked as closed if (logicalConnection != null && !logicalConnection.isClosed()) { // should notify pool of error so the pooled connection can // be removed !FIXME! throw new SQLException("PooledConnection was reused, without its previous Connection being closed."); } // the spec requires that this return a new Connection instance. logicalConnection = new ConnectionImpl(this, connection, isAccessToUnderlyingConnectionAllowed()); return logicalConnection; } private Connection getRawConnection() throws SQLException { assertOpen(); return connection; } private String getSchemaOrNull() { try { return connection == null ? null : Jdbc41Bridge.getSchema(connection); } catch (final SQLException e) { return null; } } /** * Returns the value of the accessToUnderlyingConnectionAllowed property. * * @return true if access to the underlying is allowed, false otherwise. */ public synchronized boolean isAccessToUnderlyingConnectionAllowed() { return this.accessToUnderlyingConnectionAllowed; } /** * My {@link KeyedPooledObjectFactory} method for creating {@link PreparedStatement}s. * * @param key * The key for the {@link PreparedStatement} to be created. */ @SuppressWarnings("resource") @Override public PooledObject makeObject(final PStmtKey key) throws SQLException { if (null == key) { throw new IllegalArgumentException("Prepared statement key is null or invalid."); } if (key.getStmtType() == StatementType.PREPARED_STATEMENT) { final PreparedStatement statement = (PreparedStatement) key.createStatement(connection); @SuppressWarnings({"rawtypes", "unchecked" }) // Unable to find way to avoid this final PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, pStmtPool, delegatingConnection); return new DefaultPooledObject<>(pps); } final CallableStatement statement = (CallableStatement) key.createStatement(connection); @SuppressWarnings("unchecked") final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, pStmtPool, (DelegatingConnection) delegatingConnection); return new DefaultPooledObject<>(pcs); } /** * Sends a connectionClosed event. */ void notifyListeners() { final ConnectionEvent event = new ConnectionEvent(this); new ArrayList<>(eventListeners).forEach(listener -> listener.connectionClosed(event)); } /** * My {@link KeyedPooledObjectFactory} method for passivating {@link PreparedStatement}s. Currently, invokes * {@link PreparedStatement#clearParameters}. * * @param key * ignored * @param pooledObject * a wrapped {@link PreparedStatement} */ @Override public void passivateObject(final PStmtKey key, final PooledObject pooledObject) throws SQLException { @SuppressWarnings("resource") final DelegatingPreparedStatement dps = pooledObject.getObject(); dps.clearParameters(); dps.passivate(); } /** * Creates or obtains a {@link CallableStatement} from my pool. * * @param sql * an SQL statement that may contain one or more '?' parameter placeholders. Typically, this statement is * specified using JDBC call escape syntax. * @return a default {@code CallableStatement} object containing the pre-compiled SQL statement. * @throws SQLException * Thrown if a database access error occurs or this method is called on a closed connection. * @since 2.4.0 */ @SuppressWarnings("resource") // getRawConnection() does not allocate CallableStatement prepareCall(final String sql) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareCall(sql); } try { return (CallableStatement) pStmtPool.borrowObject(createKey(sql, StatementType.CALLABLE_STATEMENT)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareCall from pool failed", e); } } /** * Creates or obtains a {@link CallableStatement} from my pool. * * @param sql * a {@code String} object that is the SQL statement to be sent to the database; may contain on or * more '?' parameters. * @param resultSetType * a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * a concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @return a {@code CallableStatement} object containing the pre-compiled SQL statement that will produce * {@code ResultSet} objects with the given type and concurrency. * @throws SQLException * Thrown if a database access error occurs, this method is called on a closed connection or the given * parameters are not {@code ResultSet} constants indicating type and concurrency. * @since 2.4.0 */ @SuppressWarnings("resource") // getRawConnection() does not allocate CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareCall(sql, resultSetType, resultSetConcurrency); } try { return (CallableStatement) pStmtPool.borrowObject( createKey(sql, resultSetType, resultSetConcurrency, StatementType.CALLABLE_STATEMENT)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareCall from pool failed", e); } } /** * Creates or obtains a {@link CallableStatement} from my pool. * * @param sql * a {@code String} object that is the SQL statement to be sent to the database; may contain on or * more '?' parameters. * @param resultSetType * one of the following {@code ResultSet} constants: {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * one of the following {@code ResultSet} constants: {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * @param resultSetHoldability * one of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}. * @return a new {@code CallableStatement} object, containing the pre-compiled SQL statement, that will * generate {@code ResultSet} objects with the given type, concurrency, and holdability. * @throws SQLException * Thrown if a database access error occurs, this method is called on a closed connection or the given * parameters are not {@code ResultSet} constants indicating type, concurrency, and holdability. * @since 2.4.0 */ @SuppressWarnings("resource") // getRawConnection() does not allocate CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } try { return (CallableStatement) pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.CALLABLE_STATEMENT)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareCall from pool failed", e); } } /** * Creates or obtains a {@link PreparedStatement} from my pool. * * @param sql the SQL statement. * @return a {@link PoolablePreparedStatement} * @throws SQLException Thrown if a database access error occurs, this method is called on a closed connection, or * the borrow failed. */ @SuppressWarnings("resource") // getRawConnection() does not allocate PreparedStatement prepareStatement(final String sql) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareStatement(sql); } try { return pStmtPool.borrowObject(createKey(sql)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareStatement from pool failed", e); } } /** * Creates or obtains a {@link PreparedStatement} from my pool. * * @param sql * an SQL statement that may contain one or more '?' IN parameter placeholders. * @param autoGeneratedKeys * a flag indicating whether auto-generated keys should be returned; one of * {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}. * @return a {@link PoolablePreparedStatement} * @throws SQLException Thrown if a database access error occurs, this method is called on a closed connection, or * the borrow failed. * @see Connection#prepareStatement(String, int) */ @SuppressWarnings("resource") // getRawConnection() does not allocate PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareStatement(sql, autoGeneratedKeys); } try { return pStmtPool.borrowObject(createKey(sql, autoGeneratedKeys)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareStatement from pool failed", e); } } /** * Creates or obtains a {@link PreparedStatement} from my pool. * * @param sql * a {@code String} object that is the SQL statement to be sent to the database; may contain one or * more '?' IN parameters. * @param resultSetType * a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}. * @param resultSetConcurrency * a concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or * {@code ResultSet.CONCUR_UPDATABLE}. * * @return a {@link PoolablePreparedStatement}. * @throws SQLException Thrown if a database access error occurs, this method is called on a closed connection, or * the borrow failed. * @see Connection#prepareStatement(String, int, int) */ @SuppressWarnings("resource") // getRawConnection() does not allocate PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareStatement(sql, resultSetType, resultSetConcurrency); } try { return pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareStatement from pool failed", e); } } @SuppressWarnings("resource") // getRawConnection() does not allocate PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } try { return pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareStatement from pool failed", e); } } @SuppressWarnings("resource") // getRawConnection() does not allocate PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareStatement(sql, columnIndexes); } try { return pStmtPool.borrowObject(createKey(sql, columnIndexes)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareStatement from pool failed", e); } } @SuppressWarnings("resource") // getRawConnection() does not allocate PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { if (pStmtPool == null) { return getRawConnection().prepareStatement(sql, columnNames); } try { return pStmtPool.borrowObject(createKey(sql, columnNames)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Borrow prepareStatement from pool failed", e); } } /** * {@inheritDoc} */ @Override public void removeConnectionEventListener(final ConnectionEventListener listener) { eventListeners.remove(listener); } @Override public void removeStatementEventListener(final StatementEventListener listener) { statementEventListeners.remove(listener); } /** * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to * the underlying connection. (Default: false.) * * @param allow * Access to the underlying connection is granted when true. */ public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { this.accessToUnderlyingConnectionAllowed = allow; } public void setStatementPool(final KeyedObjectPool statementPool) { pStmtPool = statementPool; } /** * @since 2.6.0 */ @Override public synchronized String toString() { final StringBuilder builder = new StringBuilder(super.toString()); builder.append("[connection="); builder.append(connection); builder.append(", delegatingConnection="); builder.append(delegatingConnection); builder.append(", logicalConnection="); builder.append(logicalConnection); builder.append(", eventListeners="); builder.append(eventListeners); builder.append(", statementEventListeners="); builder.append(statementEventListeners); builder.append(", closed="); builder.append(closed); builder.append(", pStmtPool="); builder.append(pStmtPool); builder.append(", accessToUnderlyingConnectionAllowed="); builder.append(accessToUnderlyingConnectionAllowed); builder.append("]"); return builder.toString(); } /** * My {@link KeyedPooledObjectFactory} method for validating {@link PreparedStatement}s. * * @param key * Ignored. * @param pooledObject * Ignored. * @return {@code true} */ @Override public boolean validateObject(final PStmtKey key, final PooledObject pooledObject) { return true; } } package-info.java000066400000000000000000000060161447311732500340370ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/cpdsadapter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT 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 one public class which is a * {@code ConnectionPoolDataSource} (CPDS) implementation that can be used to * adapt older {@code Driver} based JDBC implementations. Below is an * example of setting up the CPDS to be available via JNDI in the * catalina servlet container. *

*

In server.xml, the following would be added to the <Context> for your * webapp: *

* *
 *  <Resource name="jdbc/bookstoreCPDS" auth="Container"
 *             type="org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS"/>
 *   <ResourceParams name="jdbc/bookstoreCPDS">
 *     <parameter>
 *       <name>factory</name>
 *       <value>org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS</value>
 *     </parameter>
 *         <parameter><name>user</name><value>root</value></parameter>
 *         <parameter><name>password</name><value></value></parameter>
 *         <parameter>
 *             <name>driver</name>
 *             <value>org.gjt.mm.mysql.Driver</value></parameter>
 *         <parameter>
 *              <name>url</name>
 *              <value>jdbc:mysql://localhost:3306/bookstore</value>
 *         </parameter>
 *   </ResourceParams>
 * 
* *

* In web.xml. Note that elements must be given in the order of the dtd * described in the servlet specification: *

* *
 * <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 server.xml file.
 *   </description>
 *   <res-ref-name>
 *     jdbc/bookstoreCPDS
 *   </res-ref-name>
 *   <res-type>
 *     org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS
 *   </res-type>
 *   <res-auth>
 *     Container
 *   </res-auth>
 * </resource-ref>
 * 
* *

* Catalina deploys all objects configured similarly to above within the * java:comp/env namespace. *

*/ package org.apache.commons.dbcp2.cpdsadapter; commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/000077500000000000000000000000001447311732500307475ustar00rootroot00000000000000CPDSConnectionFactory.java000066400000000000000000000476321447311732500356500ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; import org.apache.commons.dbcp2.Utils; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.DefaultPooledObject; /** * A {@link PooledObjectFactory} that creates {@link org.apache.commons.dbcp2.PoolableConnection PoolableConnection}s. * * @since 2.0 */ final class CPDSConnectionFactory implements PooledObjectFactory, ConnectionEventListener, PooledConnectionManager { private static final String NO_KEY_MESSAGE = "close() was called on a Connection, but I have no record of the underlying PooledConnection."; private final ConnectionPoolDataSource cpds; private final String validationQuery; private final Duration validationQueryTimeoutDuration; private final boolean rollbackAfterValidation; private ObjectPool pool; private UserPassKey userPassKey; private Duration maxConnDuration = Duration.ofMillis(-1); /** * Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated. */ private final Set validatingSet = Collections.newSetFromMap(new ConcurrentHashMap<>()); /** * Map of PooledConnectionAndInfo instances */ private final Map pcMap = new ConcurrentHashMap<>(); /** * Creates a new {@code PoolableConnectionFactory}. * * @param cpds * the ConnectionPoolDataSource from which to obtain PooledConnection's * @param validationQuery * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one * row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate * connections. * @param validationQueryTimeoutDuration * Timeout Duration before validation fails * @param rollbackAfterValidation * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s. * @param userName * The user name to use to create connections * @param userPassword * The password to use to create connections * @since 2.10.0 */ public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final Duration validationQueryTimeoutDuration, final boolean rollbackAfterValidation, final String userName, final char[] userPassword) { this.cpds = cpds; this.validationQuery = validationQuery; this.validationQueryTimeoutDuration = validationQueryTimeoutDuration; this.userPassKey = new UserPassKey(userName, userPassword); this.rollbackAfterValidation = rollbackAfterValidation; } /** * Creates a new {@code PoolableConnectionFactory}. * * @param cpds * the ConnectionPoolDataSource from which to obtain PooledConnection's * @param validationQuery * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one * row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate * connections. * @param validationQueryTimeoutDuration * Timeout in seconds before validation fails * @param rollbackAfterValidation * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s. * @param userName * The user name to use to create connections * @param userPassword * The password to use to create connections * @since 2.10.0 */ public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final Duration validationQueryTimeoutDuration, final boolean rollbackAfterValidation, final String userName, final String userPassword) { this(cpds, validationQuery, validationQueryTimeoutDuration, rollbackAfterValidation, userName, Utils.toCharArray(userPassword)); } /** * Creates a new {@code PoolableConnectionFactory}. * * @param cpds * the ConnectionPoolDataSource from which to obtain PooledConnection's * @param validationQuery * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one * row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate * connections. * @param validationQueryTimeoutSeconds * Timeout in seconds before validation fails * @param rollbackAfterValidation * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s. * @param userName * The user name to use to create connections * @param userPassword * The password to use to create connections * @since 2.4.0 * @deprecated Use {@link #CPDSConnectionFactory(ConnectionPoolDataSource, String, Duration, boolean, String, char[])}. */ @Deprecated public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName, final char[] userPassword) { this.cpds = cpds; this.validationQuery = validationQuery; this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds); this.userPassKey = new UserPassKey(userName, userPassword); this.rollbackAfterValidation = rollbackAfterValidation; } /** * Creates a new {@code PoolableConnectionFactory}. * * @param cpds * the ConnectionPoolDataSource from which to obtain PooledConnection's * @param validationQuery * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one * row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate * connections. * @param validationQueryTimeoutSeconds * Timeout in seconds before validation fails * @param rollbackAfterValidation * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s. * @param userName * The user name to use to create connections * @param userPassword * The password to use to create connections * @deprecated Use {@link #CPDSConnectionFactory(ConnectionPoolDataSource, String, Duration, boolean, String, String)}. */ @Deprecated public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName, final String userPassword) { this(cpds, validationQuery, validationQueryTimeoutSeconds, rollbackAfterValidation, userName, Utils.toCharArray(userPassword)); } @Override public void activateObject(final PooledObject p) throws SQLException { validateLifetime(p); } /** * Verifies that the user name matches the user whose connections are being managed by this factory and closes the * pool if this is the case; otherwise does nothing. */ @Override public void closePool(final String userName) throws SQLException { synchronized (this) { if (userName == null || !userName.equals(this.userPassKey.getUserName())) { return; } } try { pool.close(); } catch (final Exception ex) { throw new SQLException("Error closing connection pool", ex); } } /** * This will be called if the Connection returned by the getConnection method came from a PooledConnection, and the * user calls the close() method of this connection object. What we need to do here is to release this * PooledConnection from our pool... */ @Override public void connectionClosed(final ConnectionEvent event) { final PooledConnection pc = (PooledConnection) event.getSource(); // if this event occurred because we were validating, ignore it // otherwise return the connection to the pool. if (!validatingSet.contains(pc)) { final PooledConnectionAndInfo pci = pcMap.get(pc); if (pci == null) { throw new IllegalStateException(NO_KEY_MESSAGE); } try { pool.returnObject(pci); } catch (final Exception e) { System.err.println("CLOSING DOWN CONNECTION AS IT COULD " + "NOT BE RETURNED TO THE POOL"); pc.removeConnectionEventListener(this); try { doDestroyObject(pci); } catch (final Exception e2) { System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci); e2.printStackTrace(); } } } } /** * If a fatal error occurs, close the underlying physical connection so as not to be returned in the future */ @Override public void connectionErrorOccurred(final ConnectionEvent event) { final PooledConnection pc = (PooledConnection) event.getSource(); if (null != event.getSQLException()) { System.err.println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" + event.getSQLException() + ")"); } pc.removeConnectionEventListener(this); final PooledConnectionAndInfo pci = pcMap.get(pc); if (pci == null) { throw new IllegalStateException(NO_KEY_MESSAGE); } try { pool.invalidateObject(pci); } catch (final Exception e) { System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci); e.printStackTrace(); } } /** * Closes the PooledConnection and stops listening for events from it. */ @Override public void destroyObject(final PooledObject p) throws SQLException { doDestroyObject(p.getObject()); } private void doDestroyObject(final PooledConnectionAndInfo pci) throws SQLException { final PooledConnection pc = pci.getPooledConnection(); pc.removeConnectionEventListener(this); pcMap.remove(pc); pc.close(); } /** * (Testing API) Gets the value of password for the default user. * * @return value of password. */ char[] getPasswordCharArray() { return userPassKey.getPasswordCharArray(); } /** * Returns the object pool used to pool connections created by this factory. * * @return ObjectPool managing pooled connections */ public ObjectPool getPool() { return pool; } /** * Invalidates the PooledConnection in the pool. The CPDSConnectionFactory closes the connection and pool counters * are updated appropriately. Also closes the pool. This ensures that all idle connections are closed and * connections that are checked out are closed on return. */ @Override public void invalidate(final PooledConnection pc) throws SQLException { final PooledConnectionAndInfo pci = pcMap.get(pc); if (pci == null) { throw new IllegalStateException(NO_KEY_MESSAGE); } try { pool.invalidateObject(pci); // Destroy instance and update pool counters pool.close(); // Clear any other instances in this pool and kill others as they come back } catch (final Exception ex) { throw new SQLException("Error invalidating connection", ex); } } @Override public synchronized PooledObject makeObject() throws SQLException { PooledConnection pc = null; if (userPassKey.getUserName() == null) { pc = cpds.getPooledConnection(); } else { pc = cpds.getPooledConnection(userPassKey.getUserName(), userPassKey.getPassword()); } if (pc == null) { throw new IllegalStateException("Connection pool data source returned null from getPooledConnection"); } // should we add this object as a listener or the pool. // consider the validateObject method in decision pc.addConnectionEventListener(this); final PooledConnectionAndInfo pci = new PooledConnectionAndInfo(pc, userPassKey); pcMap.put(pc, pci); return new DefaultPooledObject<>(pci); } @Override public void passivateObject(final PooledObject p) throws SQLException { validateLifetime(p); } /** * Sets the maximum Duration of a connection after which the connection will always fail activation, * passivation and validation. * * @param maxConnDuration * A value of zero or less indicates an infinite lifetime. The default value is -1 milliseconds. * @since 2.10.0 */ public void setMaxConn(final Duration maxConnDuration) { this.maxConnDuration = maxConnDuration; } /** * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation, * passivation and validation. * * @param maxConnDuration * A value of zero or less indicates an infinite lifetime. The default value is -1 milliseconds. * @since 2.9.0 * @deprecated Use {@link #setMaxConn(Duration)}. */ @Deprecated public void setMaxConnLifetime(final Duration maxConnDuration) { this.maxConnDuration = maxConnDuration; } /** * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation, * passivation and validation. * * @param maxConnLifetimeMillis * A value of zero or less indicates an infinite lifetime. The default value is -1. * @deprecated Use {@link #setMaxConn(Duration)}. */ @Deprecated public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { setMaxConnLifetime(Duration.ofMillis(maxConnLifetimeMillis)); } /** * Sets the database password used when creating new connections. * * @param userPassword * new password */ public synchronized void setPassword(final char[] userPassword) { this.userPassKey = new UserPassKey(userPassKey.getUserName(), userPassword); } /** * Sets the database password used when creating new connections. * * @param userPassword * new password */ @Override public synchronized void setPassword(final String userPassword) { this.userPassKey = new UserPassKey(userPassKey.getUserName(), userPassword); } /** * * @param pool * the {@link ObjectPool} in which to pool those {@link Connection}s */ public void setPool(final ObjectPool pool) { this.pool = pool; } /** * @since 2.6.0 */ @Override public synchronized String toString() { final StringBuilder builder = new StringBuilder(super.toString()); builder.append("[cpds="); builder.append(cpds); builder.append(", validationQuery="); builder.append(validationQuery); builder.append(", validationQueryTimeoutDuration="); builder.append(validationQueryTimeoutDuration); builder.append(", rollbackAfterValidation="); builder.append(rollbackAfterValidation); builder.append(", pool="); builder.append(pool); builder.append(", maxConnDuration="); builder.append(maxConnDuration); builder.append(", validatingSet="); builder.append(validatingSet); builder.append(", pcMap="); builder.append(pcMap); builder.append("]"); return builder.toString(); } private void validateLifetime(final PooledObject p) throws SQLException { Utils.validateLifetime(p, maxConnDuration); } @Override public boolean validateObject(final PooledObject p) { try { validateLifetime(p); } catch (final Exception e) { return false; } boolean valid = false; final PooledConnection pconn = p.getObject().getPooledConnection(); Connection conn = null; validatingSet.add(pconn); if (null == validationQuery) { Duration timeoutDuration = validationQueryTimeoutDuration; if (timeoutDuration.isNegative()) { timeoutDuration = Duration.ZERO; } try { conn = pconn.getConnection(); valid = conn.isValid((int) timeoutDuration.getSeconds()); } catch (final SQLException e) { valid = false; } finally { Utils.closeQuietly((AutoCloseable) conn); validatingSet.remove(pconn); } } else { Statement stmt = null; ResultSet rset = null; // logical Connection from the PooledConnection must be closed // before another one can be requested and closing it will // generate an event. Keep track so we know not to return // the PooledConnection validatingSet.add(pconn); try { conn = pconn.getConnection(); stmt = conn.createStatement(); rset = stmt.executeQuery(validationQuery); valid = rset.next(); if (rollbackAfterValidation) { conn.rollback(); } } catch (final Exception e) { valid = false; } finally { Utils.closeQuietly((AutoCloseable) rset); Utils.closeQuietly((AutoCloseable) stmt); Utils.closeQuietly((AutoCloseable) conn); validatingSet.remove(pconn); } } return valid; } } CharArray.java000066400000000000000000000045201447311732500334100ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.Serializable; import java.util.Arrays; import org.apache.commons.dbcp2.Utils; /** * A {@code char} array wrapper that does not reveal its contents inadvertently through toString(). In contrast to, for * example, AtomicReference which toString()'s its contents. * * May contain null. * * @since 2.9.0 */ final class CharArray implements Serializable { private static final long serialVersionUID = 1L; static final CharArray NULL = new CharArray((char[]) null); private final char[] chars; CharArray(final char[] chars) { this.chars = Utils.clone(chars); } CharArray(final String string) { this.chars = Utils.toCharArray(string); } /** * Converts the value of char array as a String. * * @return value as a string, may be null. */ String asString() { return Utils.toString(chars); } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (!(obj instanceof CharArray)) { return false; } final CharArray other = (CharArray) obj; return Arrays.equals(chars, other.chars); } /** * Gets the value of char array. * * @return value, may be null. */ char[] get() { return Utils.clone(chars); } @Override public int hashCode() { return Arrays.hashCode(chars); } } InstanceKeyDataSource.java000066400000000000000000001541551447311732500357360ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.time.Duration; import java.util.Properties; import java.util.logging.Logger; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Referenceable; import javax.sql.ConnectionPoolDataSource; import javax.sql.DataSource; import javax.sql.PooledConnection; import org.apache.commons.dbcp2.Utils; import org.apache.commons.pool2.impl.BaseObjectPoolConfig; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; import org.apache.commons.pool2.impl.GenericObjectPool; /** *

* The base class for {@code SharedPoolDataSource} and {@code PerUserPoolDataSource}. Many of the * configuration properties are shared and defined here. This class is declared public in order to allow particular * usage with commons-beanutils; do not make direct use of it outside of commons-dbcp2. *

* *

* A J2EE container will normally provide some method of initializing the {@code DataSource} whose attributes are * presented as bean getters/setters and then deploying it via JNDI. It is then available to an application as a source * of pooled logical connections to the database. The pool needs a source of physical connections. This source is in the * form of a {@code ConnectionPoolDataSource} that can be specified via the {@link #setDataSourceName(String)} used * to lookup the source via JNDI. *

* *

* Although normally used within a JNDI environment, A DataSource can be instantiated and initialized as any bean. In * this case the {@code ConnectionPoolDataSource} will likely be instantiated in a similar manner. This class * allows the physical source of connections to be attached directly to this pool using the * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method. *

* *

* The dbcp package contains an adapter, {@link org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS}, that can be * used to allow the use of {@code DataSource}'s based on this class with JDBC driver implementations that do not * supply a {@code ConnectionPoolDataSource}, but still provide a {@link java.sql.Driver} implementation. *

* *

* The package documentation contains an example using Apache Tomcat and JNDI and it * also contains a non-JNDI example. *

* * @since 2.0 */ public abstract class InstanceKeyDataSource implements DataSource, Referenceable, Serializable, AutoCloseable { private static final long serialVersionUID = -6819270431752240878L; private static final String GET_CONNECTION_CALLED = "A Connection was already requested from this source, " + "further initialization is not allowed."; private static final String BAD_TRANSACTION_ISOLATION = "The requested TransactionIsolation level is invalid."; /** * Internal constant to indicate the level is not set. */ protected static final int UNKNOWN_TRANSACTIONISOLATION = -1; /** Guards property setters - once true, setters throw IllegalStateException */ private volatile boolean getConnectionCalled; /** Underlying source of PooledConnections */ private ConnectionPoolDataSource dataSource; /** DataSource Name used to find the ConnectionPoolDataSource */ private String dataSourceName; /** Description */ private String description; /** Environment that may be used to set up a JNDI initial context. */ private Properties jndiEnvironment; /** Login Timeout */ private Duration loginTimeoutDuration = Duration.ZERO; /** Log stream */ private PrintWriter logWriter; /** Instance key */ private String instanceKey; // Pool properties private boolean defaultBlockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED; private String defaultEvictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME; private boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO; private int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY; private int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; private Duration defaultMaxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT; private Duration defaultMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION; private int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY; private int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; private Duration defaultSoftMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION; private boolean defaultTestOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE; private boolean defaultTestOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW; private boolean defaultTestOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN; private boolean defaultTestWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE; private Duration defaultDurationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS; // Connection factory properties private String validationQuery; private Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1); private boolean rollbackAfterValidation; private Duration maxConnDuration = Duration.ofMillis(-1); // Connection properties private Boolean defaultAutoCommit; private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION; private Boolean defaultReadOnly; /** * Default no-arg constructor for Serialization. */ public InstanceKeyDataSource() { } /** * Throws an IllegalStateException, if a PooledConnection has already been requested. * * @throws IllegalStateException Thrown if a PooledConnection has already been requested. */ protected void assertInitializationAllowed() throws IllegalStateException { if (getConnectionCalled) { throw new IllegalStateException(GET_CONNECTION_CALLED); } } /** * Closes the connection pool being maintained by this datasource. */ @Override public abstract void close() throws SQLException; private void closeDueToException(final PooledConnectionAndInfo info) { if (info != null) { try { info.getPooledConnection().getConnection().close(); } catch (final Exception e) { // do not throw this exception because we are in the middle // of handling another exception. But record it because // it potentially leaks connections from the pool. getLogWriter().println("[ERROR] Could not return connection to pool during exception handling. " + e.getMessage()); } } } /** * Attempts to establish a database connection. */ @Override public Connection getConnection() throws SQLException { return getConnection(null, null); } /** * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the * provided user name and password. The password on the {@code PooledConnectionAndInfo} instance returned by * {@code getPooledConnectionAndInfo} is compared to the {@code password} parameter. If the comparison * fails, a database connection using the supplied user name and password is attempted. If the connection attempt * fails, an SQLException is thrown, indicating that the given password did not match the password used to create * the pooled connection. If the connection attempt succeeds, this means that the database password has been * changed. In this case, the {@code PooledConnectionAndInfo} instance retrieved with the old password is * destroyed and the {@code getPooledConnectionAndInfo} is repeatedly invoked until a * {@code PooledConnectionAndInfo} instance with the new password is returned. */ @Override public Connection getConnection(final String userName, final String userPassword) throws SQLException { if (instanceKey == null) { throw new SQLException("Must set the ConnectionPoolDataSource " + "through setDataSourceName or setConnectionPoolDataSource" + " before calling getConnection."); } getConnectionCalled = true; PooledConnectionAndInfo info = null; try { info = getPooledConnectionAndInfo(userName, userPassword); } catch (final RuntimeException | SQLException e) { closeDueToException(info); throw e; } catch (final Exception e) { closeDueToException(info); throw new SQLException("Cannot borrow connection from pool", e); } // Password on PooledConnectionAndInfo does not match if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) { try { // See if password has changed by attempting connection testCPDS(userName, userPassword); } catch (final SQLException ex) { // Password has not changed, so refuse client, but return connection to the pool closeDueToException(info); throw new SQLException( "Given password did not match password used" + " to create the PooledConnection.", ex); } catch (final javax.naming.NamingException ne) { throw new SQLException("NamingException encountered connecting to database", ne); } /* * Password must have changed -> destroy connection and keep retrying until we get a new, good one, * destroying any idle connections with the old password as we pull them from the pool. */ final UserPassKey upkey = info.getUserPassKey(); final PooledConnectionManager manager = getConnectionManager(upkey); // Destroy and remove from pool manager.invalidate(info.getPooledConnection()); // Reset the password on the factory if using CPDSConnectionFactory manager.setPassword(upkey.getPassword()); info = null; for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return try { info = getPooledConnectionAndInfo(userName, userPassword); } catch (final RuntimeException | SQLException e) { closeDueToException(info); throw e; } catch (final Exception e) { closeDueToException(info); throw new SQLException("Cannot borrow connection from pool", e); } if (info != null && userPassword != null && userPassword.equals(info.getPassword())) { break; } if (info != null) { manager.invalidate(info.getPooledConnection()); } info = null; } if (info == null) { throw new SQLException("Cannot borrow connection from pool - password change failure."); } } final Connection connection = info.getPooledConnection().getConnection(); try { setupDefaults(connection, userName); connection.clearWarnings(); return connection; } catch (final SQLException ex) { Utils.close(connection, e -> getLogWriter().println("ignoring exception during close: " + e)); throw ex; } } protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey); /** * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being * accessed via JNDI. * * @return value of connectionPoolDataSource. */ public ConnectionPoolDataSource getConnectionPoolDataSource() { return dataSource; } /** * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source * from a JNDI service provider. * * @return value of dataSourceName. */ public String getDataSourceName() { return dataSourceName; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user * pool. */ public boolean getDefaultBlockWhenExhausted() { return this.defaultBlockWhenExhausted; } /** * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool. * * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool. * @since 2.10.0 */ public Duration getDefaultDurationBetweenEvictionRuns() { return this.defaultDurationBetweenEvictionRuns; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user * pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user * pool. */ public String getDefaultEvictionPolicyClassName() { return this.defaultEvictionPolicyClassName; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. */ public boolean getDefaultLifo() { return this.defaultLifo; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. */ public int getDefaultMaxIdle() { return this.defaultMaxIdle; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. */ public int getDefaultMaxTotal() { return this.defaultMaxTotal; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool. * @since 2.9.0 */ public Duration getDefaultMaxWait() { return this.defaultMaxWaitDuration; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool. * @deprecated Use {@link #getDefaultMaxWait()}. */ @Deprecated public long getDefaultMaxWaitMillis() { return getDefaultMaxWait().toMillis(); } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user * pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per * user pool. * @since 2.10.0 */ public Duration getDefaultMinEvictableIdleDuration() { return this.defaultMinEvictableIdleDuration; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user * pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per * user pool. * @deprecated Use {@link #getDefaultMinEvictableIdleDuration()}. */ @Deprecated public long getDefaultMinEvictableIdleTimeMillis() { return this.defaultMinEvictableIdleDuration.toMillis(); } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. */ public int getDefaultMinIdle() { return this.defaultMinIdle; } /** * Gets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user * pool. * * @return The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user * pool. */ public int getDefaultNumTestsPerEvictionRun() { return this.defaultNumTestsPerEvictionRun; } /** * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * @since 2.10.0 */ public Duration getDefaultSoftMinEvictableIdleDuration() { return this.defaultSoftMinEvictableIdleDuration; } /** * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * @deprecated Use {@link #getDefaultSoftMinEvictableIdleDuration()}. */ @Deprecated public long getDefaultSoftMinEvictableIdleTimeMillis() { return this.defaultSoftMinEvictableIdleDuration.toMillis(); } /** * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnBorrow()} for each per user pool. * * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnBorrow()} for each per user pool. */ public boolean getDefaultTestOnBorrow() { return this.defaultTestOnBorrow; } /** * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnCreate()} for each per user pool. * * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnCreate()} for each per user pool. */ public boolean getDefaultTestOnCreate() { return this.defaultTestOnCreate; } /** * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnReturn()} for each per user pool. * * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnReturn()} for each per user pool. */ public boolean getDefaultTestOnReturn() { return this.defaultTestOnReturn; } /** * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestWhileIdle()} for each per user pool. * * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestWhileIdle()} for each per user pool. */ public boolean getDefaultTestWhileIdle() { return this.defaultTestWhileIdle; } /** * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool. * * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool. * @deprecated Use {@link #getDefaultDurationBetweenEvictionRuns()}. */ @Deprecated public long getDefaultTimeBetweenEvictionRunsMillis() { return this.defaultDurationBetweenEvictionRuns.toMillis(); } /** * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool. * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns * -1, the default is JDBC driver dependent. * * @return value of defaultTransactionIsolation. */ public int getDefaultTransactionIsolation() { return defaultTransactionIsolation; } /** * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the * datasource. It serves no internal purpose. * * @return value of description. */ public String getDescription() { return description; } /** * Gets the instance key. * * @return the instance key. */ protected String getInstanceKey() { return instanceKey; } /** * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is * used to locate the back end ConnectionPoolDataSource. * * @param key * JNDI environment key. * @return value of jndiEnvironment. */ public String getJndiEnvironment(final String key) { String value = null; if (jndiEnvironment != null) { value = jndiEnvironment.getProperty(key); } return value; } /** * Gets the value of loginTimeout. * * @return value of loginTimeout. * @deprecated Use {@link #getLoginTimeoutDuration()}. */ @Deprecated @Override public int getLoginTimeout() { return (int) loginTimeoutDuration.getSeconds(); } /** * Gets the value of loginTimeout. * * @return value of loginTimeout. * @since 2.10.0 */ public Duration getLoginTimeoutDuration() { return loginTimeoutDuration; } /** * Gets the value of logWriter. * * @return value of logWriter. */ @Override public PrintWriter getLogWriter() { if (logWriter == null) { logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8)); } return logWriter; } /** * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an * infinite lifetime. * * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an * infinite lifetime. * @since 2.10.0 */ public Duration getMaxConnDuration() { return maxConnDuration; } /** * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an * infinite lifetime. * * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an * infinite lifetime. * @deprecated Use {@link #getMaxConnDuration()}. */ @Deprecated public Duration getMaxConnLifetime() { return maxConnDuration; } /** * Gets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an * infinite lifetime. * * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an * infinite lifetime. * @deprecated Use {@link #getMaxConnLifetime()}. */ @Deprecated public long getMaxConnLifetimeMillis() { return maxConnDuration.toMillis(); } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } /** * This method is protected but can only be implemented in this package because PooledConnectionAndInfo is a package * private type. * * @param userName The user name. * @param userPassword The user password. * @return Matching PooledConnectionAndInfo. * @throws SQLException Connection or registration failure. */ protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword) throws SQLException; /** * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller. * If specified, this query MUST be an SQL SELECT statement that returns at least one row. If not * specified, {@link Connection#isValid(int)} will be used to validate connections. * * @return The SQL query that will be used to validate connections from this pool before returning them to the * caller. */ public String getValidationQuery() { return this.validationQuery; } /** * Returns the timeout in seconds before the validation query fails. * * @return The timeout in seconds before the validation query fails. * @deprecated Use {@link #getValidationQueryTimeoutDuration()}. */ @Deprecated public int getValidationQueryTimeout() { return (int) validationQueryTimeoutDuration.getSeconds(); } /** * Returns the timeout Duration before the validation query fails. * * @return The timeout Duration before the validation query fails. */ public Duration getValidationQueryTimeoutDuration() { return validationQueryTimeoutDuration; } /** * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is {@code null} which * will use the default value for the drive. * * @return value of defaultAutoCommit. */ public Boolean isDefaultAutoCommit() { return defaultAutoCommit; } /** * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value * can be changed on the Connection using Connection.setReadOnly(boolean). The default is {@code null} which * will use the default value for the drive. * * @return value of defaultReadOnly. */ public Boolean isDefaultReadOnly() { return defaultReadOnly; } /** * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from * this pool before returning them to the caller. * * @return true if a rollback will be issued after executing the validation query */ public boolean isRollbackAfterValidation() { return this.rollbackAfterValidation; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { return iface.isInstance(this); } /** * Sets the back end ConnectionPoolDataSource. This property should not be set if using JNDI to access the * data source. * * @param dataSource * Value to assign to connectionPoolDataSource. */ public void setConnectionPoolDataSource(final ConnectionPoolDataSource dataSource) { assertInitializationAllowed(); if (dataSourceName != null) { throw new IllegalStateException("Cannot set the DataSource, if JNDI is used."); } if (this.dataSource != null) { throw new IllegalStateException("The CPDS has already been set. It cannot be altered."); } this.dataSource = dataSource; instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this); } /** * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source * from a JNDI service provider. * * @param dataSourceName * Value to assign to dataSourceName. */ public void setDataSourceName(final String dataSourceName) { assertInitializationAllowed(); if (dataSource != null) { throw new IllegalStateException("Cannot set the JNDI name for the DataSource, if already " + "set using setConnectionPoolDataSource."); } if (this.dataSourceName != null) { throw new IllegalStateException("The DataSourceName has already been set. " + "It cannot be altered."); } this.dataSourceName = dataSourceName; instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this); } /** * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is {@code null} which * will use the default value for the drive. * * @param defaultAutoCommit * Value to assign to defaultAutoCommit. */ public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { assertInitializationAllowed(); this.defaultAutoCommit = defaultAutoCommit; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool. * * @param blockWhenExhausted * The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user * pool. */ public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) { assertInitializationAllowed(); this.defaultBlockWhenExhausted = blockWhenExhausted; } /** * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool. * * @param defaultDurationBetweenEvictionRuns The default value for * {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool. * @since 2.10.0 */ public void setDefaultDurationBetweenEvictionRuns(final Duration defaultDurationBetweenEvictionRuns) { assertInitializationAllowed(); this.defaultDurationBetweenEvictionRuns = defaultDurationBetweenEvictionRuns; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user * pool. * * @param evictionPolicyClassName * The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per * user pool. */ public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) { assertInitializationAllowed(); this.defaultEvictionPolicyClassName = evictionPolicyClassName; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. * * @param lifo * The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. */ public void setDefaultLifo(final boolean lifo) { assertInitializationAllowed(); this.defaultLifo = lifo; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. * * @param maxIdle * The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. */ public void setDefaultMaxIdle(final int maxIdle) { assertInitializationAllowed(); this.defaultMaxIdle = maxIdle; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. * * @param maxTotal * The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. */ public void setDefaultMaxTotal(final int maxTotal) { assertInitializationAllowed(); this.defaultMaxTotal = maxTotal; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool. * * @param maxWaitMillis * The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool. * @since 2.9.0 */ public void setDefaultMaxWait(final Duration maxWaitMillis) { assertInitializationAllowed(); this.defaultMaxWaitDuration = maxWaitMillis; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. * * @param maxWaitMillis * The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. * @deprecated Use {@link #setDefaultMaxWait(Duration)}. */ @Deprecated public void setDefaultMaxWaitMillis(final long maxWaitMillis) { setDefaultMaxWait(Duration.ofMillis(maxWaitMillis)); } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user * pool. * * @param defaultMinEvictableIdleDuration * The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each * per user pool. * @since 2.10.0 */ public void setDefaultMinEvictableIdle(final Duration defaultMinEvictableIdleDuration) { assertInitializationAllowed(); this.defaultMinEvictableIdleDuration = defaultMinEvictableIdleDuration; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user * pool. * * @param minEvictableIdleTimeMillis * The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each * per user pool. * @deprecated Use {@link #setDefaultMinEvictableIdle(Duration)}. */ @Deprecated public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) { assertInitializationAllowed(); this.defaultMinEvictableIdleDuration = Duration.ofMillis(minEvictableIdleTimeMillis); } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. * * @param minIdle * The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. */ public void setDefaultMinIdle(final int minIdle) { assertInitializationAllowed(); this.defaultMinIdle = minIdle; } /** * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user * pool. * * @param numTestsPerEvictionRun * The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per * user pool. */ public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { assertInitializationAllowed(); this.defaultNumTestsPerEvictionRun = numTestsPerEvictionRun; } /** * Sets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value * can be changed on the Connection using Connection.setReadOnly(boolean). The default is {@code null} which * will use the default value for the drive. * * @param defaultReadOnly * Value to assign to defaultReadOnly. */ public void setDefaultReadOnly(final Boolean defaultReadOnly) { assertInitializationAllowed(); this.defaultReadOnly = defaultReadOnly; } /** * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * * @param defaultSoftMinEvictableIdleDuration * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * @since 2.10.0 */ public void setDefaultSoftMinEvictableIdle(final Duration defaultSoftMinEvictableIdleDuration) { assertInitializationAllowed(); this.defaultSoftMinEvictableIdleDuration = defaultSoftMinEvictableIdleDuration; } /** * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * * @param softMinEvictableIdleTimeMillis * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. * @deprecated Use {@link #setDefaultSoftMinEvictableIdle(Duration)}. */ @Deprecated public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) { assertInitializationAllowed(); this.defaultSoftMinEvictableIdleDuration = Duration.ofMillis(softMinEvictableIdleTimeMillis); } /** * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnBorrow()} for each per user pool. * * @param testOnBorrow * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnBorrow()} for each per user pool. */ public void setDefaultTestOnBorrow(final boolean testOnBorrow) { assertInitializationAllowed(); this.defaultTestOnBorrow = testOnBorrow; } /** * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnCreate()} for each per user pool. * * @param testOnCreate * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnCreate()} for each per user pool. */ public void setDefaultTestOnCreate(final boolean testOnCreate) { assertInitializationAllowed(); this.defaultTestOnCreate = testOnCreate; } /** * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnReturn()} for each per user pool. * * @param testOnReturn * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestOnReturn()} for each per user pool. */ public void setDefaultTestOnReturn(final boolean testOnReturn) { assertInitializationAllowed(); this.defaultTestOnReturn = testOnReturn; } /** * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestWhileIdle()} for each per user pool. * * @param testWhileIdle * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool * GenericObjectPool#getTestWhileIdle()} for each per user pool. */ public void setDefaultTestWhileIdle(final boolean testWhileIdle) { assertInitializationAllowed(); this.defaultTestWhileIdle = testWhileIdle; } /** * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool. * * @param timeBetweenEvictionRunsMillis The default value for * {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool. * @deprecated Use {@link #setDefaultDurationBetweenEvictionRuns(Duration)}. */ @Deprecated public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { assertInitializationAllowed(); this.defaultDurationBetweenEvictionRuns = Duration.ofMillis(timeBetweenEvictionRunsMillis); } /** * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool. * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC * driver dependent. * * @param defaultTransactionIsolation * Value to assign to defaultTransactionIsolation */ public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { assertInitializationAllowed(); switch (defaultTransactionIsolation) { case Connection.TRANSACTION_NONE: case Connection.TRANSACTION_READ_COMMITTED: case Connection.TRANSACTION_READ_UNCOMMITTED: case Connection.TRANSACTION_REPEATABLE_READ: case Connection.TRANSACTION_SERIALIZABLE: break; default: throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION); } this.defaultTransactionIsolation = defaultTransactionIsolation; } /** * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the * datasource. It serves no internal purpose. * * @param description * Value to assign to description. */ public void setDescription(final String description) { this.description = description; } /** * Sets the JNDI environment to be used when instantiating a JNDI InitialContext. This InitialContext is used to * locate the back end ConnectionPoolDataSource. * * @param properties * the JNDI environment property to set which will overwrite any current settings */ void setJndiEnvironment(final Properties properties) { if (jndiEnvironment == null) { jndiEnvironment = new Properties(); } else { jndiEnvironment.clear(); } jndiEnvironment.putAll(properties); } /** * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This * InitialContext is used to locate the back end ConnectionPoolDataSource. * * @param key * the JNDI environment property to set. * @param value * the value assigned to specified JNDI environment property. */ public void setJndiEnvironment(final String key, final String value) { if (jndiEnvironment == null) { jndiEnvironment = new Properties(); } jndiEnvironment.setProperty(key, value); } /** * Sets the value of loginTimeout. * * @param loginTimeout * Value to assign to loginTimeout. * @since 2.10.0 */ public void setLoginTimeout(final Duration loginTimeout) { this.loginTimeoutDuration = loginTimeout; } /** * Sets the value of loginTimeout. * * @param loginTimeout * Value to assign to loginTimeout. * @deprecated Use {@link #setLoginTimeout(Duration)}. */ @Deprecated @Override public void setLoginTimeout(final int loginTimeout) { this.loginTimeoutDuration = Duration.ofSeconds(loginTimeout); } /** * Sets the value of logWriter. * * @param logWriter * Value to assign to logWriter. */ @Override public void setLogWriter(final PrintWriter logWriter) { this.logWriter = logWriter; } /** *

* Sets the maximum permitted lifetime of a connection. A value of zero or less indicates an * infinite lifetime. *

*

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param maxConnLifetimeMillis * The maximum permitted lifetime of a connection. A value of zero or less indicates an * infinite lifetime. * @since 2.9.0 */ public void setMaxConnLifetime(final Duration maxConnLifetimeMillis) { this.maxConnDuration = maxConnLifetimeMillis; } /** *

* Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an * infinite lifetime. *

*

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param maxConnLifetimeMillis * The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an * infinite lifetime. * @deprecated Use {@link #setMaxConnLifetime(Duration)}. */ @Deprecated public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { setMaxConnLifetime(Duration.ofMillis(maxConnLifetimeMillis)); } /** * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from * this pool before returning them to the caller. Default behavior is NOT to issue a rollback. The setting will only * have an effect if a validation query is set * * @param rollbackAfterValidation * new property value */ public void setRollbackAfterValidation(final boolean rollbackAfterValidation) { assertInitializationAllowed(); this.rollbackAfterValidation = rollbackAfterValidation; } protected abstract void setupDefaults(Connection connection, String userName) throws SQLException; /** * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller. * If specified, this query MUST be an SQL SELECT statement that returns at least one row. If not * specified, connections will be validated using {@link Connection#isValid(int)}. * * @param validationQuery * The SQL query that will be used to validate connections from this pool before returning them to the * caller. */ public void setValidationQuery(final String validationQuery) { assertInitializationAllowed(); this.validationQuery = validationQuery; } /** * Sets the timeout duration before the validation query fails. * * @param validationQueryTimeoutDuration * The new timeout duration. */ public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) { this.validationQueryTimeoutDuration = validationQueryTimeoutDuration; } /** * Sets the timeout in seconds before the validation query fails. * * @param validationQueryTimeoutSeconds * The new timeout in seconds * @deprecated Use {@link #setValidationQueryTimeout(Duration)}. */ @Deprecated public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds); } protected ConnectionPoolDataSource testCPDS(final String userName, final String userPassword) throws javax.naming.NamingException, SQLException { // The source of physical db connections ConnectionPoolDataSource cpds = this.dataSource; if (cpds == null) { Context ctx = null; if (jndiEnvironment == null) { ctx = new InitialContext(); } else { ctx = new InitialContext(jndiEnvironment); } final Object ds = ctx.lookup(dataSourceName); if (!(ds instanceof ConnectionPoolDataSource)) { throw new SQLException("Illegal configuration: " + "DataSource " + dataSourceName + " (" + ds.getClass().getName() + ")" + " doesn't implement javax.sql.ConnectionPoolDataSource"); } cpds = (ConnectionPoolDataSource) ds; } // try to get a connection with the supplied userName/password PooledConnection conn = null; try { if (userName != null) { conn = cpds.getPooledConnection(userName, userPassword); } else { conn = cpds.getPooledConnection(); } if (conn == null) { throw new SQLException("Cannot connect using the supplied userName/password"); } } finally { if (conn != null) { try { conn.close(); } catch (final SQLException ignored) { // at least we could connect } } } return cpds; } /** * @since 2.6.0 */ @Override public synchronized String toString() { final StringBuilder builder = new StringBuilder(super.toString()); builder.append('['); toStringFields(builder); builder.append(']'); return builder.toString(); } protected void toStringFields(final StringBuilder builder) { builder.append("getConnectionCalled="); builder.append(getConnectionCalled); builder.append(", dataSource="); builder.append(dataSource); builder.append(", dataSourceName="); builder.append(dataSourceName); builder.append(", description="); builder.append(description); builder.append(", jndiEnvironment="); builder.append(jndiEnvironment); builder.append(", loginTimeoutDuration="); builder.append(loginTimeoutDuration); builder.append(", logWriter="); builder.append(logWriter); builder.append(", instanceKey="); builder.append(instanceKey); builder.append(", defaultBlockWhenExhausted="); builder.append(defaultBlockWhenExhausted); builder.append(", defaultEvictionPolicyClassName="); builder.append(defaultEvictionPolicyClassName); builder.append(", defaultLifo="); builder.append(defaultLifo); builder.append(", defaultMaxIdle="); builder.append(defaultMaxIdle); builder.append(", defaultMaxTotal="); builder.append(defaultMaxTotal); builder.append(", defaultMaxWaitDuration="); builder.append(defaultMaxWaitDuration); builder.append(", defaultMinEvictableIdleDuration="); builder.append(defaultMinEvictableIdleDuration); builder.append(", defaultMinIdle="); builder.append(defaultMinIdle); builder.append(", defaultNumTestsPerEvictionRun="); builder.append(defaultNumTestsPerEvictionRun); builder.append(", defaultSoftMinEvictableIdleDuration="); builder.append(defaultSoftMinEvictableIdleDuration); builder.append(", defaultTestOnCreate="); builder.append(defaultTestOnCreate); builder.append(", defaultTestOnBorrow="); builder.append(defaultTestOnBorrow); builder.append(", defaultTestOnReturn="); builder.append(defaultTestOnReturn); builder.append(", defaultTestWhileIdle="); builder.append(defaultTestWhileIdle); builder.append(", defaultDurationBetweenEvictionRuns="); builder.append(defaultDurationBetweenEvictionRuns); builder.append(", validationQuery="); builder.append(validationQuery); builder.append(", validationQueryTimeoutDuration="); builder.append(validationQueryTimeoutDuration); builder.append(", rollbackAfterValidation="); builder.append(rollbackAfterValidation); builder.append(", maxConnDuration="); builder.append(maxConnDuration); builder.append(", defaultAutoCommit="); builder.append(defaultAutoCommit); builder.append(", defaultTransactionIsolation="); builder.append(defaultTransactionIsolation); builder.append(", defaultReadOnly="); builder.append(defaultReadOnly); } @Override @SuppressWarnings("unchecked") public T unwrap(final Class iface) throws SQLException { if (isWrapperFor(iface)) { return (T) this; } throw new SQLException(this + " is not a wrapper for " + iface); } } InstanceKeyDataSourceFactory.java000066400000000000000000000322071447311732500372570ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.time.Duration; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.commons.dbcp2.ListException; import org.apache.commons.dbcp2.Utils; /** * A JNDI ObjectFactory which creates {@code SharedPoolDataSource}s or {@code PerUserPoolDataSource}s * * @since 2.0 */ abstract class InstanceKeyDataSourceFactory implements ObjectFactory { private static final Map INSTANCE_MAP = new ConcurrentHashMap<>(); /** * Closes all pools associated with this class. * * @throws ListException * a {@link ListException} containing all exceptions thrown by {@link InstanceKeyDataSource#close()} * @see InstanceKeyDataSource#close() * @since 2.4.0 throws a {@link ListException} instead of, in 2.3.0 and before, the first exception thrown by * {@link InstanceKeyDataSource#close()}. */ public static void closeAll() throws ListException { // Get iterator to loop over all instances of this data source. final List exceptionList = new ArrayList<>(INSTANCE_MAP.size()); INSTANCE_MAP.entrySet().forEach(entry -> { // Bullet-proof to avoid anything else but problems from InstanceKeyDataSource#close(). if (entry != null) { @SuppressWarnings("resource") final InstanceKeyDataSource value = entry.getValue(); Utils.close(value, exceptionList::add); } }); INSTANCE_MAP.clear(); if (!exceptionList.isEmpty()) { throw new ListException("Could not close all InstanceKeyDataSource instances.", exceptionList); } } /** * Deserializes the provided byte array to create an object. * * @param data * Data to deserialize to create the configuration parameter. * * @return The Object created by deserializing the data. * * @throws ClassNotFoundException * If a class cannot be found during the deserialization of a configuration parameter. * @throws IOException * If an I/O error occurs during the deserialization of a configuration parameter. */ protected static final Object deserialize(final byte[] data) throws IOException, ClassNotFoundException { ObjectInputStream in = null; try { in = new ObjectInputStream(new ByteArrayInputStream(data)); return in.readObject(); } finally { Utils.closeQuietly(in); } } static synchronized String registerNewInstance(final InstanceKeyDataSource ds) { int max = 0; for (final String s : INSTANCE_MAP.keySet()) { if (s != null) { try { max = Math.max(max, Integer.parseInt(s)); } catch (final NumberFormatException ignored) { // no sweat, ignore those keys } } } final String instanceKey = String.valueOf(max + 1); // Put a placeholder here for now, so other instances will not // take our key. We will replace with a pool when ready. INSTANCE_MAP.put(instanceKey, ds); return instanceKey; } static void removeInstance(final String key) { if (key != null) { INSTANCE_MAP.remove(key); } } /** * Creates an instance of the subclass and sets any properties contained in the Reference. * * @param ref * The properties to be set on the created DataSource * * @return A configured DataSource of the appropriate type. * * @throws ClassNotFoundException * If a class cannot be found during the deserialization of a configuration parameter. * @throws IOException * If an I/O error occurs during the deserialization of a configuration parameter. */ protected abstract InstanceKeyDataSource getNewInstance(Reference ref) throws IOException, ClassNotFoundException; /** * Implements ObjectFactory to create an instance of SharedPoolDataSource or PerUserPoolDataSource */ @Override public Object getObjectInstance(final Object refObj, final Name name, final Context context, final Hashtable env) throws IOException, ClassNotFoundException { // The spec says to return null if we can't create an instance // of the reference Object obj = null; if (refObj instanceof Reference) { final Reference ref = (Reference) refObj; if (isCorrectClass(ref.getClassName())) { final RefAddr refAddr = ref.get("instanceKey"); if (refAddr != null && refAddr.getContent() != null) { // object was bound to JNDI via Referenceable API. obj = INSTANCE_MAP.get(refAddr.getContent()); } else { // Tomcat JNDI creates a Reference out of server.xml // configuration and passes it to an // instance of the factory given in server.xml. String key = null; if (name != null) { key = name.toString(); obj = INSTANCE_MAP.get(key); } if (obj == null) { final InstanceKeyDataSource ds = getNewInstance(ref); setCommonProperties(ref, ds); obj = ds; if (key != null) { INSTANCE_MAP.put(key, ds); } } } } } return obj; } /** * Tests if className is the value returned from getClass().getName().toString(). * * @param className * The class name to test. * * @return true if and only if className is the value returned from getClass().getName().toString() */ protected abstract boolean isCorrectClass(String className); boolean parseBoolean(final RefAddr refAddr) { return Boolean.parseBoolean(toString(refAddr)); } int parseInt(final RefAddr refAddr) { return Integer.parseInt(toString(refAddr)); } long parseLong(final RefAddr refAddr) { return Long.parseLong(toString(refAddr)); } private void setCommonProperties(final Reference ref, final InstanceKeyDataSource ikds) throws IOException, ClassNotFoundException { RefAddr refAddr = ref.get("dataSourceName"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDataSourceName(toString(refAddr)); } refAddr = ref.get("description"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDescription(toString(refAddr)); } refAddr = ref.get("jndiEnvironment"); if (refAddr != null && refAddr.getContent() != null) { final byte[] serialized = (byte[]) refAddr.getContent(); ikds.setJndiEnvironment((Properties) deserialize(serialized)); } refAddr = ref.get("loginTimeout"); if (refAddr != null && refAddr.getContent() != null) { ikds.setLoginTimeout(Duration.ofSeconds(parseInt(refAddr))); } // Pool properties refAddr = ref.get("blockWhenExhausted"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultBlockWhenExhausted(parseBoolean(refAddr)); } refAddr = ref.get("evictionPolicyClassName"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultEvictionPolicyClassName(toString(refAddr)); } // Pool properties refAddr = ref.get("lifo"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultLifo(parseBoolean(refAddr)); } refAddr = ref.get("maxIdlePerKey"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultMaxIdle(parseInt(refAddr)); } refAddr = ref.get("maxTotalPerKey"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultMaxTotal(parseInt(refAddr)); } refAddr = ref.get("maxWaitMillis"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultMaxWait(Duration.ofMillis(parseLong(refAddr))); } refAddr = ref.get("minEvictableIdleTimeMillis"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultMinEvictableIdle(Duration.ofMillis(parseLong(refAddr))); } refAddr = ref.get("minIdlePerKey"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultMinIdle(parseInt(refAddr)); } refAddr = ref.get("numTestsPerEvictionRun"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultNumTestsPerEvictionRun(parseInt(refAddr)); } refAddr = ref.get("softMinEvictableIdleTimeMillis"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultSoftMinEvictableIdle(Duration.ofMillis(parseLong(refAddr))); } refAddr = ref.get("testOnCreate"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultTestOnCreate(parseBoolean(refAddr)); } refAddr = ref.get("testOnBorrow"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultTestOnBorrow(parseBoolean(refAddr)); } refAddr = ref.get("testOnReturn"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultTestOnReturn(parseBoolean(refAddr)); } refAddr = ref.get("testWhileIdle"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultTestWhileIdle(parseBoolean(refAddr)); } refAddr = ref.get("timeBetweenEvictionRunsMillis"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultDurationBetweenEvictionRuns(Duration.ofMillis(parseLong(refAddr))); } // Connection factory properties refAddr = ref.get("validationQuery"); if (refAddr != null && refAddr.getContent() != null) { ikds.setValidationQuery(toString(refAddr)); } refAddr = ref.get("validationQueryTimeout"); if (refAddr != null && refAddr.getContent() != null) { ikds.setValidationQueryTimeout(Duration.ofSeconds(parseInt(refAddr))); } refAddr = ref.get("rollbackAfterValidation"); if (refAddr != null && refAddr.getContent() != null) { ikds.setRollbackAfterValidation(parseBoolean(refAddr)); } refAddr = ref.get("maxConnLifetimeMillis"); if (refAddr != null && refAddr.getContent() != null) { ikds.setMaxConnLifetime(Duration.ofMillis(parseLong(refAddr))); } // Connection properties refAddr = ref.get("defaultAutoCommit"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultAutoCommit(Boolean.valueOf(toString(refAddr))); } refAddr = ref.get("defaultTransactionIsolation"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultTransactionIsolation(parseInt(refAddr)); } refAddr = ref.get("defaultReadOnly"); if (refAddr != null && refAddr.getContent() != null) { ikds.setDefaultReadOnly(Boolean.valueOf(toString(refAddr))); } } String toString(final RefAddr refAddr) { return refAddr.getContent().toString(); } } KeyedCPDSConnectionFactory.java000066400000000000000000000377731447311732500366370ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; import org.apache.commons.dbcp2.Utils; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.KeyedPooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; /** * A {@link KeyedPooledObjectFactory} that creates {@link org.apache.commons.dbcp2.PoolableConnection * PoolableConnection}s. * * @since 2.0 */ final class KeyedCPDSConnectionFactory implements KeyedPooledObjectFactory, ConnectionEventListener, PooledConnectionManager { private static final String NO_KEY_MESSAGE = "close() was called on a Connection, but " + "I have no record of the underlying PooledConnection."; private final ConnectionPoolDataSource cpds; private final String validationQuery; private final Duration validationQueryTimeoutDuration; private final boolean rollbackAfterValidation; private KeyedObjectPool pool; private Duration maxConnLifetime = Duration.ofMillis(-1); /** * Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated. */ private final Set validatingSet = Collections.newSetFromMap(new ConcurrentHashMap<>()); /** * Map of PooledConnectionAndInfo instances */ private final Map pcMap = new ConcurrentHashMap<>(); /** * Creates a new {@code KeyedPoolableConnectionFactory}. * * @param cpds * the ConnectionPoolDataSource from which to obtain PooledConnections * @param validationQuery * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one * row. May be {@code null} in which case3 {@link Connection#isValid(int)} will be used to validate * connections. * @param validationQueryTimeoutSeconds * The Duration to allow for the validation query to complete * @param rollbackAfterValidation * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s. * @since 2.10.0 */ public KeyedCPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final Duration validationQueryTimeoutSeconds, final boolean rollbackAfterValidation) { this.cpds = cpds; this.validationQuery = validationQuery; this.validationQueryTimeoutDuration = validationQueryTimeoutSeconds; this.rollbackAfterValidation = rollbackAfterValidation; } /** * Creates a new {@code KeyedPoolableConnectionFactory}. * * @param cpds * the ConnectionPoolDataSource from which to obtain PooledConnections * @param validationQuery * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one * row. May be {@code null} in which case3 {@link Connection#isValid(int)} will be used to validate * connections. * @param validationQueryTimeoutSeconds * The time, in seconds, to allow for the validation query to complete * @param rollbackAfterValidation * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s. * @deprecated Use {@link #KeyedCPDSConnectionFactory(ConnectionPoolDataSource, String, Duration, boolean)}. */ @Deprecated public KeyedCPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation) { this(cpds, validationQuery, Duration.ofSeconds(validationQueryTimeoutSeconds), rollbackAfterValidation); } @Override public void activateObject(final UserPassKey key, final PooledObject p) throws SQLException { validateLifetime(p); } /** * This implementation does not fully close the KeyedObjectPool, as this would affect all users. Instead, it clears * the pool associated with the given user. This method is not currently used. */ @Override public void closePool(final String userName) throws SQLException { try { pool.clear(new UserPassKey(userName)); } catch (final Exception ex) { throw new SQLException("Error closing connection pool", ex); } } /** * This will be called if the Connection returned by the getConnection method came from a PooledConnection, and the * user calls the close() method of this connection object. What we need to do here is to release this * PooledConnection from our pool... */ @Override public void connectionClosed(final ConnectionEvent event) { final PooledConnection pc = (PooledConnection) event.getSource(); // if this event occurred because we were validating, or if this // connection has been marked for removal, ignore it // otherwise return the connection to the pool. if (!validatingSet.contains(pc)) { final PooledConnectionAndInfo pci = pcMap.get(pc); if (pci == null) { throw new IllegalStateException(NO_KEY_MESSAGE); } try { pool.returnObject(pci.getUserPassKey(), pci); } catch (final Exception e) { System.err.println("CLOSING DOWN CONNECTION AS IT COULD " + "NOT BE RETURNED TO THE POOL"); pc.removeConnectionEventListener(this); try { pool.invalidateObject(pci.getUserPassKey(), pci); } catch (final Exception e3) { System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci); e3.printStackTrace(); } } } } /** * If a fatal error occurs, close the underlying physical connection so as not to be returned in the future */ @Override public void connectionErrorOccurred(final ConnectionEvent event) { final PooledConnection pc = (PooledConnection) event.getSource(); if (null != event.getSQLException()) { System.err.println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" + event.getSQLException() + ")"); } pc.removeConnectionEventListener(this); final PooledConnectionAndInfo info = pcMap.get(pc); if (info == null) { throw new IllegalStateException(NO_KEY_MESSAGE); } try { pool.invalidateObject(info.getUserPassKey(), info); } catch (final Exception e) { System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + info); e.printStackTrace(); } } /** * Closes the PooledConnection and stops listening for events from it. */ @Override public void destroyObject(final UserPassKey key, final PooledObject p) throws SQLException { final PooledConnection pooledConnection = p.getObject().getPooledConnection(); pooledConnection.removeConnectionEventListener(this); pcMap.remove(pooledConnection); pooledConnection.close(); } /** * Returns the keyed object pool used to pool connections created by this factory. * * @return KeyedObjectPool managing pooled connections */ public KeyedObjectPool getPool() { return pool; } /** * Invalidates the PooledConnection in the pool. The KeyedCPDSConnectionFactory closes the connection and pool * counters are updated appropriately. Also clears any idle instances associated with the user name that was used to * create the PooledConnection. Connections associated with this user are not affected, and they will not be * automatically closed on return to the pool. */ @Override public void invalidate(final PooledConnection pc) throws SQLException { final PooledConnectionAndInfo info = pcMap.get(pc); if (info == null) { throw new IllegalStateException(NO_KEY_MESSAGE); } final UserPassKey key = info.getUserPassKey(); try { pool.invalidateObject(key, info); // Destroy and update pool counters pool.clear(key); // Remove any idle instances with this key } catch (final Exception ex) { throw new SQLException("Error invalidating connection", ex); } } /** * Creates a new {@code PooledConnectionAndInfo} from the given {@code UserPassKey}. * * @param userPassKey * {@code UserPassKey} containing user credentials * @throws SQLException * if the connection could not be created. * @see org.apache.commons.pool2.KeyedPooledObjectFactory#makeObject(Object) */ @Override public synchronized PooledObject makeObject(final UserPassKey userPassKey) throws SQLException { PooledConnection pooledConnection = null; final String userName = userPassKey.getUserName(); final String password = userPassKey.getPassword(); if (userName == null) { pooledConnection = cpds.getPooledConnection(); } else { pooledConnection = cpds.getPooledConnection(userName, password); } if (pooledConnection == null) { throw new IllegalStateException("Connection pool data source returned null from getPooledConnection"); } // should we add this object as a listener or the pool. // consider the validateObject method in decision pooledConnection.addConnectionEventListener(this); final PooledConnectionAndInfo pci = new PooledConnectionAndInfo(pooledConnection, userPassKey); pcMap.put(pooledConnection, pci); return new DefaultPooledObject<>(pci); } @Override public void passivateObject(final UserPassKey key, final PooledObject p) throws SQLException { validateLifetime(p); } /** * Sets the maximum lifetime of a connection after which the connection will always fail activation, * passivation and validation. * * @param maxConnLifetimeMillis * A value of zero or less indicates an infinite lifetime. The default value is -1 milliseconds. * @since 2.10.0 */ public void setMaxConn(final Duration maxConnLifetimeMillis) { this.maxConnLifetime = maxConnLifetimeMillis; } /** * Sets the maximum lifetime of a connection after which the connection will always fail activation, * passivation and validation. * * @param maxConnLifetimeMillis * A value of zero or less indicates an infinite lifetime. The default value is -1 milliseconds. * @since 2.9.0 * @deprecated Use {@link #setMaxConn(Duration)}. */ @Deprecated public void setMaxConnLifetime(final Duration maxConnLifetimeMillis) { this.maxConnLifetime = maxConnLifetimeMillis; } /** * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation, * passivation and validation. * * @param maxConnLifetimeMillis * A value of zero or less indicates an infinite lifetime. The default value is -1. * @deprecated Use {@link #setMaxConnLifetime(Duration)}. */ @Deprecated public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { setMaxConn(Duration.ofMillis(maxConnLifetimeMillis)); } /** * Does nothing. This factory does not cache user credentials. */ @Override public void setPassword(final String password) { // Does nothing. This factory does not cache user credentials. } public void setPool(final KeyedObjectPool pool) { this.pool = pool; } private void validateLifetime(final PooledObject pooledObject) throws SQLException { Utils.validateLifetime(pooledObject, maxConnLifetime); } /** * Validates a pooled connection. * * @param key * ignored * @param pooledObject * wrapped {@code PooledConnectionAndInfo} containing the connection to validate * @return true if validation succeeds */ @Override public boolean validateObject(final UserPassKey key, final PooledObject pooledObject) { try { validateLifetime(pooledObject); } catch (final Exception e) { return false; } boolean valid = false; final PooledConnection pooledConn = pooledObject.getObject().getPooledConnection(); Connection conn = null; validatingSet.add(pooledConn); if (null == validationQuery) { Duration timeoutDuration = validationQueryTimeoutDuration; if (timeoutDuration.isNegative()) { timeoutDuration = Duration.ZERO; } try { conn = pooledConn.getConnection(); valid = conn.isValid((int) timeoutDuration.getSeconds()); } catch (final SQLException e) { valid = false; } finally { Utils.closeQuietly((AutoCloseable) conn); validatingSet.remove(pooledConn); } } else { Statement stmt = null; ResultSet rset = null; // logical Connection from the PooledConnection must be closed // before another one can be requested and closing it will // generate an event. Keep track so we know not to return // the PooledConnection validatingSet.add(pooledConn); try { conn = pooledConn.getConnection(); stmt = conn.createStatement(); rset = stmt.executeQuery(validationQuery); valid = rset.next(); if (rollbackAfterValidation) { conn.rollback(); } } catch (final Exception e) { valid = false; } finally { Utils.closeQuietly((AutoCloseable) rset); Utils.closeQuietly((AutoCloseable) stmt); Utils.closeQuietly((AutoCloseable) conn); validatingSet.remove(pooledConn); } } return valid; } } PerUserPoolDataSource.java000066400000000000000000001275531447311732500357420ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.IOException; import java.io.ObjectInputStream; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.sql.ConnectionPoolDataSource; import org.apache.commons.dbcp2.SwallowedExceptionLogger; import org.apache.commons.dbcp2.Utils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; /** *

* A pooling {@code DataSource} appropriate for deployment within J2EE environment. There are many configuration * options, most of which are defined in the parent class. This datasource uses individual pools per user, and some * properties can be set specifically for a given user, if the deployment environment can support initialization of * mapped properties. So for example, a pool of admin or write-access Connections can be guaranteed a certain number of * connections, separate from a maximum set for users with read-only connections. *

* *

* User passwords can be changed without re-initializing the datasource. When a * {@code getConnection(userName, password)} request is processed with a password that is different from those used * to create connections in the pool associated with {@code userName}, an attempt is made to create a new * connection using the supplied password and if this succeeds, the existing pool is cleared and a new pool is created * for connections using the new password. *

* * @since 2.0 */ public class PerUserPoolDataSource extends InstanceKeyDataSource { private static final long serialVersionUID = 7872747993848065028L; private static final Log log = LogFactory.getLog(PerUserPoolDataSource.class); private static HashMap createMap() { // Should there be a default size different from what this ctor provides? return new HashMap<>(); } private Map perUserBlockWhenExhausted; private Map perUserEvictionPolicyClassName; private Map perUserLifo; private Map perUserMaxIdle; private Map perUserMaxTotal; private Map perUserMaxWaitDuration; private Map perUserMinEvictableIdleDuration; private Map perUserMinIdle; private Map perUserNumTestsPerEvictionRun; private Map perUserSoftMinEvictableIdleDuration; private Map perUserTestOnCreate; private Map perUserTestOnBorrow; private Map perUserTestOnReturn; private Map perUserTestWhileIdle; private Map perUserDurationBetweenEvictionRuns; private Map perUserDefaultAutoCommit; private Map perUserDefaultTransactionIsolation; private Map perUserDefaultReadOnly; /** * Map to keep track of Pools for a given user. */ private transient Map managers = createMap(); /** * Default no-arg constructor for Serialization. */ public PerUserPoolDataSource() { } /** * Clears pool(s) maintained by this data source. * * @see org.apache.commons.pool2.ObjectPool#clear() * @since 2.3.0 */ public void clear() { managers.values().forEach(manager -> { try { getCPDSConnectionFactoryPool(manager).clear(); } catch (final Exception ignored) { // ignore and try to close others. } }); InstanceKeyDataSourceFactory.removeInstance(getInstanceKey()); } /** * Closes pool(s) maintained by this data source. * * @see org.apache.commons.pool2.ObjectPool#close() */ @Override public void close() { managers.values().forEach(manager -> Utils.closeQuietly(getCPDSConnectionFactoryPool(manager))); InstanceKeyDataSourceFactory.removeInstance(getInstanceKey()); } /** * Converts a map with Long milliseconds values to another map with Duration values. */ private Map convertMap(final Map currentMap, final Map longMap) { final Map durationMap = createMap(); longMap.forEach((k, v) -> durationMap.put(k, toDurationOrNull(v))); if (currentMap == null) { return durationMap; } currentMap.clear(); currentMap.putAll(durationMap); return currentMap; } @Override protected PooledConnectionManager getConnectionManager(final UserPassKey upKey) { return managers.get(getPoolKey(upKey.getUserName())); } /** * Gets the underlying pool but does NOT allocate it. * * @param manager A CPDSConnectionFactory. * @return the underlying pool. */ private ObjectPool getCPDSConnectionFactoryPool(final PooledConnectionManager manager) { return ((CPDSConnectionFactory) manager).getPool(); } /** * Gets the number of active connections in the default pool. * * @return The number of active connections in the default pool. */ public int getNumActive() { return getNumActive(null); } /** * Gets the number of active connections in the pool for a given user. * * @param userName * The user name key. * @return The user specific value. */ @SuppressWarnings("resource") public int getNumActive(final String userName) { final ObjectPool pool = getPool(getPoolKey(userName)); return pool == null ? 0 : pool.getNumActive(); } /** * Gets the number of idle connections in the default pool. * * @return The number of idle connections in the default pool. */ public int getNumIdle() { return getNumIdle(null); } /** * Gets the number of idle connections in the pool for a given user. * * @param userName * The user name key. * @return The user specific value. */ @SuppressWarnings("resource") public int getNumIdle(final String userName) { final ObjectPool pool = getPool(getPoolKey(userName)); return pool == null ? 0 : pool.getNumIdle(); } /** * Gets the user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool * or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public boolean getPerUserBlockWhenExhausted(final String userName) { Boolean value = null; if (perUserBlockWhenExhausted != null) { value = perUserBlockWhenExhausted.get(userName); } if (value == null) { return getDefaultBlockWhenExhausted(); } return value; } /** * Gets the user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool. * * @param userName * The user name key. * @return The user specific value. */ public Boolean getPerUserDefaultAutoCommit(final String userName) { Boolean value = null; if (perUserDefaultAutoCommit != null) { value = perUserDefaultAutoCommit.get(userName); } return value; } /** * Gets the user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool. * * @param userName * The user name key. * @return The user specific value. */ public Boolean getPerUserDefaultReadOnly(final String userName) { Boolean value = null; if (perUserDefaultReadOnly != null) { value = perUserDefaultReadOnly.get(userName); } return value; } /** * Gets the user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's * pool. * * @param userName * The user name key. * @return The user specific value. */ public Integer getPerUserDefaultTransactionIsolation(final String userName) { Integer value = null; if (perUserDefaultTransactionIsolation != null) { value = perUserDefaultTransactionIsolation.get(userName); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for the specified * user's pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. * @since 2.10.0 */ public Duration getPerUserDurationBetweenEvictionRuns(final String userName) { Duration value = null; if (perUserDurationBetweenEvictionRuns != null) { value = perUserDurationBetweenEvictionRuns.get(userName); } if (value == null) { return getDefaultDurationBetweenEvictionRuns(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's * pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public String getPerUserEvictionPolicyClassName(final String userName) { String value = null; if (perUserEvictionPolicyClassName != null) { value = perUserEvictionPolicyClassName.get(userName); } if (value == null) { return getDefaultEvictionPolicyClassName(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool or the default * if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public boolean getPerUserLifo(final String userName) { Boolean value = null; if (perUserLifo != null) { value = perUserLifo.get(userName); } if (value == null) { return getDefaultLifo(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool or the * default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public int getPerUserMaxIdle(final String userName) { Integer value = null; if (perUserMaxIdle != null) { value = perUserMaxIdle.get(userName); } if (value == null) { return getDefaultMaxIdle(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool or the * default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public int getPerUserMaxTotal(final String userName) { Integer value = null; if (perUserMaxTotal != null) { value = perUserMaxTotal.get(userName); } if (value == null) { return getDefaultMaxTotal(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool or * the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. * @since 2.10.0 */ public Duration getPerUserMaxWaitDuration(final String userName) { Duration value = null; if (perUserMaxWaitDuration != null) { value = perUserMaxWaitDuration.get(userName); } if (value == null) { return getDefaultMaxWait(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool or * the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. * @deprecated Use {@link #getPerUserMaxWaitDuration}. */ @Deprecated public long getPerUserMaxWaitMillis(final String userName) { return getPerUserMaxWaitDuration(userName).toMillis(); } /** * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified * user's pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value, never null. * @since 2.10.0 */ public Duration getPerUserMinEvictableIdleDuration(final String userName) { Duration value = null; if (perUserMinEvictableIdleDuration != null) { value = perUserMinEvictableIdleDuration.get(userName); } if (value == null) { return getDefaultMinEvictableIdleDuration(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified * user's pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. * @deprecated Use {@link #getPerUserMinEvictableIdleDuration(String)}. */ @Deprecated public long getPerUserMinEvictableIdleTimeMillis(final String userName) { return getPerUserMinEvictableIdleDuration(userName).toMillis(); } /** * Gets the user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool or the * default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public int getPerUserMinIdle(final String userName) { Integer value = null; if (perUserMinIdle != null) { value = perUserMinIdle.get(userName); } if (value == null) { return getDefaultMinIdle(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's * pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public int getPerUserNumTestsPerEvictionRun(final String userName) { Integer value = null; if (perUserNumTestsPerEvictionRun != null) { value = perUserNumTestsPerEvictionRun.get(userName); } if (value == null) { return getDefaultNumTestsPerEvictionRun(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified * user's pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. * @since 2.10.0 */ public Duration getPerUserSoftMinEvictableIdleDuration(final String userName) { Duration value = null; if (perUserSoftMinEvictableIdleDuration != null) { value = perUserSoftMinEvictableIdleDuration.get(userName); } if (value == null) { return getDefaultSoftMinEvictableIdleDuration(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified * user's pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. * @deprecated Use {@link #getPerUserSoftMinEvictableIdleDuration(String)}. */ @Deprecated public long getPerUserSoftMinEvictableIdleTimeMillis(final String userName) { return getPerUserSoftMinEvictableIdleDuration(userName).toMillis(); } /** * Gets the user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool or the * default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public boolean getPerUserTestOnBorrow(final String userName) { Boolean value = null; if (perUserTestOnBorrow != null) { value = perUserTestOnBorrow.get(userName); } if (value == null) { return getDefaultTestOnBorrow(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool or the * default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public boolean getPerUserTestOnCreate(final String userName) { Boolean value = null; if (perUserTestOnCreate != null) { value = perUserTestOnCreate.get(userName); } if (value == null) { return getDefaultTestOnCreate(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool or the * default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public boolean getPerUserTestOnReturn(final String userName) { Boolean value = null; if (perUserTestOnReturn != null) { value = perUserTestOnReturn.get(userName); } if (value == null) { return getDefaultTestOnReturn(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool or * the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. */ public boolean getPerUserTestWhileIdle(final String userName) { Boolean value = null; if (perUserTestWhileIdle != null) { value = perUserTestWhileIdle.get(userName); } if (value == null) { return getDefaultTestWhileIdle(); } return value; } /** * Gets the user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for the specified * user's pool or the default if no user specific value is defined. * * @param userName * The user name key. * @return The user specific value. * @deprecated Use {@link #getPerUserDurationBetweenEvictionRuns(String)}. */ @Deprecated public long getPerUserTimeBetweenEvictionRunsMillis(final String userName) { return getPerUserDurationBetweenEvictionRuns(userName).toMillis(); } /** * Returns the object pool associated with the given PoolKey. * * @param poolKey * PoolKey identifying the pool * @return the GenericObjectPool pooling connections for the userName and datasource specified by the PoolKey */ private ObjectPool getPool(final PoolKey poolKey) { final CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(poolKey); return mgr == null ? null : mgr.getPool(); } @Override protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String password) throws SQLException { final PoolKey key = getPoolKey(userName); ObjectPool pool; PooledConnectionManager manager; synchronized (this) { manager = managers.get(key); if (manager == null) { try { registerPool(userName, password); manager = managers.get(key); } catch (final NamingException e) { throw new SQLException("RegisterPool failed", e); } } pool = getCPDSConnectionFactoryPool(manager); } PooledConnectionAndInfo info = null; try { info = pool.borrowObject(); } catch (final NoSuchElementException ex) { throw new SQLException("Could not retrieve connection info from pool", ex); } catch (final Exception e) { // See if failure is due to CPDSConnectionFactory authentication failure try { testCPDS(userName, password); } catch (final Exception ex) { throw new SQLException("Could not retrieve connection info from pool", ex); } // New password works, so kill the old pool, create a new one, and borrow manager.closePool(userName); synchronized (this) { managers.remove(key); } try { registerPool(userName, password); pool = getPool(key); } catch (final NamingException ne) { throw new SQLException("RegisterPool failed", ne); } try { info = pool.borrowObject(); } catch (final Exception ex) { throw new SQLException("Could not retrieve connection info from pool", ex); } } return info; } /** * Creates a pool key from the provided parameters. * * @param userName * User name * @return The pool key */ private PoolKey getPoolKey(final String userName) { return new PoolKey(getDataSourceName(), userName); } /** * Returns a {@code PerUserPoolDataSource} {@link Reference}. */ @Override public Reference getReference() throws NamingException { final Reference ref = new Reference(getClass().getName(), PerUserPoolDataSourceFactory.class.getName(), null); ref.add(new StringRefAddr("instanceKey", getInstanceKey())); return ref; } Map put(Map map, final K key, final V value) { if (map == null) { map = createMap(); } map.put(key, value); return map; } /** * Supports Serialization interface. * * @param in * a {@code java.io.ObjectInputStream} value * @throws IOException * if an error occurs * @throws ClassNotFoundException * if an error occurs */ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { try { in.defaultReadObject(); final PerUserPoolDataSource oldDS = (PerUserPoolDataSource) new PerUserPoolDataSourceFactory() .getObjectInstance(getReference(), null, null, null); this.managers = oldDS.managers; } catch (final NamingException e) { throw new IOException("NamingException: " + e); } } private synchronized void registerPool(final String userName, final String password) throws NamingException, SQLException { final ConnectionPoolDataSource cpds = testCPDS(userName, password); // Set up the factory we will use (passing the pool associates // the factory with the pool, so we do not have to do so // explicitly) final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, getValidationQuery(), getValidationQueryTimeoutDuration(), isRollbackAfterValidation(), userName, password); factory.setMaxConn(getMaxConnDuration()); // Create an object pool to contain our PooledConnections final GenericObjectPool pool = new GenericObjectPool<>(factory); factory.setPool(pool); pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(userName)); pool.setEvictionPolicyClassName(getPerUserEvictionPolicyClassName(userName)); pool.setLifo(getPerUserLifo(userName)); pool.setMaxIdle(getPerUserMaxIdle(userName)); pool.setMaxTotal(getPerUserMaxTotal(userName)); pool.setMaxWait(Duration.ofMillis(getPerUserMaxWaitMillis(userName))); pool.setMinEvictableIdle(getPerUserMinEvictableIdleDuration(userName)); pool.setMinIdle(getPerUserMinIdle(userName)); pool.setNumTestsPerEvictionRun(getPerUserNumTestsPerEvictionRun(userName)); pool.setSoftMinEvictableIdle(getPerUserSoftMinEvictableIdleDuration(userName)); pool.setTestOnCreate(getPerUserTestOnCreate(userName)); pool.setTestOnBorrow(getPerUserTestOnBorrow(userName)); pool.setTestOnReturn(getPerUserTestOnReturn(userName)); pool.setTestWhileIdle(getPerUserTestWhileIdle(userName)); pool.setTimeBetweenEvictionRuns(getPerUserDurationBetweenEvictionRuns(userName)); pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log)); final PooledConnectionManager old = managers.put(getPoolKey(userName), factory); if (old != null) { throw new IllegalStateException("Pool already contains an entry for this user/password: " + userName); } } private Map replaceAll(final Map currentMap, final Map newMap) { if (currentMap == null) { return new HashMap<>(newMap); } currentMap.clear(); currentMap.putAll(newMap); return currentMap; } void setPerUserBlockWhenExhausted(final Map newMap) { assertInitializationAllowed(); perUserBlockWhenExhausted = replaceAll(perUserBlockWhenExhausted, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserBlockWhenExhausted(final String userName, final Boolean value) { assertInitializationAllowed(); perUserBlockWhenExhausted = put(perUserBlockWhenExhausted, userName, value); } void setPerUserDefaultAutoCommit(final Map newMap) { assertInitializationAllowed(); perUserDefaultAutoCommit = replaceAll(perUserDefaultAutoCommit, newMap); } /** * Sets a user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserDefaultAutoCommit(final String userName, final Boolean value) { assertInitializationAllowed(); perUserDefaultAutoCommit = put(perUserDefaultAutoCommit, userName, value); } void setPerUserDefaultReadOnly(final Map newMap) { assertInitializationAllowed(); perUserDefaultReadOnly = replaceAll(perUserDefaultReadOnly, newMap); } /** * Sets a user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserDefaultReadOnly(final String userName, final Boolean value) { assertInitializationAllowed(); perUserDefaultReadOnly = put(perUserDefaultReadOnly, userName, value); } void setPerUserDefaultTransactionIsolation(final Map newMap) { assertInitializationAllowed(); perUserDefaultTransactionIsolation = replaceAll(perUserDefaultTransactionIsolation, newMap); } /** * Sets a user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's * pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserDefaultTransactionIsolation(final String userName, final Integer value) { assertInitializationAllowed(); perUserDefaultTransactionIsolation = put(perUserDefaultTransactionIsolation, userName, value); } void setPerUserDurationBetweenEvictionRuns(final Map newMap) { assertInitializationAllowed(); perUserDurationBetweenEvictionRuns = replaceAll(perUserDurationBetweenEvictionRuns, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for the specified * user's pool. * * @param userName * The user name key. * @param value * The user specific value. * @since 2.10.0 */ public void setPerUserDurationBetweenEvictionRuns(final String userName, final Duration value) { assertInitializationAllowed(); perUserDurationBetweenEvictionRuns = put(perUserDurationBetweenEvictionRuns, userName, value); } void setPerUserEvictionPolicyClassName(final Map newMap) { assertInitializationAllowed(); perUserEvictionPolicyClassName = replaceAll(perUserEvictionPolicyClassName, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's * pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserEvictionPolicyClassName(final String userName, final String value) { assertInitializationAllowed(); perUserEvictionPolicyClassName = put(perUserEvictionPolicyClassName, userName, value); } void setPerUserLifo(final Map newMap) { assertInitializationAllowed(); perUserLifo = replaceAll(perUserLifo, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserLifo(final String userName, final Boolean value) { assertInitializationAllowed(); perUserLifo = put(perUserLifo, userName, value); } void setPerUserMaxIdle(final Map newMap) { assertInitializationAllowed(); perUserMaxIdle = replaceAll(perUserMaxIdle, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserMaxIdle(final String userName, final Integer value) { assertInitializationAllowed(); perUserMaxIdle = put(perUserMaxIdle, userName, value); } void setPerUserMaxTotal(final Map newMap) { assertInitializationAllowed(); perUserMaxTotal = replaceAll(perUserMaxTotal, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserMaxTotal(final String userName, final Integer value) { assertInitializationAllowed(); perUserMaxTotal = put(perUserMaxTotal, userName, value); } /** * Sets a user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. * @since 2.10.0 */ public void setPerUserMaxWait(final String userName, final Duration value) { assertInitializationAllowed(); perUserMaxWaitDuration = put(perUserMaxWaitDuration, userName, value); } void setPerUserMaxWaitDuration(final Map newMap) { assertInitializationAllowed(); perUserMaxWaitDuration = replaceAll(perUserMaxWaitDuration, newMap); } void setPerUserMaxWaitMillis(final Map newMap) { assertInitializationAllowed(); perUserMaxWaitDuration = convertMap(perUserMaxWaitDuration, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. * @deprecated Use {@link #setPerUserMaxWait(String, Duration)}. */ @Deprecated public void setPerUserMaxWaitMillis(final String userName, final Long value) { setPerUserMaxWait(userName, toDurationOrNull(value)); } void setPerUserMinEvictableIdle(final Map newMap) { assertInitializationAllowed(); perUserMinEvictableIdleDuration = replaceAll(perUserMinEvictableIdleDuration, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified user's * pool. * * @param userName * The user name key. * @param value * The user specific value. * @since 2.10.0 */ public void setPerUserMinEvictableIdle(final String userName, final Duration value) { assertInitializationAllowed(); perUserMinEvictableIdleDuration = put(perUserMinEvictableIdleDuration, userName, value); } /** * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified user's * pool. * * @param userName * The user name key. * @param value * The user specific value. * @deprecated Use {@link #setPerUserMinEvictableIdle(String, Duration)}. */ @Deprecated public void setPerUserMinEvictableIdleTimeMillis(final String userName, final Long value) { setPerUserMinEvictableIdle(userName, toDurationOrNull(value)); } void setPerUserMinIdle(final Map newMap) { assertInitializationAllowed(); perUserMinIdle = replaceAll(perUserMinIdle, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserMinIdle(final String userName, final Integer value) { assertInitializationAllowed(); perUserMinIdle = put(perUserMinIdle, userName, value); } void setPerUserNumTestsPerEvictionRun(final Map newMap) { assertInitializationAllowed(); perUserNumTestsPerEvictionRun = replaceAll(perUserNumTestsPerEvictionRun, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's * pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserNumTestsPerEvictionRun(final String userName, final Integer value) { assertInitializationAllowed(); perUserNumTestsPerEvictionRun = put(perUserNumTestsPerEvictionRun, userName, value); } void setPerUserSoftMinEvictableIdle(final Map newMap) { assertInitializationAllowed(); perUserSoftMinEvictableIdleDuration = replaceAll(perUserSoftMinEvictableIdleDuration, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified * user's pool. * * @param userName * The user name key. * @param value * The user specific value. * @since 2.10.0 */ public void setPerUserSoftMinEvictableIdle(final String userName, final Duration value) { assertInitializationAllowed(); perUserSoftMinEvictableIdleDuration = put(perUserSoftMinEvictableIdleDuration, userName, value); } /** * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified * user's pool. * * @param userName * The user name key. * @param value * The user specific value. * @deprecated Use {@link #setPerUserSoftMinEvictableIdle(String, Duration)}. */ @Deprecated public void setPerUserSoftMinEvictableIdleTimeMillis(final String userName, final Long value) { setPerUserSoftMinEvictableIdle(userName, toDurationOrNull(value)); } void setPerUserTestOnBorrow(final Map newMap) { assertInitializationAllowed(); perUserTestOnBorrow = replaceAll(perUserTestOnBorrow, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserTestOnBorrow(final String userName, final Boolean value) { assertInitializationAllowed(); perUserTestOnBorrow = put(perUserTestOnBorrow, userName, value); } void setPerUserTestOnCreate(final Map newMap) { assertInitializationAllowed(); perUserTestOnCreate = replaceAll(perUserTestOnCreate, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserTestOnCreate(final String userName, final Boolean value) { assertInitializationAllowed(); perUserTestOnCreate = put(perUserTestOnCreate, userName, value); } void setPerUserTestOnReturn(final Map newMap) { assertInitializationAllowed(); perUserTestOnReturn = replaceAll(perUserTestOnReturn, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserTestOnReturn(final String userName, final Boolean value) { assertInitializationAllowed(); perUserTestOnReturn = put(perUserTestOnReturn, userName, value); } void setPerUserTestWhileIdle(final Map newMap) { assertInitializationAllowed(); perUserTestWhileIdle = replaceAll(perUserTestWhileIdle, newMap); } /** * Sets a user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool. * * @param userName * The user name key. * @param value * The user specific value. */ public void setPerUserTestWhileIdle(final String userName, final Boolean value) { assertInitializationAllowed(); perUserTestWhileIdle = put(perUserTestWhileIdle, userName, value); } /** * Sets a user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for the specified * user's pool. * * @param userName * The user name key. * @param value * The user specific value. * @deprecated Use {@link #setPerUserDurationBetweenEvictionRuns(String, Duration)}. */ @Deprecated public void setPerUserTimeBetweenEvictionRunsMillis(final String userName, final Long value) { setPerUserDurationBetweenEvictionRuns(userName, toDurationOrNull(value)); } @Override protected void setupDefaults(final Connection con, final String userName) throws SQLException { Boolean defaultAutoCommit = isDefaultAutoCommit(); if (userName != null) { final Boolean userMax = getPerUserDefaultAutoCommit(userName); if (userMax != null) { defaultAutoCommit = userMax; } } Boolean defaultReadOnly = isDefaultReadOnly(); if (userName != null) { final Boolean userMax = getPerUserDefaultReadOnly(userName); if (userMax != null) { defaultReadOnly = userMax; } } int defaultTransactionIsolation = getDefaultTransactionIsolation(); if (userName != null) { final Integer userMax = getPerUserDefaultTransactionIsolation(userName); if (userMax != null) { defaultTransactionIsolation = userMax; } } if (defaultAutoCommit != null && con.getAutoCommit() != defaultAutoCommit) { con.setAutoCommit(defaultAutoCommit); } if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) { con.setTransactionIsolation(defaultTransactionIsolation); } if (defaultReadOnly != null && con.isReadOnly() != defaultReadOnly) { con.setReadOnly(defaultReadOnly); } } private Duration toDurationOrNull(final Long millis) { return millis == null ? null : Duration.ofMillis(millis); } } PerUserPoolDataSourceFactory.java000066400000000000000000000076311447311732500372640ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.IOException; import java.time.Duration; import java.util.Map; import javax.naming.RefAddr; import javax.naming.Reference; /** * A JNDI ObjectFactory which creates {@code SharedPoolDataSource}s * * @since 2.0 */ public class PerUserPoolDataSourceFactory extends InstanceKeyDataSourceFactory { private static final String PER_USER_POOL_CLASSNAME = PerUserPoolDataSource.class.getName(); @SuppressWarnings("unchecked") // Avoid warnings on deserialization @Override protected InstanceKeyDataSource getNewInstance(final Reference ref) throws IOException, ClassNotFoundException { final PerUserPoolDataSource pupds = new PerUserPoolDataSource(); RefAddr refAddr = ref.get("defaultMaxTotal"); if (refAddr != null && refAddr.getContent() != null) { pupds.setDefaultMaxTotal(parseInt(refAddr)); } refAddr = ref.get("defaultMaxIdle"); if (refAddr != null && refAddr.getContent() != null) { pupds.setDefaultMaxIdle(parseInt(refAddr)); } refAddr = ref.get("defaultMaxWaitMillis"); if (refAddr != null && refAddr.getContent() != null) { pupds.setDefaultMaxWait(Duration.ofMillis(parseInt(refAddr))); } refAddr = ref.get("perUserDefaultAutoCommit"); if (refAddr != null && refAddr.getContent() != null) { final byte[] serialized = (byte[]) refAddr.getContent(); pupds.setPerUserDefaultAutoCommit((Map) deserialize(serialized)); } refAddr = ref.get("perUserDefaultTransactionIsolation"); if (refAddr != null && refAddr.getContent() != null) { final byte[] serialized = (byte[]) refAddr.getContent(); pupds.setPerUserDefaultTransactionIsolation((Map) deserialize(serialized)); } refAddr = ref.get("perUserMaxTotal"); if (refAddr != null && refAddr.getContent() != null) { final byte[] serialized = (byte[]) refAddr.getContent(); pupds.setPerUserMaxTotal((Map) deserialize(serialized)); } refAddr = ref.get("perUserMaxIdle"); if (refAddr != null && refAddr.getContent() != null) { final byte[] serialized = (byte[]) refAddr.getContent(); pupds.setPerUserMaxIdle((Map) deserialize(serialized)); } refAddr = ref.get("perUserMaxWaitMillis"); if (refAddr != null && refAddr.getContent() != null) { final byte[] serialized = (byte[]) refAddr.getContent(); pupds.setPerUserMaxWaitMillis((Map) deserialize(serialized)); } refAddr = ref.get("perUserDefaultReadOnly"); if (refAddr != null && refAddr.getContent() != null) { final byte[] serialized = (byte[]) refAddr.getContent(); pupds.setPerUserDefaultReadOnly((Map) deserialize(serialized)); } return pupds; } @Override protected boolean isCorrectClass(final String className) { return PER_USER_POOL_CLASSNAME.equals(className); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/PoolKey.java000066400000000000000000000041531447311732500331770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.Serializable; import java.util.Objects; /** * @since 2.0 */ final class PoolKey implements Serializable { private static final long serialVersionUID = 2252771047542484533L; private final String dataSourceName; private final String userName; PoolKey(final String dataSourceName, final String userName) { this.dataSourceName = dataSourceName; this.userName = userName; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final PoolKey other = (PoolKey) obj; if (!Objects.equals(dataSourceName, other.dataSourceName)) { return false; } return Objects.equals(userName, other.userName); } @Override public int hashCode() { return Objects.hash(dataSourceName, userName); } @Override public String toString() { final StringBuilder sb = new StringBuilder(50); sb.append("PoolKey("); sb.append(dataSourceName); sb.append(')'); return sb.toString(); } } PooledConnectionAndInfo.java000066400000000000000000000043111447311732500362330ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import javax.sql.PooledConnection; /** * Immutable poolable object holding a {@link PooledConnection} along with the user name and password used to create the * connection. * * @since 2.0 */ final class PooledConnectionAndInfo { private final PooledConnection pooledConnection; private final UserPassKey userPassKey; /** * Constructs a new instance. * * @since 2.4.0 */ PooledConnectionAndInfo(final PooledConnection pooledConnection, final char[] userName, final char[] userPassword) { this(pooledConnection, new UserPassKey(userName, userPassword)); } PooledConnectionAndInfo(final PooledConnection pooledConnection, final UserPassKey userPassKey) { this.pooledConnection = pooledConnection; this.userPassKey = userPassKey; } /** * Gets the value of password. * * @return value of password. */ String getPassword() { return userPassKey.getPassword(); } /** * Gets the pooled connection. * * @return the pooled connection. */ PooledConnection getPooledConnection() { return pooledConnection; } /** * Gets the value of userName. * * @return value of userName. */ String getUserName() { return userPassKey.getUserName(); } UserPassKey getUserPassKey() { return userPassKey; } } PooledConnectionManager.java000066400000000000000000000044361447311732500362770ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.sql.SQLException; import javax.sql.PooledConnection; /** * Methods to manage PoolableConnections and the connection pools that source them. * * @since 2.0 */ interface PooledConnectionManager { /** * Closes the connection pool associated with the given user. * * @param userName * user name * @throws SQLException * if an error occurs closing idle connections in the pool */ void closePool(String userName) throws SQLException; /** * Closes the PooledConnection and remove it from the connection pool to which it belongs, adjusting pool counters. * * @param pc * PooledConnection to be invalidated * @throws SQLException * if an SQL error occurs closing the connection */ void invalidate(PooledConnection pc) throws SQLException; // /** // * Sets the database password used when creating connections. // * // * @param password password used when authenticating to the database // * @since 2.10.0 // */ // default void setPassword(char[] password) { // setPassword(String.copyValueOf(password)); // } /** * Sets the database password used when creating connections. * * @param password * password used when authenticating to the database */ void setPassword(String password); } SharedPoolDataSource.java000066400000000000000000000214671447311732500355600ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.IOException; import java.io.ObjectInputStream; import java.sql.Connection; import java.sql.SQLException; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.sql.ConnectionPoolDataSource; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; /** *

* A pooling {@code DataSource} appropriate for deployment within J2EE environment. There are many configuration * options, most of which are defined in the parent class. All users (based on user name) share a single maximum number * of Connections in this data source. *

* *

* User passwords can be changed without re-initializing the data source. When a * {@code getConnection(user name, password)} request is processed with a password that is different from those * used to create connections in the pool associated with {@code user name}, an attempt is made to create a new * connection using the supplied password and if this succeeds, idle connections created using the old password are * destroyed and new connections are created using the new password. *

* * @since 2.0 */ public class SharedPoolDataSource extends InstanceKeyDataSource { private static final long serialVersionUID = -1458539734480586454L; // Pool properties private int maxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; private transient KeyedObjectPool pool; private transient KeyedCPDSConnectionFactory factory; /** * Default no-argument constructor for Serialization */ public SharedPoolDataSource() { // empty. } /** * Closes pool being maintained by this data source. */ @Override public void close() throws SQLException { if (pool != null) { pool.close(); } InstanceKeyDataSourceFactory.removeInstance(getInstanceKey()); } @Override protected PooledConnectionManager getConnectionManager(final UserPassKey userPassKey) { return factory; } /** * Gets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool. * * @return {@link GenericKeyedObjectPool#getMaxTotal()} for this pool. */ public int getMaxTotal() { return this.maxTotal; } // ---------------------------------------------------------------------- // Instrumentation Methods /** * Gets the number of active connections in the pool. * * @return The number of active connections in the pool. */ public int getNumActive() { return pool == null ? 0 : pool.getNumActive(); } /** * Gets the number of idle connections in the pool. * * @return The number of idle connections in the pool. */ public int getNumIdle() { return pool == null ? 0 : pool.getNumIdle(); } @Override protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String userPassword) throws SQLException { synchronized (this) { if (pool == null) { try { registerPool(userName, userPassword); } catch (final NamingException e) { throw new SQLException("registerPool failed", e); } } } try { return pool.borrowObject(new UserPassKey(userName, userPassword)); } catch (final Exception e) { throw new SQLException("Could not retrieve connection info from pool", e); } } /** * Creates a new {@link Reference} to a {@link SharedPoolDataSource}. */ @Override public Reference getReference() throws NamingException { final Reference ref = new Reference(getClass().getName(), SharedPoolDataSourceFactory.class.getName(), null); ref.add(new StringRefAddr("instanceKey", getInstanceKey())); return ref; } /** * Supports Serialization interface. * * @param in * a {@code java.io.ObjectInputStream} value * @throws IOException * if an error occurs * @throws ClassNotFoundException * if an error occurs */ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { try { in.defaultReadObject(); final SharedPoolDataSource oldDS = (SharedPoolDataSource) new SharedPoolDataSourceFactory().getObjectInstance(getReference(), null, null, null); this.pool = oldDS.pool; } catch (final NamingException e) { throw new IOException("NamingException: " + e); } } private void registerPool(final String userName, final String password) throws NamingException, SQLException { final ConnectionPoolDataSource cpds = testCPDS(userName, password); // Create an object pool to contain our PooledConnections factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(), getValidationQueryTimeoutDuration(), isRollbackAfterValidation()); factory.setMaxConn(getMaxConnDuration()); final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig<>(); config.setBlockWhenExhausted(getDefaultBlockWhenExhausted()); config.setEvictionPolicyClassName(getDefaultEvictionPolicyClassName()); config.setLifo(getDefaultLifo()); config.setMaxIdlePerKey(getDefaultMaxIdle()); config.setMaxTotal(getMaxTotal()); config.setMaxTotalPerKey(getDefaultMaxTotal()); config.setMaxWait(getDefaultMaxWait()); config.setMinEvictableIdleTime(getDefaultMinEvictableIdleDuration()); config.setMinIdlePerKey(getDefaultMinIdle()); config.setNumTestsPerEvictionRun(getDefaultNumTestsPerEvictionRun()); config.setSoftMinEvictableIdleTime(getDefaultSoftMinEvictableIdleDuration()); config.setTestOnCreate(getDefaultTestOnCreate()); config.setTestOnBorrow(getDefaultTestOnBorrow()); config.setTestOnReturn(getDefaultTestOnReturn()); config.setTestWhileIdle(getDefaultTestWhileIdle()); config.setTimeBetweenEvictionRuns(getDefaultDurationBetweenEvictionRuns()); final KeyedObjectPool tmpPool = new GenericKeyedObjectPool<>(factory, config); factory.setPool(tmpPool); pool = tmpPool; } /** * Sets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool. * * @param maxTotal * {@link GenericKeyedObjectPool#getMaxTotal()} for this pool. */ public void setMaxTotal(final int maxTotal) { assertInitializationAllowed(); this.maxTotal = maxTotal; } @Override protected void setupDefaults(final Connection connection, final String userName) throws SQLException { final Boolean defaultAutoCommit = isDefaultAutoCommit(); if (defaultAutoCommit != null && connection.getAutoCommit() != defaultAutoCommit) { connection.setAutoCommit(defaultAutoCommit); } final int defaultTransactionIsolation = getDefaultTransactionIsolation(); if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) { connection.setTransactionIsolation(defaultTransactionIsolation); } final Boolean defaultReadOnly = isDefaultReadOnly(); if (defaultReadOnly != null && connection.isReadOnly() != defaultReadOnly) { connection.setReadOnly(defaultReadOnly); } } @Override protected void toStringFields(final StringBuilder builder) { super.toStringFields(builder); builder.append(", maxTotal="); builder.append(maxTotal); } } SharedPoolDataSourceFactory.java000066400000000000000000000032351447311732500371010ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import javax.naming.RefAddr; import javax.naming.Reference; /** * A JNDI ObjectFactory which creates {@code SharedPoolDataSource}s * * @since 2.0 */ public class SharedPoolDataSourceFactory extends InstanceKeyDataSourceFactory { private static final String SHARED_POOL_CLASSNAME = SharedPoolDataSource.class.getName(); @Override protected InstanceKeyDataSource getNewInstance(final Reference ref) { final SharedPoolDataSource spds = new SharedPoolDataSource(); final RefAddr ra = ref.get("maxTotal"); if (ra != null && ra.getContent() != null) { spds.setMaxTotal(Integer.parseInt(ra.getContent().toString())); } return spds; } @Override protected boolean isCorrectClass(final String className) { return SHARED_POOL_CLASSNAME.equals(className); } } UserPassKey.java000066400000000000000000000070751447311732500337620ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.Serializable; import java.util.Objects; import org.apache.commons.pool2.KeyedObjectPool; /** *

* Holds a user name and password pair. Serves as a poolable object key for the {@link KeyedObjectPool} backing a * {@link SharedPoolDataSource}. Two instances with the same user name are considered equal. This ensures that there * will be only one keyed pool for each user in the pool. The password is used (along with the user name) by the * {@code KeyedCPDSConnectionFactory} when creating new connections. *

* *

* {@link InstanceKeyDataSource#getConnection(String, String)} validates that the password used to create a connection * matches the password provided by the client. *

* * @since 2.0 */ final class UserPassKey implements Serializable { private static final long serialVersionUID = 5142970911626584817L; private final CharArray name; private final CharArray password; UserPassKey(final char[] userName, final char[] password) { this(new CharArray(userName), new CharArray(password)); } UserPassKey(final CharArray userName, final CharArray userPassword) { this.name = userName; this.password = userPassword; } UserPassKey(final String userName) { this(new CharArray(userName), CharArray.NULL); } UserPassKey(final String userName, final char[] password) { this(new CharArray(userName), new CharArray(password)); } UserPassKey(final String userName, final String userPassword) { this(new CharArray(userName), new CharArray(userPassword)); } /** * Only takes the user name into account. */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final UserPassKey other = (UserPassKey) obj; return Objects.equals(name, other.name); } /** * Gets the value of password. * * @return value of password. */ String getPassword() { return password.asString(); } /** * Gets the value of password. * * @return value of password. */ char[] getPasswordCharArray() { return password.get(); } /** * Gets the value of user name. * * @return value of user name. */ String getUserName() { return name.asString(); } /** * Only takes the user name into account. */ @Override public int hashCode() { return Objects.hash(name); } } package-info.java000066400000000000000000000131611447311732500340610ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT 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 two DataSources: {@code PerUserPoolDataSource} and * {@code SharedPoolDataSource} which provide a database connection pool. * Below are a couple of usage examples. One shows deployment into a JNDI system. * The other is a simple example initializing the pool using standard java code. *

* *

JNDI

* *

* Most * J2EE containers will provide some way of deploying resources into JNDI. The * method will vary among containers, but once the resource is available via * JNDI, the application can access the resource in a container independent * manner. The following example shows deployment into tomcat (catalina). *

*

In server.xml, the following would be added to the <Context> for your * webapp: *

* * * <Resource name="jdbc/bookstore" auth="Container" * type="org.apache.commons.dbcp2.datasources.PerUserPoolPoolDataSource"/> * <ResourceParams name="jdbc/bookstore"> * <parameter> * <name>factory</name> * <value>org.apache.commons.dbcp2.datasources.PerUserPoolDataSourceFactory</value> * </parameter> * <parameter> * <name>dataSourceName</name><value>java:comp/env/jdbc/bookstoreCPDS</value> * </parameter> * <parameter> * <name>defaultMaxTotal</name><value>30</value> * </parameter> * </ResourceParams> * * *

* In web.xml. Note that elements must be given in the order of the dtd * described in the servlet specification: *

* * * <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 server.xml file. * </description> * <res-ref-name> * jdbc/bookstore * </res-ref-name> * <res-type> * org.apache.commons.dbcp2.datasources.PerUserPoolDataSource * </res-type> * <res-auth> * Container * </res-auth> * </resource-ref> * * *

* Apache Tomcat deploys all objects configured similarly to above within the * java:comp/env namespace. So the JNDI path given for * the dataSourceName parameter is valid for a * {@code ConnectionPoolDataSource} that is deployed as given in the * cpdsadapter example *

* *

* The {@code DataSource} is now available to the application as shown * below: *

* * * * Context ctx = new InitialContext(); * DataSource ds = (DataSource) * ctx.lookup("java:comp/env/jdbc/bookstore"); * Connection con = null; * try * { * con = ds.getConnection(); * ... * use the connection * ... * } * finally * { * if (con != null) * con.close(); * } * * * *

* The reference to the {@code DataSource} could be maintained, for * multiple getConnection() requests. Or the {@code DataSource} can be * looked up in different parts of the application code. * {@code PerUserPoolDataSourceFactory} and * {@code SharedPoolDataSourceFactory} will maintain the state of the pool * between different lookups. This behavior may be different in other * implementations. *

* *

Without JNDI

* *

* Connection pooling is useful in applications regardless of whether they run * in a J2EE environment and a {@code DataSource} can be used within a * simpler environment. The example below shows SharedPoolDataSource using * DriverAdapterCPDS as the back end source, though any CPDS is applicable. *

* * * * public class Pool * { * private static DataSource ds; * * static * { * DriverAdapterCPDS cpds = new DriverAdapterCPDS(); * cpds.setDriver("org.gjt.mm.mysql.Driver"); * cpds.setUrl("jdbc:mysql://localhost:3306/bookstore"); * cpds.setUser("foo"); * cpds.setPassword(null); * * SharedPoolDataSource tds = new SharedPoolDataSource(); * tds.setConnectionPoolDataSource(cpds); * tds.setMaxTotal(10); * tds.setMaxWaitMillis(50); * * ds = tds; * } * * public static getConnection() * { * return ds.getConnection(); * } * } * * * *

* This class can then be used wherever a connection is needed: *

* * * Connection con = null; * try * { * con = Pool.getConnection(); * ... * use the connection * ... * } * finally * { * if (con != null) * con.close(); * } * */ package org.apache.commons.dbcp2.datasources; commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/000077500000000000000000000000001447311732500300265ustar00rootroot00000000000000BasicManagedDataSource.java000066400000000000000000000253271447311732500350740ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.SQLException; import javax.sql.DataSource; import javax.sql.XADataSource; import javax.transaction.TransactionManager; import javax.transaction.TransactionSynchronizationRegistry; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingDataSource; import org.apache.commons.dbcp2.Utils; /** *

* BasicManagedDataSource is an extension of BasicDataSource which creates ManagedConnections. This data source can * create either full two-phase-commit XA connections or one-phase-commit local connections. Both types of connections * are committed or rolled back as part of the global transaction (a.k.a. XA transaction or JTA Transaction), but only * XA connections can be recovered in the case of a system crash. *

*

* BasicManagedDataSource adds the TransactionManager and XADataSource properties. The TransactionManager property is * required and is used to enlist connections in global transactions. The XADataSource is optional and if set is the * class name of the XADataSource class for a two-phase-commit JDBC driver. If the XADataSource property is set, the * driverClassName is ignored and a DataSourceXAConnectionFactory is created. Otherwise, a standard * DriverConnectionFactory is created and wrapped with a LocalXAConnectionFactory. *

* * @see BasicDataSource * @see ManagedConnection * @since 2.0 */ public class BasicManagedDataSource extends BasicDataSource { /** Transaction Registry */ private TransactionRegistry transactionRegistry; /** Transaction Manager */ private transient TransactionManager transactionManager; /** XA data source class name */ private String xaDataSource; /** XA data source instance */ private XADataSource xaDataSourceInstance; /** Transaction Synchronization Registry */ private transient TransactionSynchronizationRegistry transactionSynchronizationRegistry; @Override protected ConnectionFactory createConnectionFactory() throws SQLException { if (transactionManager == null) { throw new SQLException("Transaction manager must be set before a connection can be created"); } // If xa data source is not specified a DriverConnectionFactory is created and wrapped with a // LocalXAConnectionFactory if (xaDataSource == null) { final ConnectionFactory connectionFactory = super.createConnectionFactory(); final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(), getTransactionSynchronizationRegistry(), connectionFactory); transactionRegistry = xaConnectionFactory.getTransactionRegistry(); return xaConnectionFactory; } // Create the XADataSource instance using the configured class name if it has not been set if (xaDataSourceInstance == null) { Class xaDataSourceClass = null; try { xaDataSourceClass = Class.forName(xaDataSource); } catch (final Exception t) { final String message = "Cannot load XA data source class '" + xaDataSource + "'"; throw new SQLException(message, t); } try { xaDataSourceInstance = (XADataSource) xaDataSourceClass.getConstructor().newInstance(); } catch (final Exception t) { final String message = "Cannot create XA data source of class '" + xaDataSource + "'"; throw new SQLException(message, t); } } // finally, create the XAConnectionFactory using the XA data source final XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(), xaDataSourceInstance, getUsername(), Utils.toCharArray(getPassword()), getTransactionSynchronizationRegistry()); transactionRegistry = xaConnectionFactory.getTransactionRegistry(); return xaConnectionFactory; } @Override protected DataSource createDataSourceInstance() throws SQLException { final PoolingDataSource pds = new ManagedDataSource<>(getConnectionPool(), transactionRegistry); pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); return pds; } /** * Creates the PoolableConnectionFactory and attaches it to the connection pool. * * @param driverConnectionFactory * JDBC connection factory created by {@link #createConnectionFactory()} * @throws SQLException * if an error occurs creating the PoolableConnectionFactory */ @Override protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory) throws SQLException { PoolableConnectionFactory connectionFactory = null; try { connectionFactory = new PoolableManagedConnectionFactory((XAConnectionFactory) driverConnectionFactory, getRegisteredJmxName()); connectionFactory.setValidationQuery(getValidationQuery()); connectionFactory.setValidationQueryTimeout(getValidationQueryTimeoutDuration()); connectionFactory.setConnectionInitSql(getConnectionInitSqls()); connectionFactory.setDefaultReadOnly(getDefaultReadOnly()); connectionFactory.setDefaultAutoCommit(getDefaultAutoCommit()); connectionFactory.setDefaultTransactionIsolation(getDefaultTransactionIsolation()); connectionFactory.setDefaultCatalog(getDefaultCatalog()); connectionFactory.setDefaultSchema(getDefaultSchema()); connectionFactory.setCacheState(getCacheState()); connectionFactory.setPoolStatements(isPoolPreparedStatements()); connectionFactory.setClearStatementPoolOnReturn(isClearStatementPoolOnReturn()); connectionFactory.setMaxOpenPreparedStatements(getMaxOpenPreparedStatements()); connectionFactory.setMaxConn(getMaxConnDuration()); connectionFactory.setRollbackOnReturn(getRollbackOnReturn()); connectionFactory.setAutoCommitOnReturn(getAutoCommitOnReturn()); connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeoutDuration()); connectionFactory.setFastFailValidation(getFastFailValidation()); connectionFactory.setDisconnectionSqlCodes(getDisconnectionSqlCodes()); validateConnectionFactory(connectionFactory); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e); } return connectionFactory; } /** * Gets the required transaction manager property. * * @return the transaction manager used to enlist connections */ public TransactionManager getTransactionManager() { return transactionManager; } /** * Gets the transaction registry. * * @return the transaction registry associating XAResources with managed connections */ protected synchronized TransactionRegistry getTransactionRegistry() { return transactionRegistry; } /** * Gets the optional TransactionSynchronizationRegistry. * * @return the TSR that can be used to register synchronizations. * @since 2.6.0 */ public TransactionSynchronizationRegistry getTransactionSynchronizationRegistry() { return transactionSynchronizationRegistry; } /** * Gets the optional XADataSource class name. * * @return the optional XADataSource class name */ public synchronized String getXADataSource() { return xaDataSource; } /** * Gets the XADataSource instance used by the XAConnectionFactory. * * @return the XADataSource */ public synchronized XADataSource getXaDataSourceInstance() { return xaDataSourceInstance; } /** * Sets the required transaction manager property. * * @param transactionManager * the transaction manager used to enlist connections */ public void setTransactionManager(final TransactionManager transactionManager) { this.transactionManager = transactionManager; } /** * Sets the optional TransactionSynchronizationRegistry property. * * @param transactionSynchronizationRegistry * the TSR used to register synchronizations * @since 2.6.0 */ public void setTransactionSynchronizationRegistry( final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { this.transactionSynchronizationRegistry = transactionSynchronizationRegistry; } /** * Sets the optional XADataSource class name. * * @param xaDataSource * the optional XADataSource class name */ public synchronized void setXADataSource(final String xaDataSource) { this.xaDataSource = xaDataSource; } /** *

* Sets the XADataSource instance used by the XAConnectionFactory. *

*

* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first * time one of the following methods is invoked: getConnection, setLogwriter, * setLoginTimeout, getLoginTimeout, getLogWriter. *

* * @param xaDataSourceInstance * XADataSource instance */ public synchronized void setXaDataSourceInstance(final XADataSource xaDataSourceInstance) { this.xaDataSourceInstance = xaDataSourceInstance; xaDataSource = xaDataSourceInstance == null ? null : xaDataSourceInstance.getClass().getName(); } } DataSourceXAConnectionFactory.java000066400000000000000000000246601447311732500364550ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import java.util.Objects; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.PooledConnection; import javax.sql.XAConnection; import javax.sql.XADataSource; import javax.transaction.TransactionManager; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAResource; import org.apache.commons.dbcp2.Utils; /** * An implementation of XAConnectionFactory which uses a real XADataSource to obtain connections and XAResources. * * @since 2.0 */ public class DataSourceXAConnectionFactory implements XAConnectionFactory { private static final class XAConnectionEventListener implements ConnectionEventListener { @Override public void connectionClosed(final ConnectionEvent event) { final PooledConnection pc = (PooledConnection) event.getSource(); pc.removeConnectionEventListener(this); try { pc.close(); } catch (final SQLException e) { System.err.println("Failed to close XAConnection"); e.printStackTrace(); } } @Override public void connectionErrorOccurred(final ConnectionEvent event) { connectionClosed(event); } } private final TransactionRegistry transactionRegistry; private final XADataSource xaDataSource; private String userName; private char[] userPassword; /** * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. * The connections are enlisted into transactions using the specified transaction manager. * * @param transactionManager * the transaction manager in which connections will be enlisted * @param xaDataSource * the data source from which connections will be retrieved * @since 2.6.0 */ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource) { this(transactionManager, xaDataSource, null, (char[]) null, null); } /** * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. * The connections are enlisted into transactions using the specified transaction manager. * * @param transactionManager * the transaction manager in which connections will be enlisted * @param xaDataSource * the data source from which connections will be retrieved * @param userName * the user name used for authenticating new connections or null for unauthenticated * @param userPassword * the password used for authenticating new connections */ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final String userName, final char[] userPassword) { this(transactionManager, xaDataSource, userName, userPassword, null); } /** * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. * The connections are enlisted into transactions using the specified transaction manager. * * @param transactionManager * the transaction manager in which connections will be enlisted * @param xaDataSource * the data source from which connections will be retrieved * @param userName * the user name used for authenticating new connections or null for unauthenticated * @param userPassword * the password used for authenticating new connections * @param transactionSynchronizationRegistry * register with this TransactionSynchronizationRegistry * @since 2.6.0 */ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final String userName, final char[] userPassword, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { Objects.requireNonNull(transactionManager, "transactionManager"); Objects.requireNonNull(xaDataSource, "xaDataSource"); // We do allow the transactionSynchronizationRegistry to be null for non-app server environments this.transactionRegistry = new TransactionRegistry(transactionManager, transactionSynchronizationRegistry); this.xaDataSource = xaDataSource; this.userName = userName; this.userPassword = Utils.clone(userPassword); } /** * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. * The connections are enlisted into transactions using the specified transaction manager. * * @param transactionManager * the transaction manager in which connections will be enlisted * @param xaDataSource * the data source from which connections will be retrieved * @param userName * the user name used for authenticating new connections or null for unauthenticated * @param userPassword * the password used for authenticating new connections */ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final String userName, final String userPassword) { this(transactionManager, xaDataSource, userName, Utils.toCharArray(userPassword), null); } /** * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. * The connections are enlisted into transactions using the specified transaction manager. * * @param transactionManager * the transaction manager in which connections will be enlisted * @param xaDataSource * the data source from which connections will be retrieved * @param transactionSynchronizationRegistry * register with this TransactionSynchronizationRegistry */ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { this(transactionManager, xaDataSource, null, (char[]) null, transactionSynchronizationRegistry); } @Override public Connection createConnection() throws SQLException { // create a new XAConnection final XAConnection xaConnection; if (userName == null) { xaConnection = xaDataSource.getXAConnection(); } else { xaConnection = xaDataSource.getXAConnection(userName, Utils.toString(userPassword)); } // get the real connection and XAResource from the connection final Connection connection = xaConnection.getConnection(); final XAResource xaResource = xaConnection.getXAResource(); // register the xa resource for the connection transactionRegistry.registerConnection(connection, xaResource); // The Connection we're returning is a handle on the XAConnection. // When the pool calling us closes the Connection, we need to // also close the XAConnection that holds the physical connection. xaConnection.addConnectionEventListener(new XAConnectionEventListener()); return connection; } @Override public TransactionRegistry getTransactionRegistry() { return transactionRegistry; } /** * Gets the user name used to authenticate new connections. * * @return the user name or null if unauthenticated connections are used * @deprecated Use {@link #getUserName()}. */ @Deprecated public String getUsername() { return userName; } /** * Gets the user name used to authenticate new connections. * * @return the user name or null if unauthenticated connections are used * @since 2.6.0 */ public String getUserName() { return userName; } /** * Gets the user password. * * @return the user password. */ public char[] getUserPassword() { return Utils.clone(userPassword); } /** * Gets the XA data source. * * @return the XA data source. */ public XADataSource getXaDataSource() { return xaDataSource; } /** * Sets the password used to authenticate new connections. * * @param userPassword * the password used for authenticating the connection or null for unauthenticated. * @since 2.4.0 */ public void setPassword(final char[] userPassword) { this.userPassword = Utils.clone(userPassword); } /** * Sets the password used to authenticate new connections. * * @param userPassword * the password used for authenticating the connection or null for unauthenticated */ public void setPassword(final String userPassword) { this.userPassword = Utils.toCharArray(userPassword); } /** * Sets the user name used to authenticate new connections. * * @param userName * the user name used for authenticating the connection or null for unauthenticated */ public void setUsername(final String userName) { this.userName = userName; } } LocalXAConnectionFactory.java000066400000000000000000000365251447311732500354600ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import java.util.Objects; import javax.transaction.TransactionManager; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.apache.commons.dbcp2.ConnectionFactory; /** * An implementation of XAConnectionFactory which manages non-XA connections in XA transactions. A non-XA connection * commits and rolls back as part of the XA transaction, but is not recoverable since the connection does not implement * the 2-phase protocol. * * @since 2.0 */ public class LocalXAConnectionFactory implements XAConnectionFactory { /** * LocalXAResource is a fake XAResource for non-XA connections. When a transaction is started the connection * auto-commit is turned off. When the connection is committed or rolled back, the commit or rollback method is * called on the connection and then the original auto-commit value is restored. *

* The LocalXAResource also respects the connection read-only setting. If the connection is read-only the commit * method will not be called, and the prepare method returns the XA_RDONLY. *

*

* It is assumed that the wrapper around a managed connection disables the setAutoCommit(), commit(), rollback() and * setReadOnly() methods while a transaction is in progress. *

* * @since 2.0 */ protected static class LocalXAResource implements XAResource { private static final Xid[] EMPTY_XID_ARRAY = {}; private final Connection connection; private Xid currentXid; // @GuardedBy("this") private boolean originalAutoCommit; // @GuardedBy("this") /** * Construct a new instance for a given connection. * * @param localTransaction A connection. */ public LocalXAResource(final Connection localTransaction) { this.connection = localTransaction; } private Xid checkCurrentXid() throws XAException { if (this.currentXid == null) { throw new XAException("There is no current transaction"); } return currentXid; } /** * Commits the transaction and restores the original auto commit setting. * * @param xid * the id of the transaction branch for this connection * @param flag * ignored * @throws XAException * if connection.commit() throws an SQLException */ @Override public synchronized void commit(final Xid xid, final boolean flag) throws XAException { Objects.requireNonNull(xid, "xid"); if (!checkCurrentXid().equals(xid)) { throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); } try { // make sure the connection isn't already closed if (connection.isClosed()) { throw new XAException("Connection is closed"); } // A read only connection should not be committed if (!connection.isReadOnly()) { connection.commit(); } } catch (final SQLException e) { throw (XAException) new XAException().initCause(e); } finally { try { connection.setAutoCommit(originalAutoCommit); } catch (final SQLException ignored) { // ignored } this.currentXid = null; } } /** * This method does nothing. * * @param xid * the id of the transaction branch for this connection * @param flag * ignored * @throws XAException * if the connection is already enlisted in another transaction */ @Override public synchronized void end(final Xid xid, final int flag) throws XAException { Objects.requireNonNull(xid, "xid"); if (!checkCurrentXid().equals(xid)) { throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); } // This notification tells us that the application server is done using this // connection for the time being. The connection is still associated with an // open transaction, so we must still wait for the commit or rollback method } /** * Clears the currently associated transaction if it is the specified xid. * * @param xid * the id of the transaction to forget */ @Override public synchronized void forget(final Xid xid) { if (xid != null && xid.equals(currentXid)) { currentXid = null; } } /** * Always returns 0 since we have no way to set a transaction timeout on a JDBC connection. * * @return always 0 */ @Override public int getTransactionTimeout() { return 0; } /** * Gets the current xid of the transaction branch associated with this XAResource. * * @return the current xid of the transaction branch associated with this XAResource. */ public synchronized Xid getXid() { return currentXid; } /** * Returns true if the specified XAResource == this XAResource. * * @param xaResource * the XAResource to test * @return true if the specified XAResource == this XAResource; false otherwise */ @Override public boolean isSameRM(final XAResource xaResource) { return this == xaResource; } /** * This method does nothing since the LocalXAConnection does not support two-phase-commit. This method will * return XAResource.XA_RDONLY if the connection isReadOnly(). This assumes that the physical connection is * wrapped with a proxy that prevents an application from changing the read-only flag while enrolled in a * transaction. * * @param xid * the id of the transaction branch for this connection * @return XAResource.XA_RDONLY if the connection.isReadOnly(); XAResource.XA_OK otherwise */ @Override public synchronized int prepare(final Xid xid) { // if the connection is read-only, then the resource is read-only // NOTE: this assumes that the outer proxy throws an exception when application code // attempts to set this in a transaction try { if (connection.isReadOnly()) { // update the auto commit flag connection.setAutoCommit(originalAutoCommit); // tell the transaction manager we are read only return XAResource.XA_RDONLY; } } catch (final SQLException ignored) { // no big deal } // this is a local (one phase) only connection, so we can't prepare return XAResource.XA_OK; } /** * Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids * will ever be found. * * @param flag * ignored since recovery is not supported * @return always a zero length Xid array. */ @Override public Xid[] recover(final int flag) { return EMPTY_XID_ARRAY; } /** * Rolls back the transaction and restores the original auto commit setting. * * @param xid * the id of the transaction branch for this connection * @throws XAException * if connection.rollback() throws an SQLException */ @Override public synchronized void rollback(final Xid xid) throws XAException { Objects.requireNonNull(xid, "xid"); if (!checkCurrentXid().equals(xid)) { throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); } try { connection.rollback(); } catch (final SQLException e) { throw (XAException) new XAException().initCause(e); } finally { try { connection.setAutoCommit(originalAutoCommit); } catch (final SQLException ignored) { // Ignored. } this.currentXid = null; } } /** * Always returns false since we have no way to set a transaction timeout on a JDBC connection. * * @param transactionTimeout * ignored since we have no way to set a transaction timeout on a JDBC connection * @return always false */ @Override public boolean setTransactionTimeout(final int transactionTimeout) { return false; } /** * Signals that a connection has been enrolled in a transaction. This method saves off the current auto * commit flag, and then disables auto commit. The original auto commit setting is restored when the transaction * completes. * * @param xid * the id of the transaction branch for this connection * @param flag * either XAResource.TMNOFLAGS or XAResource.TMRESUME * @throws XAException * if the connection is already enlisted in another transaction, or if auto-commit could not be * disabled */ @Override public synchronized void start(final Xid xid, final int flag) throws XAException { if (flag == XAResource.TMNOFLAGS) { // first time in this transaction // make sure we aren't already in another tx if (this.currentXid != null) { throw new XAException("Already enlisted in another transaction with xid " + xid); } // save off the current auto commit flag, so it can be restored after the transaction completes try { originalAutoCommit = connection.getAutoCommit(); } catch (final SQLException ignored) { // no big deal, just assume it was off originalAutoCommit = true; } // update the auto commit flag try { connection.setAutoCommit(false); } catch (final SQLException e) { throw (XAException) new XAException("Count not turn off auto commit for a XA transaction") .initCause(e); } this.currentXid = xid; } else if (flag == XAResource.TMRESUME) { if (!xid.equals(this.currentXid)) { throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid + ", but was " + xid); } } else { throw new XAException("Unknown start flag " + flag); } } } private final TransactionRegistry transactionRegistry; private final ConnectionFactory connectionFactory; /** * Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections. * The connections are enlisted into transactions using the specified transaction manager. * * @param transactionManager * the transaction manager in which connections will be enlisted * @param connectionFactory * the connection factory from which connections will be retrieved */ public LocalXAConnectionFactory(final TransactionManager transactionManager, final ConnectionFactory connectionFactory) { this(transactionManager, null, connectionFactory); } /** * Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections. * The connections are enlisted into transactions using the specified transaction manager. * * @param transactionManager * the transaction manager in which connections will be enlisted * @param transactionSynchronizationRegistry * the optional TSR to register synchronizations with * @param connectionFactory * the connection factory from which connections will be retrieved * @since 2.8.0 */ public LocalXAConnectionFactory(final TransactionManager transactionManager, final TransactionSynchronizationRegistry transactionSynchronizationRegistry, final ConnectionFactory connectionFactory) { Objects.requireNonNull(transactionManager, "transactionManager"); Objects.requireNonNull(connectionFactory, "connectionFactory"); this.transactionRegistry = new TransactionRegistry(transactionManager, transactionSynchronizationRegistry); this.connectionFactory = connectionFactory; } @Override public Connection createConnection() throws SQLException { // create a new connection final Connection connection = connectionFactory.createConnection(); // create a XAResource to manage the connection during XA transactions final XAResource xaResource = new LocalXAResource(connection); // register the xa resource for the connection transactionRegistry.registerConnection(connection, xaResource); return connection; } /** * @return The connection factory. * @since 2.6.0 */ public ConnectionFactory getConnectionFactory() { return connectionFactory; } @Override public TransactionRegistry getTransactionRegistry() { return transactionRegistry; } } ManagedConnection.java000066400000000000000000000316671447311732500342030ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.dbcp2.DelegatingConnection; import org.apache.commons.pool2.ObjectPool; /** * ManagedConnection is responsible for managing a database connection in a transactional environment (typically called * "Container Managed"). A managed connection operates like any other connection when no global transaction (a.k.a. XA * transaction or JTA Transaction) is in progress. When a global transaction is active a single physical connection to * the database is used by all ManagedConnections accessed in the scope of the transaction. Connection sharing means * that all data access during a transaction has a consistent view of the database. When the global transaction is * committed or rolled back the enlisted connections are committed or rolled back. Typically, upon transaction * completion, a connection returns to the auto commit setting in effect before being enlisted in the transaction, but * some vendors do not properly implement this. *

* When enlisted in a transaction the setAutoCommit(), commit(), rollback(), and setReadOnly() methods throw a * SQLException. This is necessary to assure that the transaction completes as a single unit. *

* * @param * the Connection type * * @since 2.0 */ public class ManagedConnection extends DelegatingConnection { /** * Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events. * * @since 2.0 */ protected class CompletionListener implements TransactionContextListener { @Override public void afterCompletion(final TransactionContext completedContext, final boolean committed) { if (completedContext == transactionContext) { transactionComplete(); } } } private final ObjectPool pool; private final TransactionRegistry transactionRegistry; private final boolean accessToUnderlyingConnectionAllowed; private TransactionContext transactionContext; private boolean isSharedConnection; private final Lock lock; /** * Constructs a new instance responsible for managing a database connection in a transactional environment. * * @param pool * The connection pool. * @param transactionRegistry * The transaction registry. * @param accessToUnderlyingConnectionAllowed * Whether or not to allow access to the underlying Connection. * @throws SQLException * Thrown when there is problem managing transactions. */ public ManagedConnection(final ObjectPool pool, final TransactionRegistry transactionRegistry, final boolean accessToUnderlyingConnectionAllowed) throws SQLException { super(null); this.pool = pool; this.transactionRegistry = transactionRegistry; this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed; this.lock = new ReentrantLock(); updateTransactionStatus(); } @Override protected void checkOpen() throws SQLException { super.checkOpen(); updateTransactionStatus(); } @Override public void close() throws SQLException { if (!isClosedInternal()) { // Don't actually close the connection if in a transaction. The // connection will be closed by the transactionComplete method. // // DBCP-484 we need to make sure setClosedInternal(true) being // invoked if transactionContext is not null as this value will // be modified by the transactionComplete method which could run // in the different thread with the transaction calling back. lock.lock(); try { if (transactionContext == null || transactionContext.isTransactionComplete()) { super.close(); } } finally { try { setClosedInternal(true); } finally { lock.unlock(); } } } } @Override public void commit() throws SQLException { if (transactionContext != null) { throw new SQLException("Commit can not be set while enrolled in a transaction"); } super.commit(); } @Override public C getDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return getDelegateInternal(); } return null; } // // The following methods can't be used while enlisted in a transaction // @Override public Connection getInnermostDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return super.getInnermostDelegateInternal(); } return null; } /** * @return The transaction context. * @since 2.6.0 */ public TransactionContext getTransactionContext() { return transactionContext; } /** * @return The transaction registry. * @since 2.6.0 */ public TransactionRegistry getTransactionRegistry() { return transactionRegistry; } /** * If false, getDelegate() and getInnermostDelegate() will return null. * * @return if false, getDelegate() and getInnermostDelegate() will return null */ public boolean isAccessToUnderlyingConnectionAllowed() { return accessToUnderlyingConnectionAllowed; } @Override public void rollback() throws SQLException { if (transactionContext != null) { throw new SQLException("Commit can not be set while enrolled in a transaction"); } super.rollback(); } @Override public void setAutoCommit(final boolean autoCommit) throws SQLException { if (transactionContext != null) { throw new SQLException("Auto-commit can not be set while enrolled in a transaction"); } super.setAutoCommit(autoCommit); } @Override public void setReadOnly(final boolean readOnly) throws SQLException { if (transactionContext != null) { throw new SQLException("Read-only can not be set while enrolled in a transaction"); } super.setReadOnly(readOnly); } /** * Completes the transaction. */ protected void transactionComplete() { lock.lock(); try { transactionContext.completeTransaction(); } finally { lock.unlock(); } // If we were using a shared connection, clear the reference now that // the transaction has completed if (isSharedConnection) { setDelegate(null); isSharedConnection = false; } // autoCommit may have been changed directly on the underlying connection clearCachedState(); // If this connection was closed during the transaction and there is // still a delegate present close it final Connection delegate = getDelegateInternal(); if (isClosedInternal() && delegate != null) { try { setDelegate(null); if (!delegate.isClosed()) { delegate.close(); } } catch (final SQLException ignored) { // Not a whole lot we can do here as connection is closed // and this is a transaction callback so there is no // way to report the error. } } } private void updateTransactionStatus() throws SQLException { // if there is an active transaction context, assure the transaction context hasn't changed if (transactionContext != null && !transactionContext.isTransactionComplete()) { if (transactionContext.isActive()) { if (transactionContext != transactionRegistry.getActiveTransactionContext()) { throw new SQLException("Connection can not be used while enlisted in another transaction"); } return; } // transaction should have been cleared up by TransactionContextListener, but in // rare cases another lister could have registered which uses the connection before // our listener is called. In that rare case, trigger the transaction complete call now transactionComplete(); } // the existing transaction context ended (or we didn't have one), get the active transaction context transactionContext = transactionRegistry.getActiveTransactionContext(); // if there is an active transaction context, and it already has a shared connection, use it if (transactionContext != null && transactionContext.getSharedConnection() != null) { // A connection for the connection factory has already been enrolled // in the transaction, replace our delegate with the enrolled connection // return current connection to the pool @SuppressWarnings("resource") final C connection = getDelegateInternal(); setDelegate(null); if (connection != null && transactionContext.getSharedConnection() != connection) { try { pool.returnObject(connection); } catch (final Exception e) { // whatever... try to invalidate the connection try { pool.invalidateObject(connection); } catch (final Exception ignored) { // no big deal } } } // add a listener to the transaction context transactionContext.addTransactionContextListener(new CompletionListener()); // Set our delegate to the shared connection. Note that this will // always be of type C since it has been shared by another // connection from the same pool. @SuppressWarnings("unchecked") final C shared = (C) transactionContext.getSharedConnection(); setDelegate(shared); // remember that we are using a shared connection, so it can be cleared after the // transaction completes isSharedConnection = true; } else { C connection = getDelegateInternal(); // if our delegate is null, create one if (connection == null) { try { // borrow a new connection from the pool connection = pool.borrowObject(); setDelegate(connection); } catch (final Exception e) { throw new SQLException("Unable to acquire a new connection from the pool", e); } } // if we have a transaction, out delegate becomes the shared delegate if (transactionContext != null) { // add a listener to the transaction context transactionContext.addTransactionContextListener(new CompletionListener()); // register our connection as the shared connection try { transactionContext.setSharedConnection(connection); } catch (final SQLException e) { // transaction is hosed transactionContext = null; try { pool.invalidateObject(connection); } catch (final Exception ignored) { // we are try but no luck } throw e; } } } // autoCommit may have been changed directly on the underlying // connection clearCachedState(); } } ManagedDataSource.java000066400000000000000000000072021447311732500341220ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import java.util.Objects; import org.apache.commons.dbcp2.PoolingDataSource; import org.apache.commons.pool2.ObjectPool; /** * The ManagedDataSource is a PoolingDataSource that creates ManagedConnections. * * @param * The kind of {@link Connection} to manage. * @since 2.0 */ public class ManagedDataSource extends PoolingDataSource { private TransactionRegistry transactionRegistry; /** * Creates a ManagedDataSource which obtains connections from the specified pool and manages them using the * specified transaction registry. The TransactionRegistry must be the transaction registry obtained from the * XAConnectionFactory used to create the connection pool. If not, an error will occur when attempting to use the * connection in a global transaction because the XAResource object associated with the connection will be * unavailable. * * @param pool * the connection pool * @param transactionRegistry * the transaction registry obtained from the XAConnectionFactory used to create the connection pool * object factory */ public ManagedDataSource(final ObjectPool pool, final TransactionRegistry transactionRegistry) { super(pool); this.transactionRegistry = transactionRegistry; } @Override public Connection getConnection() throws SQLException { if (getPool() == null) { throw new IllegalStateException("Pool has not been set"); } if (transactionRegistry == null) { throw new IllegalStateException("TransactionRegistry has not been set"); } return new ManagedConnection<>(getPool(), transactionRegistry, isAccessToUnderlyingConnectionAllowed()); } /** * Gets the transaction registry. * * @return The transaction registry. * @see #setTransactionRegistry(TransactionRegistry) * @since 2.6.0 */ public TransactionRegistry getTransactionRegistry() { return transactionRegistry; } /** * Sets the transaction registry from the XAConnectionFactory used to create the pool. The transaction registry can * only be set once using either a connector or this setter method. * * @param transactionRegistry * the transaction registry acquired from the XAConnectionFactory used to create the pool */ public void setTransactionRegistry(final TransactionRegistry transactionRegistry) { if (this.transactionRegistry != null) { throw new IllegalStateException("TransactionRegistry already set"); } Objects.requireNonNull(transactionRegistry, "transactionRegistry"); this.transactionRegistry = transactionRegistry; } } PoolableManagedConnection.java000066400000000000000000000061521447311732500356500ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import java.util.Collection; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.pool2.ObjectPool; /** * PoolableConnection that unregisters from TransactionRegistry on Connection real destroy. * * @see PoolableConnection * @since 2.0 */ public class PoolableManagedConnection extends PoolableConnection { private final TransactionRegistry transactionRegistry; /** * Create a PoolableManagedConnection. * * @param transactionRegistry * transaction registry * @param conn * underlying connection * @param pool * connection pool */ public PoolableManagedConnection(final TransactionRegistry transactionRegistry, final Connection conn, final ObjectPool pool) { this(transactionRegistry, conn, pool, null, true); } /** * Create a PoolableManagedConnection. * * @param transactionRegistry * transaction registry * @param conn * underlying connection * @param pool * connection pool * @param disconnectSqlCodes * SQL_STATE codes considered fatal disconnection errors * @param fastFailValidation * true means fatal disconnection errors cause subsequent validations to fail immediately (no attempt to * run query or isValid) */ public PoolableManagedConnection(final TransactionRegistry transactionRegistry, final Connection conn, final ObjectPool pool, final Collection disconnectSqlCodes, final boolean fastFailValidation) { super(conn, pool, null, disconnectSqlCodes, fastFailValidation); this.transactionRegistry = transactionRegistry; } /** * @return The transaction registry. * @since 2.6.0 */ public TransactionRegistry getTransactionRegistry() { return transactionRegistry; } /** * Actually close the underlying connection. */ @Override public void reallyClose() throws SQLException { try { super.reallyClose(); } finally { transactionRegistry.unregisterConnection(this); } } } PoolableManagedConnectionFactory.java000066400000000000000000000120501447311732500371720ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import javax.management.ObjectName; import org.apache.commons.dbcp2.Constants; import org.apache.commons.dbcp2.DelegatingPreparedStatement; import org.apache.commons.dbcp2.PStmtKey; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingConnection; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; /** * A {@link PoolableConnectionFactory} that creates {@link PoolableManagedConnection}s. * * @since 2.0 */ public class PoolableManagedConnectionFactory extends PoolableConnectionFactory { /** Transaction registry associated with connections created by this factory */ private final TransactionRegistry transactionRegistry; /** * Creates a PoolableManagedConnectionFactory and attach it to a connection pool. * * @param connFactory * XAConnectionFactory * @param dataSourceJmxName * The data source name. */ public PoolableManagedConnectionFactory(final XAConnectionFactory connFactory, final ObjectName dataSourceJmxName) { super(connFactory, dataSourceJmxName); this.transactionRegistry = connFactory.getTransactionRegistry(); } /** * @return The transaction registry. * @since 2.6.0 */ public TransactionRegistry getTransactionRegistry() { return transactionRegistry; } /** * Uses the configured XAConnectionFactory to create a {@link PoolableManagedConnection}. Throws * {@code IllegalStateException} if the connection factory returns null. Also initializes the connection using * configured initialization SQL (if provided) and sets up a prepared statement pool associated with the * PoolableManagedConnection if statement pooling is enabled. */ @SuppressWarnings("resource") // Connection is released elsewhere. @Override public synchronized PooledObject makeObject() throws SQLException { Connection conn = getConnectionFactory().createConnection(); if (conn == null) { throw new IllegalStateException("Connection factory returned null from createConnection"); } initializeConnection(conn); if (getPoolStatements()) { conn = new PoolingConnection(conn); final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig<>(); config.setMaxTotalPerKey(-1); config.setBlockWhenExhausted(false); config.setMaxWait(Duration.ZERO); config.setMaxIdlePerKey(1); config.setMaxTotal(getMaxOpenPreparedStatements()); final ObjectName dataSourceJmxName = getDataSourceJmxName(); final long connIndex = getConnectionIndex().getAndIncrement(); if (dataSourceJmxName != null) { final StringBuilder base = new StringBuilder(dataSourceJmxName.toString()); base.append(Constants.JMX_CONNECTION_BASE_EXT); base.append(connIndex); config.setJmxNameBase(base.toString()); config.setJmxNamePrefix(Constants.JMX_STATEMENT_POOL_PREFIX); } else { config.setJmxEnabled(false); } final KeyedObjectPool stmtPool = new GenericKeyedObjectPool<>( (PoolingConnection) conn, config); ((PoolingConnection) conn).setStatementPool(stmtPool); ((PoolingConnection) conn).setCacheState(getCacheState()); } final PoolableManagedConnection pmc = new PoolableManagedConnection(transactionRegistry, conn, getPool(), getDisconnectionSqlCodes(), isFastFailValidation()); pmc.setCacheState(getCacheState()); return new DefaultPooledObject<>(pmc); } } SynchronizationAdapter.java000066400000000000000000000022271447311732500353170ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import javax.transaction.Synchronization; /** * Implements {@link Synchronization} for subclasses. */ class SynchronizationAdapter implements Synchronization { @Override public void afterCompletion(final int status) { // Noop } @Override public void beforeCompletion() { // Noop } } TransactionContext.java000066400000000000000000000213511447311732500344460ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.lang.ref.WeakReference; import java.sql.Connection; import java.sql.SQLException; import java.util.Objects; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAResource; /** * TransactionContext represents the association between a single XAConnectionFactory and a Transaction. This context * contains a single shared connection which should be used by all ManagedConnections for the XAConnectionFactory, the * ability to listen for the transaction completion event, and a method to check the status of the transaction. * * @since 2.0 */ public class TransactionContext { private final TransactionRegistry transactionRegistry; private final WeakReference transactionRef; private final TransactionSynchronizationRegistry transactionSynchronizationRegistry; private Connection sharedConnection; private boolean transactionComplete; /** * Provided for backwards compatibility * * @param transactionRegistry the TransactionRegistry used to obtain the XAResource for the * shared connection * @param transaction the transaction */ public TransactionContext(final TransactionRegistry transactionRegistry, final Transaction transaction) { this (transactionRegistry, transaction, null); } /** * Creates a TransactionContext for the specified Transaction and TransactionRegistry. The TransactionRegistry is * used to obtain the XAResource for the shared connection when it is enlisted in the transaction. * * @param transactionRegistry * the TransactionRegistry used to obtain the XAResource for the shared connection * @param transaction * the transaction * @param transactionSynchronizationRegistry * The optional TSR to register synchronizations with * @since 2.6.0 */ public TransactionContext(final TransactionRegistry transactionRegistry, final Transaction transaction, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { Objects.requireNonNull(transactionRegistry, "transactionRegistry"); Objects.requireNonNull(transaction, "transaction"); this.transactionRegistry = transactionRegistry; this.transactionRef = new WeakReference<>(transaction); this.transactionComplete = false; this.transactionSynchronizationRegistry = transactionSynchronizationRegistry; } /** * Adds a listener for transaction completion events. * * @param listener * the listener to add * @throws SQLException * if a problem occurs adding the listener to the transaction */ public void addTransactionContextListener(final TransactionContextListener listener) throws SQLException { try { if (!isActive()) { final Transaction transaction = this.transactionRef.get(); listener.afterCompletion(this, transaction != null && transaction.getStatus() == Status.STATUS_COMMITTED); return; } final Synchronization s = new SynchronizationAdapter() { @Override public void afterCompletion(final int status) { listener.afterCompletion(TransactionContext.this, status == Status.STATUS_COMMITTED); } }; if (transactionSynchronizationRegistry != null) { transactionSynchronizationRegistry.registerInterposedSynchronization(s); } else { getTransaction().registerSynchronization(s); } } catch (final RollbackException ignored) { // JTA spec doesn't let us register with a transaction marked rollback only // just ignore this and the tx state will be cleared another way. } catch (final Exception e) { throw new SQLException("Unable to register transaction context listener", e); } } /** * Sets the transaction complete flag to true. * * @since 2.4.0 */ public void completeTransaction() { this.transactionComplete = true; } /** * Gets the connection shared by all ManagedConnections in the transaction. Specifically, connection using the same * XAConnectionFactory from which the TransactionRegistry was obtained. * * @return the shared connection for this transaction */ public Connection getSharedConnection() { return sharedConnection; } private Transaction getTransaction() throws SQLException { final Transaction transaction = this.transactionRef.get(); if (transaction == null) { throw new SQLException("Unable to enlist connection because the transaction has been garbage collected"); } return transaction; } /** * True if the transaction is active or marked for rollback only. * * @return true if the transaction is active or marked for rollback only; false otherwise * @throws SQLException * if a problem occurs obtaining the transaction status */ public boolean isActive() throws SQLException { try { final Transaction transaction = this.transactionRef.get(); if (transaction == null) { return false; } final int status = transaction.getStatus(); return status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK; } catch (final SystemException e) { throw new SQLException("Unable to get transaction status", e); } } /** * Gets the transaction complete flag to true. * * @return The transaction complete flag. * * @since 2.4.0 */ public boolean isTransactionComplete() { return this.transactionComplete; } /** * Sets the shared connection for this transaction. The shared connection is enlisted in the transaction. * * @param sharedConnection * the shared connection * @throws SQLException * if a shared connection is already set, if XAResource for the connection could not be found in the * transaction registry, or if there was a problem enlisting the connection in the transaction */ public void setSharedConnection(final Connection sharedConnection) throws SQLException { if (this.sharedConnection != null) { throw new IllegalStateException("A shared connection is already set"); } // This is the first use of the connection in this transaction, so we must // enlist it in the transaction final Transaction transaction = getTransaction(); try { final XAResource xaResource = transactionRegistry.getXAResource(sharedConnection); if (!transaction.enlistResource(xaResource)) { throw new SQLException("Unable to enlist connection in transaction: enlistResource returns 'false'."); } } catch (final IllegalStateException e) { // This can happen if the transaction is already timed out throw new SQLException("Unable to enlist connection in the transaction", e); } catch (final RollbackException ignored) { // transaction was rolled back... proceed as if there never was a transaction } catch (final SystemException e) { throw new SQLException("Unable to enlist connection the transaction", e); } this.sharedConnection = sharedConnection; } } TransactionContextListener.java000066400000000000000000000024451447311732500361570ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; /** * A listener for transaction completion events. * * @since 2.0 */ public interface TransactionContextListener { /** * Occurs after the transaction commits or rolls back. * * @param transactionContext * the transaction context that completed * @param committed * true if the transaction committed; false otherwise */ void afterCompletion(TransactionContext transactionContext, boolean committed); } TransactionRegistry.java000066400000000000000000000143451447311732500346370ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import java.util.Map; import java.util.Objects; import java.util.WeakHashMap; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAResource; import org.apache.commons.dbcp2.DelegatingConnection; /** * TransactionRegistry tracks Connections and XAResources in a transacted environment for a single XAConnectionFactory. *

* The TransactionRegistry hides the details of transaction processing from the existing DBCP pooling code, and gives * the ManagedConnection a way to enlist connections in a transaction, allowing for the maximal rescue of DBCP. *

* * @since 2.0 */ public class TransactionRegistry { private final TransactionManager transactionManager; private final Map caches = new WeakHashMap<>(); private final Map xaResources = new WeakHashMap<>(); private final TransactionSynchronizationRegistry transactionSynchronizationRegistry; /** * Provided for backwards compatibility * @param transactionManager the transaction manager used to enlist connections */ public TransactionRegistry(final TransactionManager transactionManager) { this (transactionManager, null); } /** * Creates a TransactionRegistry for the specified transaction manager. * * @param transactionManager * the transaction manager used to enlist connections. * @param transactionSynchronizationRegistry * The optional TSR to register synchronizations with * @since 2.6.0 */ public TransactionRegistry(final TransactionManager transactionManager, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { this.transactionManager = transactionManager; this.transactionSynchronizationRegistry = transactionSynchronizationRegistry; } /** * Gets the active TransactionContext or null if not Transaction is active. * * @return The active TransactionContext or null if no Transaction is active. * @throws SQLException * Thrown when an error occurs while fetching the transaction. */ public TransactionContext getActiveTransactionContext() throws SQLException { Transaction transaction = null; try { transaction = transactionManager.getTransaction(); // was there a transaction? if (transaction == null) { return null; } // This is the transaction on the thread so no need to check its status - we should try to use it and // fail later based on the subsequent status } catch (final SystemException e) { throw new SQLException("Unable to determine current transaction ", e); } // register the context (or create a new one) synchronized (this) { return caches.computeIfAbsent(transaction, k -> new TransactionContext(this, k, transactionSynchronizationRegistry)); } } private Connection getConnectionKey(final Connection connection) { final Connection result; if (connection instanceof DelegatingConnection) { result = ((DelegatingConnection) connection).getInnermostDelegateInternal(); } else { result = connection; } return result; } /** * Gets the XAResource registered for the connection. * * @param connection * the connection * @return The XAResource registered for the connection; never null. * @throws SQLException * Thrown when the connection does not have a registered XAResource. */ public synchronized XAResource getXAResource(final Connection connection) throws SQLException { Objects.requireNonNull(connection, "connection"); final Connection key = getConnectionKey(connection); final XAResource xaResource = xaResources.get(key); if (xaResource == null) { throw new SQLException("Connection does not have a registered XAResource " + connection); } return xaResource; } /** * Registers the association between a Connection and a XAResource. When a connection is enlisted in a transaction, * it is actually the XAResource that is given to the transaction manager. * * @param connection * The JDBC connection. * @param xaResource * The XAResource which managed the connection within a transaction. */ public synchronized void registerConnection(final Connection connection, final XAResource xaResource) { Objects.requireNonNull(connection, "connection"); Objects.requireNonNull(xaResource, "xaResource"); xaResources.put(connection, xaResource); } /** * Unregisters a destroyed connection from {@link TransactionRegistry}. * * @param connection * A destroyed connection from {@link TransactionRegistry}. */ public synchronized void unregisterConnection(final Connection connection) { xaResources.remove(getConnectionKey(connection)); } } XAConnectionFactory.java000066400000000000000000000044511447311732500344760ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbcp2.ConnectionFactory; /** * XAConnectionFactory is an extension of ConnectionFactory used to create connections in a transaction managed * environment. The XAConnectionFactory operates like a normal ConnectionFactory except a TransactionRegistry is * provided from which the XAResource for a connection can be obtained. This allows the existing DBCP pool code to work * with XAConnections and gives the ManagedConnection a way to enlist a connection in the transaction. * * @since 2.0 */ public interface XAConnectionFactory extends ConnectionFactory { /** * Create a new {@link java.sql.Connection} in an implementation specific fashion. *

* An implementation can assume that the caller of this will wrap the connection in a proxy that protects access to * the setAutoCommit, commit and rollback when enrolled in a XA transaction. *

* * @return a new {@link java.sql.Connection} * @throws java.sql.SQLException * if a database error occurs creating the connection */ @Override Connection createConnection() throws SQLException; /** * Gets the TransactionRegistry for this connection factory which contains the XAResource for every connection * created by this factory. * * @return the transaction registry for this connection factory */ TransactionRegistry getTransactionRegistry(); } package-info.java000066400000000000000000000036161447311732500331440ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/managed/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT 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 support for pooling of ManagedConnections. A managed * connection is responsible for managing a database connection in a * transactional environment (typically called Container Managed). * A managed connection operates like any other connection when no global * transaction (a.k.a. XA transaction or JTA Transaction) is in progress. * When a global transaction is active a single physical connection to the * database is used by all ManagedConnections accessed in the scope of the * transaction. Connection sharing means that all data access during a * transaction has a consistent view of the database. When the global * transaction is committed or rolled back the enlisted connections are * committed or rolled back. *

*

* This package supports full XADataSources and non-XA data sources using * local transaction semantics. non-XA data sources commit and rollback as * part of the transaction but are not recoverable in the case of an error * because they do not implement the two-phase commit protocol. *

*/ package org.apache.commons.dbcp2.managed; commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/overview.html000066400000000000000000000017131447311732500311700ustar00rootroot00000000000000 Overview of the org.apache.commons.dbcp component

Commons Database Connection Pooling

commons-dbcp-rel-commons-dbcp-2.10.0/src/main/java/org/apache/commons/dbcp2/package-info.java000066400000000000000000000154471447311732500316340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** *

* Database Connection Pool API. *

* * Overview in Dialog Form *

* Q: How do I use the DBCP package? *

*

* A: There are two primary ways to access the DBCP pool, as a {@link java.sql.Driver Driver}, or as a * {@link javax.sql.DataSource DataSource}. You'll want to create an instance of * {@link org.apache.commons.dbcp2.PoolingDriver} or {@link org.apache.commons.dbcp2.PoolingDataSource}. When using one * of these interfaces, you can just use your JDBC objects the way you normally would. Closing a * {@link java.sql.Connection} will simply return it to its pool. *

*

* Q: But {@link org.apache.commons.dbcp2.PoolingDriver PoolingDriver} and * {@link org.apache.commons.dbcp2.PoolingDataSource PoolingDataSource} both expect an * {@link org.apache.commons.pool2.ObjectPool ObjectPool} as an input. Where do I get one of those? *

*

* A: The {@link org.apache.commons.pool2.ObjectPool ObjectPool} interface is defined in Commons Pool. You can use one * of the provided implementations such as {@link org.apache.commons.pool2.impl.GenericObjectPool GenericObjectPool}, * {@link org.apache.commons.pool2.proxy.ProxiedObjectPool ProxiedObjectPool} or * {@link org.apache.commons.pool2.impl.SoftReferenceObjectPool SoftReferenceObjectPool} or you can create your own. *

*

* Q: Ok, I've found an {@link org.apache.commons.pool2.ObjectPool ObjectPool} implementation that I think suits my * connection pooling needs. But it wants a {@link org.apache.commons.pool2.PooledObjectFactory PooledObjectFactory}. * What should I use for that? *

*

* A: The DBCP package provides a class for this purpose. It's called * {@link org.apache.commons.dbcp2.PoolableConnectionFactory}. It implements the factory and lifecycle methods of * {@link org.apache.commons.pool2.PooledObjectFactory} for {@link java.sql.Connection}s. But it doesn't create the * actual database {@link java.sql.Connection}s itself, it uses a {@link org.apache.commons.dbcp2.ConnectionFactory} for * that. The {@link org.apache.commons.dbcp2.PoolableConnectionFactory} will take {@link java.sql.Connection}s created * by the {@link org.apache.commons.dbcp2.ConnectionFactory} and wrap them with classes that implement the pooling * behavior. *

*

* Several implementations of {@link org.apache.commons.dbcp2.ConnectionFactory} are provided--one that uses * {@link java.sql.DriverManager} to create connections * ({@link org.apache.commons.dbcp2.DriverManagerConnectionFactory}), one that uses a {@link java.sql.Driver} to create * connections ({@link org.apache.commons.dbcp2.DriverConnectionFactory}), one that uses a {@link javax.sql.DataSource} * to create connections ({@link org.apache.commons.dbcp2.DataSourceConnectionFactory}). *

*

* Q: I think I'm starting to get it, but can you walk me though it again? *

*

* A: Sure. Let's assume you want to create a {@link javax.sql.DataSource} that pools {@link java.sql.Connection}s. * Let's also assume that those pooled {@link java.sql.Connection}s should be obtained from the * {@link java.sql.DriverManager}. You'll want to create a {@link org.apache.commons.dbcp2.PoolingDataSource}. *

*

* The {@link org.apache.commons.dbcp2.PoolingDataSource} uses an underlying {@link org.apache.commons.pool2.ObjectPool} * to create and store its {@link java.sql.Connection}. *

*

* To create a {@link org.apache.commons.pool2.ObjectPool}, you'll need a * {@link org.apache.commons.pool2.PooledObjectFactory} that creates the actual {@link java.sql.Connection}s. That's * what {@link org.apache.commons.dbcp2.PoolableConnectionFactory} is for. *

*

* To create the {@link org.apache.commons.dbcp2.PoolableConnectionFactory}, you'll need at least two things: *

*
    *
  1. A {@link org.apache.commons.dbcp2.ConnectionFactory} from which the actual database {@link java.sql.Connection}s * will be obtained.
  2. *
  3. An empty and factory-less {@link org.apache.commons.pool2.ObjectPool} in which the {@link java.sql.Connection}s * will be stored.
    * When you pass an {@link org.apache.commons.pool2.ObjectPool} into the * {@link org.apache.commons.dbcp2.PoolableConnectionFactory}, it will automatically register itself as the * {@link org.apache.commons.pool2.PooledObjectFactory} for that pool.
  4. *
*

* In code, that might look like this: *

* *
 * GenericObjectPool connectionPool = new GenericObjectPool(null);
 * ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
 *         "password");
 * PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
 *         connectionPool, null, null, false, true);
 * PoolingDataSource dataSource = new PoolingDataSource(connectionPool);
 * 
*

* To create a {@link org.apache.commons.dbcp2.PoolingDriver}, we do the same thing, except that instead of creating a * {@link javax.sql.DataSource} on the last line, we create a {@link org.apache.commons.dbcp2.PoolingDriver}, and * register the {@code connectionPool} with it. E.g.,: *

* *
 * GenericObjectPool connectionPool = new GenericObjectPool(null);
 * ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
 *         "password");
 * PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
 *         connectionPool, null, null, false, true);
 * PoolingDriver driver = new PoolingDriver();
 * driver.registerPool("example", connectionPool);
 * 
*

* Since the {@link org.apache.commons.dbcp2.PoolingDriver} registers itself with the {@link java.sql.DriverManager} * when it is created, now you can just go to the {@link java.sql.DriverManager} to create your * {@link java.sql.Connection}s, like you normally would: *

* *
 * Connection conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:example");
 * 
*/ package org.apache.commons.dbcp2; commons-dbcp-rel-commons-dbcp-2.10.0/src/main/resources/000077500000000000000000000000001447311732500230465ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/resources/org/000077500000000000000000000000001447311732500236355ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/resources/org/apache/000077500000000000000000000000001447311732500250565ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/resources/org/apache/commons/000077500000000000000000000000001447311732500265315ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/resources/org/apache/commons/dbcp2/000077500000000000000000000000001447311732500275235ustar00rootroot00000000000000LocalStrings.properties000066400000000000000000000025111447311732500341650ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/main/resources/org/apache/commons/dbcp2# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. connectionFactory.lifetimeExceeded=The lifetime of the connection [{0}] exceeds the maximum permitted value of [{1}]. poolableConnectionFactory.validateObject.fail=Failed to validate a poolable connection. poolableConnection.validate.fastFail=Fatal SQLException was thrown previously on this connection. swallowedExceptionLogger.onSwallowedException=An internal object pool swallowed an Exception. poolingDataSource.factoryConfig=PoolableConnectionFactory not linked to pool. Calling setPool() to fix the configuration. pool.close.fail=Cannot close connection pool. commons-dbcp-rel-commons-dbcp-2.10.0/src/media/000077500000000000000000000000001447311732500211675ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/media/dbcp-logo-white.xcf000066400000000000000000000573311447311732500246660ustar00rootroot00000000000000gimp xcf fileæPBB<K gimp-commentCreated with The GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) Æ0 N$Ģ3Ķ\ö TM˙     Ô><8gimp-text-layer(text "TM") (font "Sans") (font-size 8.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode fixed) (box-width 12.000000) (box-height 11.000000) (box-unit pixels) ­ Á Ņ„„„#°öɰĨ-É>ÉöČ8ÂxĄĐöČ8€˛8wČöČ8€PÛČöČ8€?ČúČ8€ūČnDBCP˙     j%7Ņné Bnũ F€€€ū8U UUū8û8Uqâ˙ ˙üÆĒUUū˙ ˙üâ8ū˙˙üĒU8üUâ˙˙ũâq ūq˙˙ũUüUĒ˙˙ũÆ ūÆ˙˙ūUũqâ˙˙ũâū˙˙ũâ˙˙ũâ ūĒ˙˙ūUũâ˙˙ũâ8˙ũâ˙˙ūâ ūĒ˙˙ūU ūÆ˙˙ũâ˙ ū8˙˙ūqūUūĒ˙˙ūU ũâ˙˙ūÆ˙ ūâ˙˙ūÆūâūĒ˙˙ūU ūU˙˙ūU˙ ūĒ˙˙ũ˙ūĒ˙˙ūU ūâ˙˙ūÆ˙ ūĒ˙˙˙ūĒ˙˙ūU ūq˙˙ū8˙ ūÆ˙˙ūâüq˙˙ūĒ˙˙ūU ū˙˙ū˙ ū˙˙ūüĒ˙˙ūĒ˙˙ūU ˙ūĒ˙ ūĒ˙˙ũâ˙ūĒ˙˙ūU ūĒ˙˙˙ūĒ˙˙ūUū˙˙ūĒ˙˙ūU ūĒ˙˙˙ūUUũqĒ˙˙ũÆūU˙˙ūĒ˙˙ūU ūĒ˙˙˙ũĒūU˙˙ūĒ˙˙ūU ūĒ˙˙˙üUqÆ˙˙ũÆ8ūU˙˙ūĒ˙˙ūU ūĒ˙˙˙ũ8â˙˙ūUūU˙˙ūĒ˙˙ūU ūâ˙˙ūĒ˙ ũâ˙˙ū8ū8˙˙ūĒ˙˙ūU ˙ū˙ ū8˙˙ūÆ˙ūĒ˙˙ūU ūU˙˙ū8˙ ūĒ˙˙ūüÆ˙˙ūĒ˙˙ūU ūÆ˙˙ūâ˙ ūU˙˙ūUüq˙˙ūĒ˙˙ūU ū8˙˙ūq˙ ūU˙˙ūUü˙˙ūĒ˙˙ūU ūÆ˙˙ūÆ˙ ūq˙˙ūũ˙ūĒ˙˙ūU ūĒ˙˙ũâ˙ ūÆ˙˙ūâũâūĒ˙˙ūU ūĒ˙˙ū8˙ ūU˙˙ūUūUūĒ˙˙ūUũĒ˙˙ũâ˙ ūU˙˙ūĒ ˙ūqũ8˙˙ū ūU˙˙ūũ8˙˙ūĒ ũĒ˙˙ūâĒĒ˙üÆq ũ8â˙˙ūÆĒĒ˙ũÆ8 ūqĒ ĒUū ĒUMdddüUĒÆ˙˙üĒ8úUU Uū ū˙˙ũĒqUUņĒâ˙Æqq˙UUUÆ˙ ˙ũÆqųUâ˙˙ūq˙˙ūūÆ˙˙ũÆ8ũUÆ˙˙ũâUúq˙˙â8úâ˙˙Ēūq˙˙ūĒūU˙˙ûUU˙˙ū8 û˙˙ĒūU˙˙ūĒūq˙˙ũ8˙˙ū üq˙ĒūU˙˙ūĒūâ˙˙úÆ˙˙âũâĒūU˙˙ūĒūĒ˙˙û˙˙ũqâūU˙˙ūĒūU˙˙ûU˙˙8ū˙ūU˙˙ūĒūU˙˙üU˙˙ūqūU˙˙ūĒūU˙˙üU˙ĒūU˙˙ūĒū˙˙ü˙ĒūU˙˙ūĒūâ˙˙ûÆ˙UūU˙˙ūĒū˙˙û8˙UūU˙˙ūĒū˙˙úU˙UūU˙˙øâĒqUUqâ˙˙ũâUũ˙UūU˙˙üÆĒĒ˙˙üâĒUũ˙UūU˙˙ūĒ ũ˙UūU˙˙ūĒ ũ˙ĒūU˙˙ūĒ ũ˙ÆūU˙˙ūĒ ˙ūU˙˙ūĒ ˙ūqūU˙˙ūĒ ˙ūâũUqūU˙˙ūĒ ˙ūq ũâūU˙˙ūĒ ˙ūU üâ8ūU˙˙ūĒ ūU˙˙ūU üâUūU˙˙ūĒ ūU˙˙ũĒüq˙UūĒ˙˙ũÆ˙˙ũƍUUúqĒ˙Æ8ūq˙˙ũĒü8Ēâ˙˙ũĒ8ū8Ē ĒūqūUUū7Œ<Drop-Shadow#2Ė     c8 øŒ< $“$ŸŒ< ,#g        ųúūų  ú  ô      ú÷    ū ō ü÷ ÷ ūā   ėč  !! øë !! é  $&()('&$#! ī #&())ö('&%$##""č "&+.010/-+)'&%%ī$#!  #'*-/11û/.,+**ū)ņ !'-2588ų631.,+**+é*)'%#"!"$'*.258998753211ã &-39=?@?<9630/../0122û1/-+))ņ+.15:=@AA@><98778Æ ")18>CEEDA=9631012467898753100148<@DGHGFCA><;<<>?Æ $-5=CHJJHE@<74212469;>??>=;9778;>BGJMNMKHEB@??ACEÛ &/8@GKNMKGB<8411247;>BDEEDB@>>íADHLPRRQOLHECBCEGJÛ (1:CJNQPMHB<730/037;@DHJKKIGEEíGIMQTVWURNJGEDEGKNÆ (2;DKPRQNHB;50-,.15:@FJNPPOMLJJLNRUXZZXUPLIFFGJNRÆ )3FMSWYYXWUTUVY\^__\YTPLIIKNSWÆ  )3=FMQSQMF>6.($#$'-45.'#""&+2:CKRX[\\[YXXY\^`a`]YSNIFEFINSŪ  )3=FMQSRMG?70*&%&).5DKOSTTSQPOPRUX[\[YUOJEA@ACHMß (2DIMOOéMKJJLNRUXZYWSNHD@>?AFKÛ (1;CJOQQMHB<62/./15:>CGIJJIGEEíGJNRUWWUQLGB?==@CHÆ &09AHLONLGB<73100369=ACDEDB@?>?AEIMQSSQNJEA><<>AEá %-6>DIKKIFA<74101358:=>>į<:9879;?DHLNONKGC?<::<>Aâ "*2:@DGGEB>:63100135788æ753101259>BFHIHFC?<9889:=ã  '.5;?ABA>;741/../0122å1/-+*)*,/37;8644568č #)/48:;:8630.,++,+ę)(&$#"#%(,058;<<;864200ũ12č $)-02331/-*)'&&æ%$#" "%)-024431/-,+**ū+é "&)*++*(&%#"!  į"%(*+,+*)'&%$$ō !##î"! đ "#$##! ņ ä ÷ķ đ  ÷ ūõ    ų ö  ū õ    ÷    ū û   ū   @*   ūū øø ī ķ   ü   ë  ö  øÜ    Đ   ø !""æ!  !  öø !#%')**æ)('&%$"! ('%"÷ !""!"#$Û%&(*,/1233210/.-,*(&#  1/-*'#ø!#%&''ũ&%$$Ã%&&'(())*+,.1479;<;;98765421.+'"8763/+&""$')+,,+*)(&&ī'()*+,--.0247;>ACCŨBA?>=<;:963/)$@?>;73.*&$$%&),.011ú/-+)'&&į'(*+-./01369=ADGIJJIGEDCBBŨ@>;60*#FFEC?:61.++,.03577642/,)'%%č&')+-/02369=AEJMOPONLJIHHįGEB=70)!LMLJFB=8522357:<<Ü:73/+(%#"#$%'),.0247;?DIMQSTTRPNMLLMM€;KHD=6-%QRRQMID?<:9:5+"Y[\[XTOKHFFGIKLLJFA:3,& !$'*.39?FMSX[\[YVTSRSUVWVTOH@7-#\^`_\XTPMLLMOQQPMHB:2*##'+07>EMSY\]\ZXUTSTUWXWUPIA7-$^acb_\XTRPQRTUUTPJB:1(!"'-44+"begfda]ZXXYZ\\[XSKB8.% !(08BKSY]__]ZWTSRRSRQNIB:1( dghhfc_][[\]__^ZTLB8-$ €Ģ %.7AJRY^`_]ZWTRPPONLID=5-%dgiigda_]]^`aa`\UMB8-#  #,6@IRY^`_]ZVROMLJIFC=70(!dgiihec`__`bcca\VMC8-#  "+5?IRY^`_]YTPLIGEB?;60*#cgiihfdbaaÂcdda]VMC8-$  !*4?IQY]_^[WRMHDA>;84/)$aehihgecbbdÅb^WND:/%  !*4>HQX\^]ZUOID?;740,'"_cghhgecbbÂcddb^WOE;0&  !*4>HQW\][WRLE?940,($  \aeggfecaaŋbcca]XPG<2)   "*4>HPVZ[YUOH@93.)%! Y_cefeca`__``Ä_\WPH>5+# #+4>HPVYYWRKD<4.(# V\`bcba^]\\]ąZVPI@7.& $,5>GOTWWTOH@80(" SY]_`_][YWWXXYYXUPIB91*#%,5>FNSUURLE<4+$ PUY[[ZXVSRQRSTUTRNIC<4-'!%-5=ELQSROIB90(  MQTVVUROMKJKLNOONLHC=70*% × &-46-$ IMOPPNKHECCŦEGHJJIFB=82-($  &,3:AGKMKHB;2*! EGIIHFC@=;:;CGHGD>7/' ?ABB@>;75322479<>?>=;840,(%"#(.49>ABA>92+# ß9:;:852/,*)*,.146898752/,)%# æ %*/49<=<84.'  3Į1/-*&$"!"$&),/12321/-*'$"!%*.25542-(" +î*)'$!!$')+,,ô*)'$" č $(+-.-+'# ö$##!ę"$%&&%$"!č!$&&%$! ö÷õč í ö  ø ķ ö ę   ų ķ ë  ų ÷  ô øú   ųû  ÷úøūū     QĐĐĐk üûûúųų ø ø ø ø ÷ ÷ ÷ ÷ ÷ ÷ ÷ ø ø ø ø ų ųúûûüF#×commons˙     %O×%k3ģ3Į×%‡)Œ-Š21€€€ũ8qĒĒüUũ8UĒĒũq8üq8ũqâ˙˙ũĒ ũqâ˙˙ü⍠úUĒ˙˙Uõ8â˙˙8Ē˙˙ūUôUâ˙˙8qâ˙˙ūUüqĒ˙˙ūUúU˙˙ÆūÆ˙˙ūUūq˙˙ūUūĒ˙˙ūĒüĒĒ˙˙üUÆûU˙˙âūq˙˙ūâūU˙˙ūUūĒ˙˙ūĒūq˙˙ųĒ˙Æ8˙˙ūū˙˙ūUū8˙˙ūÆ ūâ˙˙ūU˙ūĒûâ˙˙ūÆ˙˙ūūÆ˙˙ūU ū8˙˙ūâ˙ūÆūq˙˙ū8úâ˙˙Uū8˙˙ ūâ˙˙ūq˙ūĒūÆ˙˙ ūūĒ˙˙ūÆ ū˙˙ūÆ˙ûĒ˙˙ūÆ˙ūĒ ū8˙˙˙ûĒU˙˙ūĒū˙˙ūĒ ˙ū8˙ûĒ˙˙ūĒūU˙˙ūĒ ūâ˙˙ūU˙ûĒĒ˙˙ūĒūU˙˙ūĒ ūĒ˙˙ūU˙ûĒĒ˙˙ūâūU˙˙ ūĒ˙˙ūU˙ûĒĒ˙˙ūU˙˙ ūĒ˙˙ū8˙ûĒĒ˙˙ūU˙ūU ūĒ˙˙˙ûĒU˙˙ūÆ ū8ūâ˙˙ū ūĒ˙˙ūÆ˙ûĒ8˙˙ū8 ũUâū˙˙ūÆ ˙ūq˙ūĒūâ˙˙ũâ ü8˙8ū8˙˙ū8 ū˙˙ū˙ūĒūq˙˙ũĒü8âÆūÆ˙˙ū ūq˙˙ū˙ūĒūâ˙˙ũâ8ûq˙˙ū˙˙ūûâ˙˙â˙ūĒūU˙˙ũâUUúâ˙˙UūU˙˙ūÆúq˙˙â˙ūĒūU˙ ˙ūUūU˙˙ūĒúU˙˙âū˙˙ūĒūU˙ ˙ũâU ũ8â˙˙ôâqUÆ˙˙Æūq˙˙ūũÆ˙˙ũ ũqâ˙˙ũÆ8üUqÆ˙˙ũâĒũUĒĒũUũ8qĒĒũU Ē€€€ų8qĒĒ8ųUĒĒ8 ũ8ųUĒĒqųUĒ8Æ˙˙ũÆũqâ˙˙ũÆúqÆ˙˙ũqâ˙˙ūũ˙˙ū˙˙ūÆũ8â˙˙ūâü8Æ˙˙ũÆ˙˙ūqūq˙˙úâUU˙˙ųqU˙˙ĒUUũâ˙˙ūqüÆĒÆ˙˙öUâ˙ÆqUUÆ˙˙ųĒ˙âUUū8ū˙˙úâU˙Ēũâ˙˙ūâūÆ˙˙ûĒ˙ūq˙˙ûĒ˙q ū˙˙ūĒūq˙˙ū8ūU˙˙ūUūâ˙˙ūU ū8˙˙ūÆū8˙˙ūUūU˙˙ūqū˙˙ūq ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ˙ūĒ˙ūĒūU˙˙ūUūU˙˙ūU ū˙˙ūâ˙ūÆūq˙˙ūUūq˙˙ū ūq˙˙ūUūq˙˙ūūÆ˙˙ūÆūÆ˙˙ũâøU8qÆ˙˙÷ĒU88qÆ˙˙÷âU8Uâ˙˙üƍUüUâ˙˙ķâUUĒ8qĒ ĒûqqĒ Ēũq8Ē Ē Ēü8Ē€€€ĒũqüUĒĒũUü88ũqĒĒūU˙ū ũ8Æ˙˙ũĒ8 õ8â˙˙U˙˙ũâU˙ū ųÆ˙˙ÆUũUÆ˙˙ūĒüUĒâ˙˙ûU8â˙˙ûUĒ˙˙ūú8â˙˙ĒūU˙˙ũâĒ˙Uø˙âUUâ˙˙ūâūU˙˙ūúâ˙˙ĒūU˙˙ũâūĒ˙˙ûâ˙ĒūÆ˙˙ūUūÆ˙˙ūâūâ˙˙ūū˙˙ūĒūU˙˙ūUū8˙˙ūĒū˙˙ūq˙˙ūĒ ūâ˙˙ū8ūU˙˙ūqūâ˙˙ūâūU˙˙ūUūâ˙˙ūU ū˙˙ūÆūU˙˙ūUūĒ˙˙ūU˙˙ūUūU˙˙ū ū8˙˙ūūU˙˙ūUūĒ˙˙ūU˙˙ūUūĒ˙˙ ūâ˙˙ūUūU˙˙ūUūĒ˙˙ūU˙˙ūUūÆ˙˙ ūĒ˙˙ūūU˙˙ūUūĒ˙˙ūU˙˙ūU˙ ū˙˙ūĒūU˙˙ūUūĒ˙˙ūU˙˙ūU˙ ūU˙˙ūĒūU˙˙ūUūĒ˙˙ūU˙˙ūU˙ūU ūU˙˙ūĒūU˙˙ūUūĒ˙˙ūU˙˙ūU˙ūU ūU˙˙ūūU˙˙ūUūĒ˙˙ūU˙˙ūUūĒ˙˙ūĒ ūU˙˙ūUūU˙˙ūUūĒ˙˙ūU˙˙ūUū˙˙ūâ ūU˙˙ūūU˙˙ūUūĒ˙˙ūU˙˙ūUū8˙˙ū ūĒ˙˙ūÆūU˙˙ūUūĒ˙˙ūU˙˙ūUūâ˙˙ū ūÆ˙˙ūqūU˙˙ūUūĒ˙˙ūU˙˙ūUūq˙˙ūâ ū˙˙ūâūU˙˙ūUūĒ˙˙ūU˙˙ūUūÆ˙˙ūqū˙˙ū8ūU˙˙ūUūĒ˙˙ūU˙˙ūUũâ˙˙ūū˙˙ūUūU˙˙ūUūĒ˙˙ūU˙˙ūqũâ˙˙ũâúâ˙˙Uūq˙˙ūUūâ˙˙ûÆ˙˙ūÆũĒ˙˙õ88˙˙âUūâ˙˙ūÆūU˙˙üqâ˙˙ûÆqUũ8Æ˙˙ũâqü8qâ˙˙÷âUUĒ˙˙ Ēū8ũUĒĒũq8 ūqĒ Ēū8ĒĒVVV ũUĒĒúU ķ˙˙âĒĒÆ˙˙ĒÆ˙ûÆ˙â8ũ8Æ˙˙ûĒ˙˙8üâ˙˙û8˙˙Æü8˙˙û˙˙ĒũĒ˙ûĒ˙˙âũU˙ūĒ˙˙ūqū˙ūq˙˙ūqū8ū˙˙ũÆ8ū˙˙ũÆ ūĒ˙˙ũ ū˙˙ũâq ũ8â˙˙ũâ ūq˙˙ũâU ũ˙˙ũâ ũĒ˙˙ūũĒqūU˙˙ūâĒ ū˙˙ũĒ˙ū˙˙üĒ˙q˙ūÆûĒ˙âū˙˙ūqûĒ˙˙Ēû˙˙ĒūĒ˙˙ũÆ8ö˙˙ĒÆqøĒÆĒĒ˙˙âĒĒ˙ũâqĒū8ũ8ø8UĒĒUk 5õ8 Drop-ShadowĖ     ˙˙˙ú˙˙˙ú94{õ84—\Ū\ęõ84ŗ?I°T‡U  ūūūū øúųų ô  í     ų  ō ÷ ø ø ×  øî ÷ôøí  !#$%%÷$# ķ!"##$%%ų$" Đ  "$&')*+,,+*'%"!#$&'())*+,,ú*(&#!é !$&(*+-.0122į1.,)&#! !#$'(*+,--./02344ú31.,)×  #'),-/01346787642/,)(''(*,./11223û568:;;û9752ß !&*-/12334679:;<;9742/..č0245677665668:=?ABCB@=:đ "',024566Ų78:<=>>=;97544579;<==<:9878:>á=;:99:<>ABCCB@=;988:=@EIMOPONKâ &-38;==<:8655679;<=>==å>@BEGIIHFC?;9779<@FKPSUVTRÅ $+29=@AA>;853223579:;<==?ADGKMOOMJE@;7556:?EKQVZ[ZXé  (08>CEED@<830..Ü024689;=@CGLPSTSQLGA;63237=CKRX\__]à $,5=CGJIGB=72.+))*,.1369<@EJOTWXWTOHA:40/04:AJRY^abač '09AHLNMID>71+(%%Ũ'),/26:@FLRW[\[WQIA93.,-17?HQY_cddà  )3=ELPRPLF?70*%"!!"$'*.38?FMTZ^_^YSJA92-*+/5=FOX_dfeà ",6@HOTUSOIA81*$!!#'+06>ENU\`a`[TKB91,))-3;DNW^cffà #-8BKSWYWRLC;2+% !$(.55-'" #'-471,)&%&'*.3:AJRZ_bc`ZSJA93/-/28@HOUY[[à !+6ALV]bdd`[TME>83/,*)*+.38?GOV\`a_ZTLC<610149@FMRUWWã (3>IS[aeec_ZSLE?:52/--â/27=DKRX\]\YSME>94336:?EJOQRRà %/:EOX_ceeb^XRLFA<741/./149?FMSWYYWSMF@;7557;?CGKLMLÅ !+5@JS[`dec`\WQLFA<741/./15:@FLQTUSPLGB=9778;>ADFGGFĪ &0:DMU\`bba]YTOID?:51.-,.04:?EJMOOMJFA=:88÷:<>@AA@?Ä !*3=FNUZ]_^\YUPJE?:50-*))+.27=AEHIHFC@=:87789:;;:98Đ $-5>FMRVYYXVRNIC>83.*'%$%(+059=@BBA?=:8755ü421Å &-5=DINPRQPMID?:4/*%" !$(,048:;;:875321100/.,+*Ø %,3:?CFHIHEB>94/*%! $(,/133ō10/.-,+*('%$#Ö $*059<>?><:62.)$  #&)+,,ō+*)('&%#" Č !&+.134431.*&"!#$%%$$#"! É !$')**)'%" ō   õ ö ö Ú   õ ô é   ö  ö  ÷ ø øų "    ūü      ú  ô      ø ø   ë  üø  ÷ ķ ûöø  öî !!û"#$$%%û$#"!  !ū"##ø!ö !!đ"#$%!$&'))*û+,-.//õ.-,*))()*+,,ė*(%!"$&())**ú+,-.÷ #&*-/12334ü57899ú8764211ü23455í31-*&" #'*-01233í4567'%%&(+/369;<==<<ķ=>@ACCDCB@><::ũ;=>>ė=:62.)&$$%'+/37:;<=<<ņ=>@/--.037<@CEFFūEDDûFGIKMMŪKIGECAABCDFGFEC?:51-+*,.27<@CEFFEDDEFH86558;@DILNOOMLKJJLNPSUVVTROMJHGGIJLMNMKGB=841125:?DILNONMKJJKLN@>==?CHLQTVWVTRPOOPRUX[\]\YVSPMLLMOQSTTRNID?:778;@FKPTVVUSQOO€ÅQSHEDDFJNSX[]][YVSRQRUX\_aba_\XTQONOQTVXXWTPJE@=<=@EKQWZ\\ZXUSQQSVOLKJLOTY]`ba_\XUSRSUY^adfec_[VRPOPRUX[\[YUOJEA@ADJPV[_``^ZWTRRTWUSQPQTY]adedb^YURQRUY^bfhgea\WSONOQUY\^^\XSNHECDHMSY_bcb`\WTQQSV[XUU€;X\`dggfc^YTPOPSW]bfhhfb\WRNLMPTX\_`_[VQLHFGJOU\aded`[WRPOQT_\YXY[^bfhhfb]WRNLMPU[`ehhfb\VPLJKNRW\_a`]YSNJHHKPW]befd`[UPMLNRb_\[[]`dgiifb\UPKIJMRY_dggea[TNJHHKPU[_ba_ZUPKIJLQW]beec_YSNJIKOca^\\^adgiheaZTMIGGJPV]befd`YSLHEFINTZ_ab`\VQLJJMRX]beeb^WQKHGHLda_]]^adghhe`YRKGDEHMT[`dec^XQKFCDGLRY^ab`\WQMJJMRW]bdda\VOIFDFJda_]]^adghgd^XPJEBCFLRY_cdb]WPIDBBEKQX^aba]XRNKKMRW]adc`[UNHDBDHc`^\\^`cfgfc^WOICAAEJQX^bca\VOHCAADJPW]aba]XSNKKMRW]acc`ZTMFBABG`^\[[]_cegfc]VNHC@@DJQX^aba\UNHB@@DIPW]aba^YSOLLNRW]acc_ZSLFB@BF][YXY[^befeb\UNGB?@CIPW]ab`\UNGB@@CIPW]aba^YSOLLNRW\`cb_YRKEA@AEZXVVWY]`deea\UNGB?@CIPW]ab`[UNGB@@CIOW]aba^YTOLLNRW\`bb_YRKEA?AEUTRRTW[_bdda[UMGB?@CIPW\`a`[UNGB@@CIOV\`ba^YTOMLNRW\`ba^YRKEA?AEPONNPTX]acb_[TMFB?@CHOV\_`_ZTMGB@@CHOV\`a`]YTPMMNRW\_a`]XQJEA?AEJIIJLPUZ^``^YSLFA??CHNU[^_^YTMGB@@CHNU[_`_\XSOMLNRV[^`_\WQJD@?ADD€2EHMRW[^^\WQKEA>?BGMSY\]\XRLFA??BGMSY]^][WRNLLMQUY]^]ZUOIC@>@D>=>@CHMSWZZXTNHC?==@EKQVYZXUOJD@>>AEKQVY[ZXTPLJIKNRVY[ZWRLFA>=>B778:>CHNRUUTPKE@=;;>BHMRUVTQLGB><<>CHMRUWVTPLIGGHKOSUVVSOID?<;CHLOPNKGB>:88;>CHLOPPNKHECCDFJMOPPMID?;878;))+.27BFHIHEA=96446:>BFHJIGEB?>>?ADGIIÂGC?:64347"#$'+059=?@?<952/..037;>@A@>:731//147;>@AA@=;9878:=?AAí?<841/./1!$(-1466×41.+)((*,/2578752/,*))*-035788753100134688Č630-*)()+!%(+-.-+)'$#""#%(*-./.,*(%$##$&(+-.//.-+*))ü+,.//ú-+)&$""î$!#$%$#! ë #$%&%$" !#$&&õ%$#"!!"#$%&&ú%#!î ķû÷úõ õûûî ü  û õ û  ķ                õ ü 9 ū,  ú   ô û üūū     ų ÷  ū  ų ÷ üūö õ ú  é ö  õ ųõ%%û$#"!  ü!""##ö"   ķë !"#//õ.,+*)(()*+,,į+)&# !"#$%%ų$#!ô"$')+,,899õ875321122455Į42/+'" "$%&'()*+,--,+*(&#"!!"$'*.13566BCDCCA?=;::ü;<=>>å<84/*&" "%')*+,-./012344Ę20.,*))*-037;=?@@JLMMLKIFDBAABCEFGFDA=83.)&%%&(*,.01122Ã34689;<<;975321358=AEGIJJQSUVUTQNLIHGHIKMNNLJE@;61.,,-/2456766č5679<>ABCCB@><::;>AFJNQSSÚVY[\\[XUROMLLMORSTSQMHC>964468:;==<;988‰9;>BEHJKJIGECBCFINRVY[[ZZ]`bba^ZVRPNNPRUWYYWTOJEA><=>@ACCB@>;9889;?CHLOQQPOMKJKMQUY]`aa_[_cefeb^YUQOOQSWZ\]\ZVQLHFDEFGII€ųGD@=9778;?DIOSVWWVTRQRTW[_cefebZ_dghgd`ZUQONPSV[^``^[WSOMLLMOPONKGB=86458=CIPUZ\]\ZYWWY\_cghigdY^cghhe`ZUPMLNQUZ^acb_\XUSRSTUVURNIC=74236;AIPW\`aa`^\\]`cfikjhdW]bfhhe`ZTOKJLOTY_bdec`][YXYZ[[ZVQJC<61/028?GOW^bdedb``acehklkhcT[`eggd_XRMIHIMRX^cfgfda_^^€=`a`^ZTLD<50--055.*(*.5>HQZaeggfeddegijjhc]LSZ_bb_ZSLFA@AFLS[bgijjhggÂijkkid]TJ@70+)+/5>GPX_ceedcbbdfhiigb\LSY_bb_YSLEA@AELS[afijihffåhijjid^ULB92-+,/5=FNV\`bba``Ãbdghhfb\KRY^aa^YRKEA?AEKSZafhihfeddeghigd^VMD<50-.16=EMTY]^^]]…^`ceggea[KRY^aa^YRKEA@AEKSZ`eghfdbaabdefeb^WOF>830037=DKQVXZYYXYZ]`cefd`ZKQX]``]XRKEA@AEKRY_dffdb_^]^_abb`\WPHA:63358>CINRTTÂUWZ]addc_ZJQW\__\WQKEA@AEJQX^bcca^[YXYZ\]^]ZUOIC=86569=BGJMNONNÃPRVZ^aba^XIOUZ]]ZVPJDA?@DIPV[_``]ZWTSRSUWXXVSNIC>:878:=@DFHIHHÛJMRV[^_^[WGMRWYYWSMHB?>?BGMSX[\[XUQNLLėNPQRQOLGC?;9889;>@ABBAÂBDHLQVY[ZXSDJOSUUSOJE@=<=@DJOSVWVSOKHEDEFHIKKJGDA>;97789:;<<;::Ę<>BGLPTVVSO@EIMOOMJE@<989<@EIMPPOLHD@><<=?ABCCB@>;976556ũ5433’57;@EJMOOMJ;?CGHIGD@;85457;?CFHIGDA=9654568:;<;:9754221100/.-,+,.049>BFHHFC48?@><-14677641.+*))+.13677530,)&%$$%'(*+,,Ú+*)('&%$"!  "&*.256764&)+-./.,)'%##é$&)+-..,*(%" "#$%%â$#"! #&),-.-+!#$%%ĸ#" !#$%%$" !#$%$#ä ûũú  û î ú û   ūų û   đ  ü      ū  ú ô üū   ! ˜ ˜ ˜×*   ūū    ų÷÷ ú     öö ų ô ė ņ ū#$$%ė$" ņ -.Ų-,)&"  678ö753/+'"ø!#$%&&ī%$#! @?ę@AA@?<84/*%" !#%(*,--í,+*(&# ũIHGGūHIIŲGEA<71,)&%&'*-/1344321/-*'# ũQPNNÖOPPOMJE?94/-,,.1479:;::8641.*&! æWUSRRSTUVVTQLF@;632247;>@AAė?=;851-(# ü\YVUUÖWYZ[ZWRMGA<978:=ADFHHGEB?<840*% Đ_[XVUVX[]^^\XRLFA><=?BFJLNNMKHD@<72,'! Đ_[WUTUX[^`a_\VPJEB@ACGKNQSSRPMID@:5/(" Đ_ZVSRSVZ^aba^YTMHDCCFINRUWXWURNID>81*$ Ī^XSPOQTX]acc`\VPJFDEGKPTXZ\[YWSNHB<4-& Ī\VQNMNRV\`cca]WQKGEEGKPUY\^^][WSMG@91)" ĪZTNKJKOTZ_bcb^XRLGEDFJOTY]`aa_\XSLE=5-% ĪYRLIGIMSY^bcb^XRLGDCDHMRW\_bcb`\XRKC:1)  ÎWPJGFGLQX^bcb^XRKFBABEJOUZ^acdc`\WPH?6-$ ÎVOIEDFJPW]acb^XQKEA?@BFKQV[_bddc`[UMD;1( ÎUNHDCEJPV]acb^XQJD@==?CGMRW\`bdcb^XQH?5+" ÎUNHDCEIPV\acb^XQJD?<;;:;=@EINSX\_aa_[UMD:0& ÎTMGDCEIOV\`bb^XQJD>;99;>AEJNSW[]^]ZUNE;1( ÎSMGDCEIOU[`ba^XQJD>;98:<>BFJNRVYZZXSMD;1( ÎRLGCCDINUZ_a`]WQJD>;989::8789:@CFIJJIE@:2*" ÎJEA?>?CHMRUWVSOJD?;75445678:<>@BCCB?:4-& ęEA=;:BFHJIGC?;630/..č/0123455430,'" ę95311247;>@AA?<840.+*))*+ë,--..-+)%! ë1.,**+-025787630-*'%$$%&î'&%$! ü)'%$$đ&(*-./.-+(&#! đ é! !"$%&%$#!ņ üņō õøķ ū  ų ų    ô ū       û  ū  øz=,d Background˙     ˙˙˙˙],d]Ŋ^ĩ^Á^Í,d]ņ^^^/^?^O^u^…^•^Ĩ˙˙˙ų˙ûúô˙ū˙:˙ũ Å˙˙˙˙˙˙˙˙˙˙˙˙˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙&˙üūũü˙>˙ũūũ˙>˙üū˙ü˙Q˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙0˙0˙0˙0˙–2K% commons-dbcp-rel-commons-dbcp-2.10.0/src/site/000077500000000000000000000000001447311732500210545ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/000077500000000000000000000000001447311732500230665ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/download_dbcp.cgi000077500000000000000000000002351447311732500263540ustar00rootroot00000000000000#!/bin/sh # Just call the standard mirrors.cgi script. It will use download.html # as the input template. exec /www/www.apache.org/dyn/mirrors/mirrors.cgi $*commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/000077500000000000000000000000001447311732500243335ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/dbcp-logo-blue.jpg000066400000000000000000000125671447311732500276430ustar00rootroot00000000000000˙Ø˙āJFIF``˙ÛC  !"$"$˙ÛC˙ĀFŲ"˙Ä ˙Äĩ}!1AQa"q2‘Ą#BąÁRŅđ$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™šĸŖ¤Ĩϧ¨ŠĒ˛ŗ´ĩšēÂÃÄÅÆĮČÉĘŌĶÔÕÖרŲÚáâãäåæįčéęņōķôõö÷øųú˙Ä ˙Äĩw!1AQaq"2B‘ĄąÁ #3RđbrŅ $4á%ņ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™šĸŖ¤Ĩϧ¨ŠĒ˛ŗ´ĩšēÂÃÄÅÆĮČÉĘŌĶÔÕÖרŲÚâãäåæįčéęōķôõö÷øųú˙Ú ?÷-Cö‡øUa{5ÆģpŗC#Fále8eb¤pž ÔđŌ_ č=w˙‚ųŋøšøƒÆ_ō7ë?õ˙?ūŒjɯĸYMˇ×Čđ^gZû#ī_øi?„ŋôē˙Á|ßüMđŌ_ č=w˙‚ųŋøšø*ŠŲ4;ŋëä/í:Ũ‘÷¯ü4—Â_ú]˙āžoū&øi?„ŋôē˙Á|ßüM|EŲ4;ŋëäÚuģ#ī_øi/„ŋôģ˙Á|ßüMđŌ_ č=w˙‚ųŋøšø*Š?˛hw×Č?´ëvGŪŋđŌ č=u˙‚ųŋøš?ᤞ˙Đzī˙ķņ5đUdĐî˙¯iÖėŊᤞ˙Đzī˙ķņ4ÃIü%˙ õ×ū æ˙âkāĒ(ūÉĄŨ˙_ ūĶ­Ųz˙ÃI|%˙ õßū æ˙âh˙†“øK˙Aë¯üÍ˙Ä×ÁTQũ“CģūžAũ§[˛>õ˙†’øK˙AëŋüÍ˙ÄŅ˙ %đ—ūƒ×ø/›˙‰¯‚¨Ŗû&‡wũ|ƒûNˇd}ë˙ 'đ—ūƒ×_ø/›˙‰ŖūKá/ũŽ˙đ_7˙_QGöMīúųönČû×ūKá/ũŽ˙đ_7˙Gü4ŸÂ_ú]āžoū&ž ĸėšßõōí:Ũ‘÷¯ü4—Â_ú]˙āžoū&øi/„ŋôģ˙Á|ßüM|EŲ4;ŋëäÚuģ#ī_øi?„ŋôē˙Á|ßüMđŌ_ č=w˙‚ųŋøšø*Š?˛hw×Č?´ëvGŪŋđŌ_ č=w˙‚ųŋøš?á¤ū˙Đzë˙ķņ5đUdĐî˙¯iÖėŊí%đ—ūƒ×Gë§Í˙Ä×i˙ Â?ôü“˙‰¯Ízúļ°­–Ō…ŦŲŊ}YŪö>hņ—üÚĪũ„'˙ŅY5­ã/ųõŸûO˙Ŗ˛kŲŽČō%ģ (ĸ˜‚ž…ũ>é|qâoę:œ2Ü46Ų´kšS†‘‹+dnĘã ~CÉČĮƒhšmÖŗ­Xé*­u}q´ Įģ°UũH¯ĐGû;áĀšÖŲŖhzYX‹|‚k‚03Ž…ånž­^~a^TãS~ķgvŒfÜæ´Gj_˛ „—%´ßÜÛÁŲ.4ՙúŸâYtĮođŽGÅ߲ŒôÛ_´xYĶĩ¨KBĘmĨ'°]ÄŠüYkĖt‹ßôšŒļŪ:×dcÚęíŽWĄv]Ãŋ§§ ¯ ˙fŸē˙‹<]oāī-¤ķ\Âßcž†/.G•ąYųNT ‚¸ÁŨÆU6Œyų”’5ƒÂU—/+MŸ(kZ^ŖĸęˇV¯e=õŗlš ĐĢĄÆyÔAî5Ø|øcŦüOņ Ún›™í[,cІucŖFO ĄˆTåĒgĒčŋŗOà éM¨xËV¸ÔR$yŽŽ…˛ã9#iGÕĪJ–O‰?ŗ—€îeūÃ°Ō§ŊˇMĄôŊ,K#‚3ĩg +gãĮ¯C…ũ˛ôßxŸFđĪ„|7ĸŪę—WWŌ]ŋ‘V!eFö<&|ÖÁ$”×9đŸöZ†ĘXuoˆ‰y$:éVmû˛Gi$8ŨÛå\r+ΌŖ:~ĶQëŅԌĄSŲĐ‚ĶŠīßĖm Į, 2 =0WüÅã?ŲģâW†´™u1›ŦC —•tŲŲäE’Û]TˇN‹“íOPŠÎånĘ˙˜ą˛Ģ*|Š7îíų7EõĮėĪđ& ÚüAļHī#_>ÆÂįå[5‰ĻūZw ~įSķpžž# æ‘åPĄ*Ōå‰įŸŋg/øĘ(uŸ<Úˆā”VL]Î8ÁTa„SĪĖŨp0¤×З>øđĮÃÍuŽhÚ 6ã$ÍĢ ē–f Ņ›‹ íAë^[ņ§öŸ¸[Éô_‡ …2ĢĖ›‹žAōPđãælįž1‚~g×uW^ÔåÔĩ­FëPŧ”å渐ģsŒžƒžƒ\*†'ųĒK•vGk­‡ÃŽZk™÷gEãétīüSŋ>ĐMĩ•ũĘŧX[@œ*ŽBqąÛ5ė˙e-kP†ßë ¤FÜĩ• Όt/÷įĐ=x§ÂŋÜøƖž'ŗĶ­/įļI"¸z•Č#pzú;×Ų?˛ˇŧMņÃ:įˆ|Iv’ŋöŸŲā†(DqBĢ1 Üōüä“Ō¯Rĩ ģŅ.ŊHÁĶĨZ~ū­ôčfŨü3ũŸūÚ[Ũøž#1‚IĢN×N7ųXŒēœdzÖŋÛözņŦcá­Á—ˇä6‘3°BÉģžŖ?^+Án-xj?ėôXĨWIĶÕ]Cgl˛표—Ë÷ũ)ßą§ÃícVņõˇäVļŅôƒ&ŲúL­&Äö]Ų'ØųރxmRŖŊģũĮJŦ•e+z}į­|sũŸü¨øKSÖŧ5Ļω̨ÚÉqZaaŸ`-ąŖ# 0Æ31_Wܟĩ×ċ øëÂļ—žˇ­ĀĐų#“ ŗ|˛;ۆ够C_ ×^XęēW›ô9sMT´¨QEčœ_V×ĘUõmrâzXn§Í2˙‘ģY˙°„˙ú1Ģ&ĩŧe˙#~ŗ˙a ˙ôcVMtĮdsKvQE1ûûxV=gâ]߈nbI ĐíwG’r'—*‡Ę%ëßwīíÛâÖĩŅ4oÛJ›ī\ŪŪ(a¸F‡l`Œg Ŏx˙Wߜu?ą>„ēgÁąĒ’­&ą}4ų ‚¨‡É O~cs˙üūtũĒu§ņĮmb+f[”˛hôč X’Š/ģyŒãé^ ūÍ:æŋ5žąã¤›FŌC'‹Ģ•Æpį’ķƒŸ›‚08jôߏôO‡ø/Ā fÚÄpˆČP`Ķ Ž&:/AÕģ+kŠÄ{_ÜQÕŊßDg†Ąėŋ}[Dļķ9/ۋâŧígđķN•™ā‘o5'I>PpDp'y§Č~wėKá į^Ķõ8īuAÂjĢĮ Fo.=¤ 1=ķÆ@ž0ģš¸ŧģšîîyn.'‘¤–Y\ŗČėrY‰ä’I$šûsö#ŌZÃāĶß;†ūĶÔĻ@ūPącķãYã(Ŧ>‘>ŋyĻ̝ŠįkūˇņÃ㎋đÃSƒGŸHŊÔõ;‹OĩGnąÄŗ*îs’2QēŌŧÄĩŽŽæaŖčú.—\čķČŽâB˙ãĩûb_gãÅΟg’MekmdĒ‹šĨv` $ūô.=EGđ¯övņĮ‹ŽaēÖm%đæģ2MyYŨyá"?6xļ҃‘ģĨ0ØjTcRĒÕŽŋä*،EJŽŪĪĄÕü øÉņ‹Æ_tŊĩ85æķ/a}>%Ž `A‘ˇĸRåRĂˠį5ô¯ÆižđŖŽj/qEin_k\LĀ…Aßܐ'ĩyļŖâ…ŗĮ†åŅ4TŠ˙^(ÖđēŊÕĊ2Ļâ@?vŋ>@#€ĮjžkæŊk_ņwĮ_ŠzeõÂŦˇ“‹{;x˙ÔŲDN\Ē’3…˜“–ÛŽĀ ž¯MOhŖËō𝎕r9sMū§~Æŋ bÕŽ˙á`ø‚Í&˛ĩ“n•œ‰&RCJWŅÂ˙ĩ“ü Ō~ØĻÔĩ9ūxvč.ŸjÛuIâs™å˜ŨS׎[Ž6ķīõ‹/„˙nåŅĐBēm’Yi¨NãæG9#v3¸÷ Í~xË$“JōĘí$ŽÅØäą=I=Ím„_ZĒëĪeĸ2ÄŋĢRTcģÜeÕx3áĪŽČ˜â#žį/Áū#a^q[SĀĘm:îöŲt1ž20ēĸ­~ŊKÚū¯ŠëúÍÖŗŦŪË{w!’yå9goä ThĸŊ$­ĸ<öîQEõm|Ĩ_V×.'ĄÕ†ę|Ņã/ųõŸûO˙Ŗ˛k[Æ_ō7k?öŸ˙F5d×LvG4ˇaESú/đ'N×tĪ„^Ķu{kK ˆlĐ*ÄæBŒ‚Ü$ Ã'ŊrZÆģđ;á&ĄĒÉ%…׉'šIîZ]ßÉ3í“Ō-Įœ|‹ĪA_ŨxĶÆ7zwöm׋5éėŧŋ+ėŌj2´[1ģKcn8ĮJÁ¯*9krnrŅôGĨ,Á(ĨęēŗÜ>/~ŅŪ,ņ„ré~WđæĮȔũĒ`¤ÚÆU}Á, x}WŖJŒ)G– Į JŗĒī7p¯ŅŋšD^ø1áĢ Ę[ųv <åÜa^\Ęųlãī9īŠüä­kŸx’įDMįÄ´ÚTaBYIy#@Ąz;F01Åsã0¯íŠļ°ōrĩĪĩ|[ņĮáƒo¯n´Ųmĩ^ä‰'m*Ėp柅8 8ÜpqŌž~øûIxûÅ1MeĨŧ>Ķä8ÛdÄÜÆi>ŧ¨ZņZ)QĀQ§ĢW~eUÆÕŠĸŅy–I&•å•ÚI‹;ąÉbz’{šõĪŲ'Ä^đĮő¨xšū+ w°– {‰¸D™™1¸ôPT8Éãšō +Ē­5RŠÍNnœÔ—Cô?Æ^$ø/ã é~%ņO„5+ÂQš´A•°@e*ᕰÄd`ōk†ĩ×fË °˙„~K…%Ŗ–$Ô$__ŪaĘõîÃô¯ŠhŽeŠ+—Øî–`äīČŽ}—âÚĮÁö+$^đūŠĢH„i™mĄa܃ķ7…F}ē׌|Mũĸŧwã+ôģco i“š;Ūs§÷ZRrGŽĐšŒ×Ņ[ŌĀPĻîŖ¯™…LmjŠÍč{wėU¤ÁŠ|kKŠ—sišl÷qķ҉HŗųJkÜ˙m}nÎĮá hīy ^jw‘­ÉËȈÛŲ€ô.ON@î+âÍXÕ´KߡhēĨö™u´§ŸipĐÉ´õ”ƒŽ7WÕ5=bôŪęúæĄtĀ)šęv•Čæ$ÔTÁē˜…UŊTņJ$ĩe:(ĸģŽ0ĸŠ(ĸŠ(¯Ģkå*úļšq=Ŧ7SÉŧWđ§ÄSxŖU™o4 ¯{3 Ë&p\ŸîVgü*_˙Īî“˙d˙â(ĸĒ3•‘œĸŽÃū/ˆ˙į÷I˙ŋ˛ņÂĨņüūé?÷öOū"Š)ķČ\¨?áRøūtŸûû'˙Gü*_˙Īî“˙d˙â(ĸŽy*øTž#˙ŸŨ'ūūÉ˙ÄQ˙ —Äķû¤˙ßŲ?øŠ(ŖžAʃū/ˆ˙į÷I˙ŋ˛ņÂĨņüūé?÷öOū"Š(įr ˙…Kâ?ųũŌīėŸüEđŠ|G˙?ēOũũ“˙ˆĸŠ9ä¨?áRøūtŸûû'˙Gü*_˙Īî“˙d˙â(ĸŽy*øTž#˙ŸŨ'ūūÉ˙ÄQ˙ —Äķû¤˙ßŲ?øŠ(ŖžAʃū/ˆ˙į÷I˙ŋ˛ņÂĨņüūé?÷öOū"Š(įr ˙…Kâ?ųũŌīėŸüEđŠ|G˙?ēOũũ“˙ˆĸŠ9ä¨?áRøūtŸûû'˙Gü*_˙Īî“˙d˙â(ĸŽy*đ—Äķû¤˙ßŲ?øŠ?áRøūtŸûû'˙EsČ9PÂĨņüūé?÷öOū"øTž#˙ŸŨ'ūūÉ˙ÄQEōTđŠ|G˙?ēOũũ“˙ˆ¯Ĩ?áÕŋįâËūûoū&Š+—7ĄÕ†ŠÔ˙Ųcommons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/dbcp-logo-white.png000066400000000000000000000300421447311732500300240ustar00rootroot00000000000000‰PNG  IHDRæP ų ĶsRGBŽÎébKGD˙˙˙ Ŋ§“ pHYs  šœtIMEÛ c4H!iTXtCommentCreated with The GIMPm°— IDATxÚí}ypUåų˙įŪ\¤3ũC!dũ§Ę ¨ÆHÚ2:ļ*–Å@ë"P%" %Č" Rd ⁰"°C՞Р’Ü{“ķûCß3ĪyÎķžsŖũ͡bÎĖBrŪũŲßgņ†a ũŧ‘M-Įãiôx˙Kc¨6ĄŽÁÛ:ĩsú[cį*}˙cæĘ\Ĩ~ųø?ö8pž×Ēm|||Hķ՝¯ę_íŖšÄĮĮ›ã¸žŌĢŊÉÉÉ1ĪRõŠāH#dgg#''Įu<'âû 999čŅŖ‡šį?ū8f͚Ĩ%ŪN˙76\žŲŗgņņņĮ7;;Û8ūŧQWW§}ũ~ŋá÷û@ `ƒAŖžžŪ¨¯¯7f͚ŌņņņFnnnŖĮ ƒÆš5kŒœœŗ¯5kÖÁ`Іßī7vīŪmtīŪ];v÷îŨsįÎ7nܰŊ3fĖpœŋj[[[kiW[[kÔÖÖZæŒĪ>û˘5k–‘’’böĄæĒæ;sæLĮ1{ė1Ûx7nÜ0Ξ=k<öØcŽûŦÚĒWš+/=Ë={öXæí3ģví2ęęę,ãIįŠÖ^TTdŒ?Ū˛öˇß~Ûܗ˙ûßFnnŽ# ­^ŊÚļ/ēŗPë›0a‚Ĩœœ#''Į˛Öėėl†B…KĩoõõõFCCƒŅĐĐ`†ahsßž}–ÅO˜0Á(**27āüųķFvvļmáĢV­2žũö[ÛûŨwߙ &úÖ[oYÆ?~ŧą{÷nÃī÷uuuÆųķį—_~Y@ˇqΝ;gŧüōËâoŊõ–97@UoˇnŨŒožųƸ~ũēqũúucĮŽF\\\HmãââŒožųÆöĒy=ö˜–8¨šž?Ū‘€Đ7//Ī2ßŧŧŧÚ0ƍ§+?Kŋßo|öŲg MII1ÖŦYc‹:oiîC† q<Ë7ß|ĶČÎÎÖ"u–;wî ‰Ā0VŽ\iîËõë××§æoėŪŊÛB ëęęŒ]ģvŲÖuãÆ ãģīž3ûŌ!ŋ9EÄü×ŋūeŲā/žøÂ2‘ēē:sānŨēŲŊbÅ ãë¯ŋ6ßk׎Y˙Ũwß3fĖĐ" í_m֐!ClãdeeiĮ7nœ1dČcčĐĄâÁŦ^ŊÚ8sæŒ9˙¸¸8cėØąÆoŧaŦXąÂ3fŒØîÅ_4jjjŒe˖™ŋËĖĖ4–/_nŦXąÂl+!ė‹/žh|ų嗖÷̝ž2žūúkŖ[ˇnƐ!CÄũTŊzõjŗßnŨēͧO7ĮėÚĩĢØŽŦŦĖ¨ŠŠ1233ÍuŽ=Ú2ßŦŦ,m[iŽjŸÕYr„ČÎÎļŠâēęĢtLÅŨuëĸãP‚(6JÔ¸Ô!"&EĘøøxS„ĸųöÛoožųƸvíš1}útÛĸcccęęjŖĒĒĘ¨ŽŽ6ĒĢĢššsáoŧņ†mc)…Qũ_ŋ~Ũ<¤¯žúĘ.úfffšc¨qžüōKŗŽS(DīÚĩĢąmÛ6ãË/ŋ4û¨ĒĒ2ĒĒnjcĮމk[˛d‰ĀČČČ0JJJŒĢW¯šoEE…QYYi=zԈĩĩĨß^ŊzÕ¨ŦŦ4÷‰"Šnžcƌ1Ž?nÔÔÔØæ;mÚ4[ģG}ÔČČČ0S§NįZYYi,]ēTl+}_]]mîņŠS§,9tčP‹LĪķÚĩkæY._ž\ÜÛcĮŽŲΓ"ŒD ÕøYYYFiiŠš'•••FEE…QQQa$''ÛÚ-Y˛Äq}ÛˇoˇHKŠûIpzíÚ5Ë÷AãHO”#§Åøŗoß>ôėŲĶTD?˙üsÄÆÆÂ0 444 ĄĄÁüYũ{áÂtęÔÉĻ$įįį###Ãb(đx<())AZZšų]ˇnŨ°cĮ‹aƒžj,õvîÜåååâXÔ áõzáõzÕī-Z´hÆį˜™™‰e˖‰kSĪÔŠS‘ŸŸo[_zz:,X`QÚéĢæ5uęTKģ͛7#))ÉüŋšŖšoXX6oی‡~Ø6æ˛eË0xđ`Û\é|ģvíjÛX°`ŌĶĶį;xđ`>|Øü&&&´ĩĄsMLLÄĨK—ĖoΜ9cAøųĪ“'OÆĸE‹,ķĖČČ@~~že^jLĮŖŨ›ĨK—"##ÃĢžJJJ™™Š=C:†Zߔ)S°páB@VVV­ZĮcƒQ5&<ôĐC(((@eeĨÍĀCûĻ?ķ˙€—"Ä˙øGŗŖņãĮ›HY__††Ô××# " "  ** ]ētąmT§Nā÷û-o Āĉ-ß=účŖfŸô đûũ–ą€šQôyūųįá÷ûQWW‡ēē:ŗ­Ķī÷‡ņ6ÉÉÉČĪĪ7ŋSméĪuuučßŋŋmŧΝ;cΜ9¨­­Õžuuu"Áúâ‹/,ũĢoéŧëëëmíĻM›†ôôtË|ų\kkk-DO=Ī<ķ îšįqŽt;wļ´ģ|ų˛ĨēG~ŋķįΎ eVVĸĸĸ´įŠ^u.Ī=÷bbb,cnŲ˛û÷EÛH{3uęT 8PÜĩļöíÛ#::ÚŌîđáÃâY¨ą¨åĩ¸¸Ø\ Åĩļ`0ŋßo? Ō~Ô×כxʼnˆ1įĖ™ƒ‹/ZLË ĉ¨^°`eƒį͛‡ˆˆÛa8pĀB‘ÕâũŠW-–ūŽS§NļÃŧ|ų2/^lŽCįäöō̎Ž6˙Ž„¤úš}ûö6@ˆŒŒtDJÕGBB‚­íÖ­[ĩĀ^[[ĢEĖČČH‘ĢC‡ļļááá–5Š÷ƍ–>:vėhk[PP`CÍsņâÅ6n§CDŽ`ę›Aƒ‰ˆFĪÎ1 Úžˆˆ0÷Ĩ1„ōʕ+ļočĪ aāŌĨK˜7ož6é:Õēa”ö#ĻÂ/Iúņ)L}įw,“îÚĩĢŖ9–Ķ[ĩj…ĸĸ"\ēt ŅŅŅ0 @Āv×ČE¤¤$ÛFKâ2§&iiiXž|š āīŋ˙~‹XB_ū444˜™¯‰Ž%Ũe544ØN'ņ§žžĩĩĩ–6aaaæĢ¨ąÔŽÎW͙Î×ãņˆmƒÁ jkkm÷†\Œ ļļ@Ā2_%ÂnŨē—/_ļ|›˜˜ŋßoŠ{j~øčy0K—.ĩôsäČüį?˙19§4Į`0ˆēē:s_øŪĐsãO]]MÔ C0D§NđŪ{ī™ßNž< 9r¤EdĻǐaXģv­š\ĩRũĶ1Õŧ¨˜ė3 /^´\ÄvīŪŨL-Ta:åĸy"## mōˇšĀ| r-5yސtcé÷īß߆˜GĩGNrŠĩŠuōÃÔ!Ļß! ëŸųęK!Ļnž:ÄT"×ytˆŠÆUķUßR€åœ‹î“ÛyvėØŅŅҏråŠMĖėׯŸmŽēŊQÜT‡˜G”Dč|)bú|>ÜsĪ=xéĨ—,ßO™2˜4iÅ5&$$ XΗ#%wdđzŊœņĀŪŊ{-ƒĮÅʼnHI‘“Skn¸áœŽĸĸBp :ŝ/B𠤤:t°Ũ ĮT˙ō1CALS/øÃÂÂĖukĻČīõz-ÔŪcRä¤ÄOŠŽ-Î!t€ĢÚrā判¸"‚œŖĐķäž.:u˛õwäČôéĶĮr^¯×2Š\1ÕŪĐq$ŽIĪB퉒\Zļl‰xĢV­˛ÁŲĐĄCŅšsgĖž=‘‘‘–5JF̰°0ÛZ$ŧQ8`ŖęH¨|,)Ŧŧ­úEŪO?ũTä1u¯B7/** W¯^ĩôW^^Ž6mÚØÚ9qLŠ˜t|7ŽGĨēęPÃÂÂD@Pmųú|>Ÿų;WāēŠ: ēVŠ­RE8!Ą@¨ˆƒŽ-:Įƒ˛˛2A$é‡jÉeëëʕ+&ŌĐqC•&(ŒrDām-F—öAÍ=77WŽ\ÁļmÛlm9‚{îš÷ß?îģī>DFFj­íœ@ĐWš›Ī0 ‹õ‰"ĻdđáĀČÍÚ\įrō‡¤‡.Éę|SéņŅG9=å :ÎE×É×ĨCjhØiŋjžĮäWOü÷jīu{E”Ž­æ*Ē~pBŌĐĐ`ęˇēļBKâ˜ēĢÎAÔīm\‰ŪĐöNĸ,å–tjo$XävIŦœ>}:ĸĸĸ°zõjqŨožų&ļmۆ?ũéO6l˜MZ“87g@\ōôJÛ8&ˇ.q9^ŌYøŊ ļmÛ&öĪš‚$–č<üéĩĩę]˛˜éƕ$'ã˜č´-ĄųØNˆÉÅoŽWšÍU×V7_ÉŪ =īŋ˙žíŠL'~Sds"ÜU_r9ÁDuÄGRŨ‚Á rssą|ųr‘ģ@EEæÍ›‡ŦŦ,\ētɆ+|’øJ%P¯$Ž^ētIË1%[˛j):,,LËy¤Í—5tˆiãöĒH)šÄš.˛…Ō–s7„æs“ p:ÄĸRÄ͜€–[ Õ<¤Gq.éūšī/‡ūDEEŲ­zĨŊŅJÜÂļøõ įĀ Øēu+&L˜ í§˛˛ŖGÆöíÛĩw–Ļ%Xņ樴i“MĮÔqKÉėO­Œ>ŸĮŲļm›HĨ¤ v2Č@BB‚ Øu‡IL:H7@•æ*"sDáI§›rāáÆ§˜BiÎ?ežŊzõ˛}WXX(J?T ’ŒkŌŧÕ0įdNĸētį&iņĩņ+;.×××cذaØŧy3† ĻEÎ āōåË"ņ… z Ã@vvļčR'‰XĮ¤Ŧ˛´´>Ÿ͚5CŗfÍāķųlžPZZ*ŠX:cĩzŌ§cĮŽ6Ž@ÅLbJîbn@C•{§oÜAĮ=Ũ¨ēb9é4W][ēNJá[ļliûöøņãÚKuŽ8ĨÛyēéÁÜ0évŽTĶ@ŪoDDƌƒĩk×"55UDÎĩk×ŠĖ†âŽNŧõĒāUéęáđáÃ6Hũ,YN•ØúÁ`ėØą!qM…˜üē@Į=twĸũúõE6ŨaJE AĖâēŗø:M§wKNĄpcéŽL>…ēW§đ1Ôü¨OĩzĒĒĒL.á¤cņ~?üđC›;gtt´vœÔ‰P9%ņŌ0 äååaũúõŽũGDDāšįžÃŗĪ>kë{׎]ĸ$čĻwšŗ{÷îbÄ{nn.ĘËËmH#éBjQGŽÁčŅŖąxņbbR'jõ”••ĄŦŦĖŅ“‚‹#ŌZŋ~ũDęį$.8$åNČÅĮ Đ)B;qÄPÅäP87÷JrLÎQøßīŧķN„‡‡Ûžß¸qŖ¨Ÿétoé<û÷īo›“äh↘tž:ĩH{xâÄ ą_ūĻĻĻ"++ËF¨œüdŠaģWŒ7NŧKš={6._žŦÕmø]åčŅŖŅĨK$''[LÆaaaHNNÆ]wŨeį“O>Sw§Éšå_ūōÄÄĈĸ;L7Q.QVĮ1u‡Ŧ;T ĐB¯Dt„„ĪMšcôé{īŊ×ö}QQ‘+œpŖwÜŅŅŅøķŸ˙l#znšwœ¤‰ÆœvīŪ-ˆ´wC† ŅĻ$_gQˇ\—Œ7NäšÛˇoĮ¨QŖPZZĒ5°|ųräääāōåËX´h‘x}âõzņÚk¯ŲÆXģv­éäf54 Ã⎃gžyF‹Ąj¨ÜE'>:‰ŗ55ö e’˜Ëį­ã(NkJOOGëÖ­-ßWWWŖ  @DLéN”ģVžúęĢ"Rū˜bĄî[˙ëÖ­Μ;Ŋ^¯ÅÁÚ´iãx#á‘ét@âÅ_ÔŪҌ7÷ß?-Z„;wĸ°°ü1æĖ™ƒ`ƌ€×^{ 111Z ‹šsįÚūö /ˆú7)¯XąÂtžŽ‰‰1īÃÍāᔄ)Tã'TôS2օ2žä“)­÷Įī„ l"íoŧĒĒ*1ž–žWŽ\ą æŧyķp×]wi×ęĨ6ēļŌ~HˆYQQ!2Šœ555–v={ö´YwÄZJ´,d2++ K–,ŅBUU6mڄéͧã…^Ā”)S°fÍĶ5nΜ9HKKsŊ 4h^yåËīNž<‰ŧŧ<­ĨŌ0 |øá‡&ˆ‰‰Áēuë#Ũ<žaĄčWęo<āUéÅ?QŽ^ŊꚞR3õx<¨ĒĒįĢp7 $Ũwááá˜>}ē 9'Mš„ęęjQ RHyß}÷™ßΟ?ƒ u9z–ĒO'äŌ!čņãĮŊ>ea?žk*NŠsãÆf›^ŊzYtN'I’đōIeffZ"ķCy"##ņŌK/á÷ŋ˙ŊH ¤ƒIKKÃĒUĢ,ėŋ¨¨ÇGAAåP 1bÄ<õÔSžT^ģv-ĸŖŖEãEΰ°0›“žĢēēڑĶy<|ōÉ'âaērØĩk׊H"9ô;é5lay:._XXhkûņĮ; ú4ߏ?ūؕ(„‡‡#//=zô°ˆ´ŖGÆĒUĢpæĖķ,?Žšsį"==W¯^Ett4æÎ‹j‘’"įģīžk›ÃæÍ›]Eߝ;wŠOÚ/é),,ÄđáÃQZZj™rĸY¸pĄ™ ôîģĪ>kSxŌ'#'ÔŨK¤~öŲg;v,Ž;æ8áėėl 6 ņņņ¸å–[pË-ˇ˜÷–<˛CrŽ÷ûũXšr%ÖŦYãĘ):vėˆ'Ÿ|]ēt1Š•Z ’Øž};***°k×.œ:uJė¯UĢVhÛļ-zöėią2ž;wgΜÁž={pōäIí|z÷îßũîwhŲ˛%î¸ãĀéͧqöėYiÛFFFĸwīŪhŨē5Zļl‰Ûnģ §OŸÆéͧągĪ‘ë@ûöíŅļm[´nŨÚ“€īŖƒÎž=‹Ũģwk÷022ŠŠŠhŨē5Zˇn-Zø>Ė™3gÛ&$$ 55-Z´Āoû[ÜvÛm6WLõž>}˖-3‘҉˜?đĀxøá‡MXĄ>Č4(üčŅŖ(++Æ ´{ĶĒU+ôėŲ­[ˇ6 Duu5Ν;‡Ŋ{÷ĸ¨¨H;—öíÛãîģīFĪž=Íĩy<˜9ÕÕՈŒŒ„×ë5‘8**Ę ē6 Ûˇo7×ô‡?üC‡ĩEbŅkĢf͚á–[nÁ¯~õ+ËKņĮķC ‹åHEr߸qŸū9>Œ;v˜Ü)<<­[ˇFjj*|>ŸŲYķæÍ-ŠÅķ ji<ŋߏŖGĸ´´ÔĐ^¯}úôAbb"nŋũv âĢ>šKŸßīĮäɓĩac’x•™™‰;īŧĀ÷é-Μ9Ŗĩ r r›6m0xđ`†‚‚œ>}Úĩ­úW!ĘæÍ›EÒtbž|ōIsm3gÎÔŪ­J†4ēÖÆļÍČČĀwÜasúæs­¨¨0 í3!!:uBRR’å,W„›žå[oŊ…ãĮ‡ėâøøãÃ0 œ={[ļlŅúmķõŠ}Qãœ={ŅŅ҈5įzâÄ TVVĸ´´Ôŧ扌ŒD‡Сo_ņ۟ī•™æÍ››HŲŧysķĩ &nÅ5oܸaϟPéhŪTĒ&N7[QB~pÔ#‡§Ÿā.tŠÂø|>sŌĒoĩÁÜߖR++ÉÛĐM¤›fY“"2œ(_PęE=ž¨ô@‰ĪcŖÚJ~ÆÔ•SbęmĨæJÛĒuJĻzĩŋj?Õz1UkĨsĨîuôڈ{ņ;Y:OÅÔK×IĮä†Ũ&%’tn|LĩGŠĐąčÚÔ8 ö8\sfÃ]*ųí‡Cĩß !%Äôé,Méxę ‹,üC€-E&úw*ŌJž1 ØšWˆbÄ)=LŽĨÖ ÅVŌ`VNFÞ¤ģ/>ŲX+°[[åVr śE7'ˇ˙;͕[ø%Ŋ,/q,Ė|’›'…:WŠ ™¤Ģ"§5ķ}§ã‡ō讚TŸRxžÎK=>[÷Úņų|ZcõG•ãķų,›ĻžáNįbšŲS‚ Ũ˙ŅC­šŸŦĢįüR.šĘõ m+ƒî˙4>U ĩsē*qģĪt"ŨWŽĶũ’ÄYŽ&pũY’ļhēI‚ đGΚÂĒĝčžņ3ã‘/ēŊåūƜøP Ā 19‚Ēũ÷q™šsĖf͚‰Ž47ŠtėDąšōĖ9ŒSŪ*ääJĻsWĸ$ĒĐÍÕ ×OŠÁVm85TI„…œDC>WnP ‡LĪ–s7 NÛR)I&t­œ€éBęøY†"I6Ĩ_RØáęÛJ(ĮTj–î,$;‹Ķ\)÷äD‰Â#GLNP}7S”DŠÎ IŸ8פĸnm”…n„SÖ:ÉGU2ĖHîV\oåĸĩ19'āãĐÍ×ĩ•ŧTø¸NŲũ§•D;Ž\ܐ!‰_´­jĪĮĨgË×*Inâ,×Ĩ-e˜‘ÆÉĐFû ƒ65H2ļPÄRㄟŸ'°\ä•|Ũ¤F]2Ę|\ˇĸĖ0 4kÖL n•.PŠ1@˜Õ¯¨øĒ˛Ėņü0Ą¸`9ųąĒĸ™áÔ+Ũ7)"#ŨŅvŧ­ĸˆ\wāF ]nX§;Åúúzø|>1Ÿ­„ÔHDĪOâĐt­1ô%îÍo’ke¨§ßŅũ ë§7ŌYrŽŽÖ'ßWŪŪMOæ6.)HĖ˄õŌ0 ›1% Ąƒ;‰Å-ÄÕ`¯ĢCâTŊ‰_:ëb#\Ũx?N™Ēb*Ũ‚ųŨš‚đûĒPŦoĄDÎģYîtœĪ0 \ētÉVRNfll,ētébšG+((ĀáÇņîģīZ:&&#FŒĀ¨QŖΆŽŋhŅ"Lž<Ųōû×_]ģvEllŦųģōōrŖ  –īģté‚üü|ÄÆÆj¯Ôt•Ķ6n܈§žzĘŦË9vėXŒ=Ú ”ˆy~~>ĻL™b™Ã¨QŖĖĸÂR@åž]ētÁ´i͐œœlūn˖-X´h:d!>S§NÅāÁƒEé‰rNÉqÁÂY Úu=ē*ĪĄč nŽ_ē+nˆéåŽĶÜ2b‡â÷ĒĢFŠßŦŽ­S|'Ũ˙~ũúĄ¸¸ØüÛŌĨKM€Đ‰˙†a ??K–,ą hll,Ū}÷]ÄÅÅ9熁ōōrQPŲ ¸(§~W^^ŽAƒدܞe‹™ÎF_ųÕÆŧyķđôĶO›"ōęÕĢŅĩkWĮÔ%t÷Ū{¯9‡ŒŒ ŧūúëâYpDVßr5JŊ‘#GZö#??ß< ŽŌH…§$ÉčköiIDAT—×-"^ōŗ”ŽBx4…î~FgŲ’îđÜÆÔš59õÁķĩH}éî_îeĨ>t–iŨØns íxĘQ§Lëԝō‘GÁĻM›,ÅĐ:tH[$J!›”J2¤Đđ§ČČHØ8Ē*Íî$I(éfÆ &RĀęÕĢŅ­[7­•—ĻĮãŅgbwōÚáŽËē×Éo4Go‚I¯ōëRBč"j¤uęžu{C™¯ÛŪIŋĶ=ŧ܂”W&** DRR’QFŒ .ˆÉĄœ$ ^ûCJÚ…… Zڕ——cŅĸEļøE>î† đĀ˜íƍg"%pŠđąšwLLŒ…ōĩéōúęBģÔī†nĢrūüķĪ[T?]æ@ÉeQ[T(ũÍ @uæķP.T÷ē]LKZB7„Ō!Y¨éÖN×åōēœĩô° %)[¸pĄsŽ9RDh§ÂC<擖Ŗ§Ĩė;vėhā-[ļˆČLéi2常8äååYJ!rÂĀ ũûˆ#ëzm%!&ĻuZ:wîliSRR‚/žøÂŒ1ÖÕåáiElye‹ nęßc]mL›Æô÷ß7‚đc_§¸I*BōĖ´ęE؈ˆLœ8ŅP7n´R%ĸ}ęj—¨W`ižĒ¯I“&™†āû„q<ņ¸Žđ•. Ũ#<‚Ç‹ųw¤jkĒ ¸ęŸĢyĢę×ô)..ļ™Ķ}” )äô5Æ,ücs{ūØĮ)4ëŋŲgcÚū˜Ü¯˙íGĮ-iZ ¸ü‹zĨĨĨ!&&ÆL Ē IiiiŽ–EúĐą¤:œ’Ÿ-}čų•ŋžÉČČkĒō€i§+¨áÇcÚ´iÚ:0’(Ģ2H uu;U5nžŽfP ķ¤^Kž˙+ ˙_yģ†˙ë5;•{āÜCį˙ˋŠ>øāƒ–ÔĄŸ~ú)Š‹‹MîæVEĨVŅĨĶ í)žOlÅKÉĢoWŽ\i+11ŅRiÚ)ÛģĶÕŲsĪ=įx ‰žD|x¤D°€%1­ÔąōĄéųŲ=:=HJ*,ųÄō€€´´4 bߥUe ŨęąPҌëM´meeĨ-ëbŋ~ũl÷āaaaļ‹ūôôtˡŠË8ÕEĄÄ„ö˙Č#ØŽTœŒ?’ŽNĮ“˛IöéĶĮ$:*"KYÕš“=ˇß4!æMōč˛}ķđ.)EˆT%ųōåË&p@wBL'š'ųŽŠŠÂ°aÃ,ÕãÔ8Á`}ô‘M4¤ˆ)9ŧčüÔ"îęDôxK…\;vė°´éĐĄƒe˙xHšÎ…Õ ˛hé›9ųŋÜTĪīū`Ā€–žhAaj´ b'7ūđ)—™8qĸ-ytnn.ZĩjeËč÷û-õôīßßVКŒœDiŗ}(5R¤Bļę?ž-'ī˜1c´…¸ˆWĐûÉ:fĶķŋŖcō pj ŅšēY{ŠŅƒ‡zŅgöėŲHHH°]UTVVâäɓØĩk—›LŸ>‘‘‘6"ĸÆ9r䈨ŗQ – >ŪÜņÜŠH­›ëŗj΋/Ɔ lw˜íÚĩcmi`AĻŠTšķ&2VéüĨ>¤ n˛ķ2üYŗfMČķīÛˇ/Əˆˆ1Ŧ”ŽƒSøú$ĪIĪ”ÖË34HâúącĮđôĶOŖ}ûöG}}=Ž^ŊŠõë×[2ÃGDDā¯ũ+RSSĩ”hƒA 2Ō6Mˆy“qSÉ˙×ɏY—sUuÜē°°ĐÆM ÃĀîŨģQ]]m)QXXˆÂÂBtčĐãÆCģvíDį龔ë˜R|(Ej]ždžoŠĪ#ĻŌÁËĘĘlâ¸*ŗ‘ššŠ>}úX M\’ĄēŊ[Š÷&Äŧɑ“sJÉŊ2g{žás2ǃŠ6Ŋzõ‚×ëEvv6Μ9ƒüãĻ.VVV†QŖFaʔ)¸ûîģm—ėēûN 19ˇ”Ži¤l4ģƒBH‰cFGG#//ĪtÚ ×QTTæbĢD #˜ļÂXM |ķ‹ŊĄ¸7ŌĒÎęƒëc<Ĩ¨Nד¸@Ûļm1ū|DDDXÚN™2eee6ąY*#/ÕUe–8Ļ“$D§bÃ:¤ĶG7ĩ¤ 1!†"CŋzųÅtt´Č…uœLēOäÛĒU+[\$,Z´Č"Ę644˜EčķÉ'ŸˆVQntr’ÜJ€Đ:3D҈ün R¨—ŽŽĢežMāûË1éâcˇnŨ*^MčréŒDNSũŽ]ģvčͧĨũɓ'M—~ßĻMËw•••ŽE{œRŠXŌ!¨Sš'¨K•B‰(fûoߛŨŠņr/“üü|ˇŧëŽģ´‰ĩtW N‰ˇč›ššjëãäɓļ>h!\õS•rJĄ€ēPŧPöÕ)xŸrËPc‰›8æ/Äø —””XŌcĀÃ?ėĘ$ŽÉÕ-;žŽ_õ]Īž=mßmذÁvWëļåŲŖã¤NHéæ+ÍĶeō@4ŠĪÄnážM üË~xô}RR†ŽÕ§BÕi QRåęvíÚŲ~ײeKdddX~ˇiĶ&mZ˜P .ęYŋ~=^}õUņĘȉcē!%O M‘RĢUuAue-ŧ^obū’ŸG}Ԓt*66֖e 1ĀJOØšs§Ĩ]ĢV­!ö‘‘aąĐVUUaĶĻM!KŌw/^ÄO<ņãĮģ&os[§S– ĘUá[ūōō Ž9šž›KĮ”žącĮÚrā,^ŧØL˙č–V“ëRĄÔÕôzŊØĩkNœ8ai¯˛ôIsĮC=dų~Ų˛e(**PŌ{éß/\¸€ŪŊ{ãíˇßūIąĩNŠw$NŲŦY3KÕhÅ5iÅqËÛĘŋ,ķʕ+?~<Ū{ī= §,))1s…ĸ¯I"œSFDĮƒ]ģv™)#ÕͧOôíÛזF…ŽÕŗgO<ņÄ–vŗfÍž={BZŋZĪŋҎo_˘1Ũēu Y˙ …ęĮI"ŦÄ1šŗGbūLî8Íī!9°–••áŸ˙ü'ŌŌŌđᇚ9r$:„¨¨(1ÅOÚģw¯­˙ššGä<}ú4ōķķ1mÚ4Kģž}ûbÚ´iŽ ÔÔĶĢW/<ųä“6äœ9s&ĒĒĒÄŌ ônôĩ×^Cģv퐗—‡!C†hËM¨ä_ôy˙ũ÷ĩČ(]ÁH™#‚rũRW YĖ+Ûôüīr .āī˙;Ö¯_/~…„„ Āq.11ƒ ÂāÁƒoĩēTaUĩĩĩæĪÁ`ĮĮôéĶ-ŽÛôiÛļ-Zĩjeá<WëĐĄƏoΓ‡FŅģIŽäÕÕ՘1cN:eģ}ûöčØąŖ‰555(--Åûīŋäädŧđ čŅŖ‡ļÆJCCæÎ‹gžyÆ6į 77ˇŪzĢjFŨ}>Ÿņ(g”R‘Jå3ą7=˙›Ī+¯ŧ‚}ûöY”ģąI8”;ų|>$%%áöÛoˇPmõHq‘~ŋ“&MŌęœNzũV‰ĢũúõŗÔåö¤”(lu7O:…7âÔŠSZBiii5jēwīnŅįhÄÜšsm–]]žļmÛbčĐĄĻ{"5ô<ûėŗđzŊ¨ĒĒBtt4~ũë_#77ûÛß°qãF´hŅ{÷îŤI“PTT¤/#߄˜??Ũ‘'ŨĒĢĢCmm-jkk-é"i…„Í›77Å*Z‘§hTíũ~ŋ%Uˆdؑb)ˇ ŗq>&ĪU¤Ģŧ&]áTVVâÔŠS–‚W;wÆo~ķËz%Ää!`Š@QéA9¯s ‚Įåēä}÷Ũ‡-[ļ Yŗf8zô(ĻNŠā‰'žĀˆ#PZZŠC‡iËR4E—ÜdÖXŽ8<>‘ģČŅī¤$S*,Š^ŧs$Q•ˇhB*^eÜ)%'7œpĢ'õ5UŋŖœ-::111ļęŠHĐBÅ<ĒDWÚO*ŗ  ™ã9€U[úûŪŊ{ã(..FûöíqöėY›@×܄˜?sd 9uœ—‡Lé,ą*˜—>(Ēžxļ87¤Ô•Ĩã1•\s* ȝLx&а-oCR2ú¨Lw:˙[ a|đA >DAAļ˛[Įŧ‰T˛ˆJ%ÔCšV }ŌīuŲō8āĶ`c]Ĩk)Ģ?EfŠ=į0NÖcÎyŪYõ7§BģNW"ērđ62—ĖĖL„‡‡ãÖ[oš$}šķ&ā˜RqeԑĒmSĀä?K5)Âpd§ĩFyÖ9žĪ–ˇnMRØGn)´ŒsjÎŅŠxMŋ ÅŖIˇyé jmåDEõҧOGNiŽŲdüųy¨Ņ„(h9ØĖ/ŋ%.ĻĶą8'’CĒÂ‘‹z¸đō‹NĨä9'ĸē­T ‡#“Ö%94pŽI@´æˆ2üPÂŖģ.‘*Ū…B š8æĪØĐÃEKzÁÍsĖH ¸$.Ēô/)Ŗ, Āęī*Š1ĩâ:U}Ŗb2/€ĖÅ`)-ˆŽö‡.{ŧų"éę´â¸”ŊžŽãVP*Ų„˜7!‚*ŠŨĐĐ`1ÔĐ<4Rx“Ķ$ÉēǁĻa¤uG¸Ū'UˆÖéuü[eé¤ÜZēĮå§ĢRJ•9)(\ĒÁÂ#I”dā.憜MˆypKe!äH)å\•ÄÉVŋČ +”CpŅR‡Ą´¸‡ ×CųåŋSĀ´¤ķI’€´vn¨âĸŦ”;Č 9ވi7Ŧ %­™āx™nÕäN’G‡$žĨˆŠ8'Īø.ŨIjĖX%!'ז@ë,×\bĐY›šąˆ‹éÔōŦgCMĀõsALĪ/ERī/)95įyLšøĮ "NVZ'ąNĮY•(Š–rŽÃé ē9HŪÉYŠúĩ[ö]JjqĻk•TŠųá–?'QV!ŠņÃŋõŋt.ĘSé`ŠĘSqQ%¤tģjá\…'OÖûuc:q7‰ëđz–Riw§LļŦt„‡§xūX~Å$ŨÛ6Vŋlē.ų^™đĨĖtŧt€DbHČ)qPÉhŖKČĨ‘CÕkŨt4ilžn.NK„­ąk䏔?H'ē7!æ/ 9%ĀÔqL§Ō!¯ô}(Iˇ¸…× @Äi]Ų<]Ŋ'Ž­“$ÕAZŖ›ķSū˜Ī.æũN;IENDŽB`‚commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/000077500000000000000000000000001447311732500251305ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/AbandonedObjectPool.gif000066400000000000000000000540651447311732500314650ustar00rootroot00000000000000GIF89aÄJ÷˙˙{{{{{„{„{{„„„{{„{„„„{„„„”)”1œ)œ1œ9ŊŊŊŊÆŊŊÆÆÆŊŊÆŊÆÆÆŊÆÆÆ÷˙Æ÷˙Î˙˙˙˙˙˙Æ˙˙Î˙˙Ö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙,ÄJū;H° Áƒ*\ȰĄÃ‡#JœHąĸŋ3jÜČąŖĮ CŠI˛¤É“(SĒ\ɲĨ˗0cƜIŗĻ͛8sęÜÉŗ§ĪŸ@ƒ J´¨ŅŖH“*]Ę´ŠĶ§PŖJJĩĒÕĢXŗjŨĘĩĢׯ`ÊKļŦŲŗhĶĒ]Ëļ­ÛˇpãʝKˇŽŨģxķꕸ Aƒž€˙ŧ€đßÃ{+^˘fƒŽKžLš˛Æ1[ŪĖšŗį‘7jūLē´éēŖ/Ÿ^ÍēõŲÔaģžMģļTŲqÛŪÍģ7PŨCûNŧ8Mā…_ÎŧųHä•;ŸNŊ:_ČÖŗkß~ēDéÜÃū‹7î="øņčĶĶ.ņŧú÷đ?ŗ8?žũûzë7ԏŋŋ˙ˇü-äŪčV€ !hā‚ jĨ B6(á„OEH Q¨á†\āá… „aˆŠXĸ‡%r¨âŠIĄX‰/š(âŒĀXc˛¨ãŽ2ŲXã‰Ąh#Œōhä‘7 Icˆ7^¸d†HF)e’)ūčŖ•OĘ8å–\ēĤj]†)fI_Æ6æ™hff‘l9Ļ鿘öõ朙v˜xŪŠgž|îégŸ€ū)h „jhĄˆúgaˆ‰”ca %*Šĸ“VJéĨ–fŠéϚvjčžt2ÔĀl`ꊨĻĒęĒŦĻzĒūĨZ°ĒŦĻ–j*­ŠâzëēÚJĢ­ģĒĒ+Š [ëĢ­&Ģ랰žÚfBy&-ŖÔŗØfĢíĒ{ǎž~{ĒąÍŽ ëĢäĢAąŠÆ:kļ ģíŧô.[d¨ ˆĢo­åōģ/ŠũÚęí¯Ũū ŦŦĨjpĀĒ+đžLjÁKÜnŋg .Æ—úlH ”¯ŋ$kĖņÉŖĖoÅ_ė­Äņŧq¸ŋēđĘ6—ĖĢš$/ŧņÎūū\˛Đ&§ltĐü~Œä¨/ëœņŋN[\jˇÜĢÆMG 3ÅG#ũôÃÆžÜôĶdũ­Ōu42ÔcgŊĒÛ Į-7ĖúŪ\ĢØĖâ-ķūÅšŪŊ˛Uīũ-ށŋ=7ÆQÃÍ7Ä mäČD›Ŋ8ԂkpĖ‹1Ū€#ÍųŨB[pÎd+Nyä7ū[é“;múĐ­ˇ +áš›ēØvĮ+đĪ7kÍ:Š,ķ=ĩÄ´#ūúī*{MęŊtŽęzė‡G]đĘ@K]=Īáūę¯ąoLJ¨vo;ßĶë|üëŧ;ŌÚįG<ÛĐ ›Ē‡Ū’l¯˛‚ßėô1Ëû/ũ¤ķĐúg´ŠÉŽuī{^üJÆŧ9åKođCÜīæ/›éĪxĩûøhE8ŽYĨōā}7Bû™Ī}čķ—ú@˛ž…0Ä`ŨH…ĸZ/wÁŌ°ôW¸Í} |ūBōPŊ&:"°}GŒáÃV¨#į!1‚ŦUū6 B xPVŨ3 @B+bŦs"¤Û߀gĒōҐŠ ”āoÆD´0†j„㠏ˆ"d]0aūŗ˜ŧ,čA-bO\ę˛bŠXŇu.|ōÛÛįĮ$ŠĢobŸĶȸīQq‡§Ēá÷6H-Ŧ“šRŧjBA†ŌCŨķ$!š˜I42ō•‰“X!“ĀZ.’’$˟éˇĘö2„Bʤ({IÃ`rR•ĸ EÄ]’Ō”Læ3ŲČj²bŗTĶ˲Y`”Žü&)8EWVą•ŨĒ"hÕĮ+ŽĶ‹Đ+ÅšÉKÚJ„ņūĖÜ.9ɲqu¸´e?_'žfjđ ü2(!ãÉLgô†$!yuATö’‹ėtf*YyGô–ČsX69šĘ“ƒt%1ķ9Nb†0“ąb&Ā”ŲRVjPžeŧč=҈°"B‘‘ŠFœ×Mu|7•g;—ZC^ŌOŠ¨SšD‡J´˜Āüd0īXUęQŗ¨&͘P5DÔŖ~õ“5ĩäKZĶĒÕ‹á Ŗ[Ŋ¸VsŪMŽg cNģČMÖŲjŦ)k_úÕįņņV hb­úÔĨFĩąw“&V‹‰PÉJ”—ŸÍčQŗZĶztĶëYTI3ĨƌjR‹ÉÅdļ˜Ŧ•ūŠZ“zOĨú˛x\“áO­G*Ā^„¨¸,íGČÃf’ōĸe(0O U‰žÖļuė2UL†Ē˛p’kayÛÛP h¸Û­wEAšõÍo=ŗæ&/-ŠĶVūs˜ a3ėúzŠ`u ŪĪŪˇŊx”[yÆ˛.ƒ=›oz§ĮOŗĄŽ´ae˜o%$Éđ†Õ]Ū+šō&ļ°<>-ˇĄkđíâk¸ÂB0¨ú5ą…W|*Š P_=M™[†2øROWâ›WgF*ņíļŗ,Ž$Ā&Ü mōˇŋ3Ėq{'b克ŒÎ\īr:Áôf7¸.3‘“ķcšg?ŖgÕđV?M{­*œūÕĨĮryôžGŽĨõļŧ ’~ÎOö\IÂ`5ívËađ |5€ĄšËēEņO€ įŨ6Š{­ŪHˇ1ƒødķņ”%m.p­Œ@îë›MWąĐĻiŋūŊåË íctų2‡cÔŽĻ—ŽĒą:ĒĮ‹^¨á—ߟŧQxž˛°gÜbė› Ž“ˇė8[s×XŽŗÛŦ:īBKØÂÍ.Å5LĘæ”Ą3œŸMĄ™Ū_đ§Ē^ ĸ}b§;9@Z pŖķyûĨ/öę­oĀŧģŨ€8Ŋņ­Ø{ßvĘ÷Ŋ~…#œáũ>¸ŋŽo€K\âņxÄû]o=9Üâ78Âū yË[NÖFˆ#Ŧ]}åL°Å5wÉ6JU„ ÖÕš¯9I ÷Ú'+÷j•Å8únĶEÛvčÄh=ŸúvåÖsÔ+-t¤šęLŋúƒ†,SŖŠÂŠfšĖ(ˆYčNwškęV9ÚĐ0׿bo´•5@gž0ō›š.›˛5ŧí˛=ųĶ{Ÿô`õiÂC:īËüûčžr•c;îp+ŸDcYĘ*öœž„j3/ÛĐŦ{ųŗdÖrŠõ†æO΅öûš>õŽ=ú•ĻOŪ¨{×gˇî˛sØī,8ōĒewĻÚĒWeÂÜ SõO\+ÜC¤¤>;ē"§/ĀęSŋrnžžáŦūĪũëw˙ûŪ?øĮ/ūō“üôôú™PŨōö+Ē7_ώš°âęÕōÎäüÖUüåúûôG=ˇŗcؗ:Š´0´Ķ;/6e¸€T7€ÚဠX€X×8€č€ßrę'ˇ|&5ŠL3åv¤¤IĻô{ÛŖ‚ÔĨWŗ÷y@Õ|úÕ6ĀJp•,ŠGx˛MŠNfTx{W„”ĶlGȃõb„iĻ-ā×؃ģĮ*ŠCOÂth‰G„2mUčĢ#>ė”ƒ¨ŌZĢF‚âT|€ÄiĻRÚã+;hæÅg¤#fvS>Æl‘Ŗa‹Įl|¸‡D1(&o¤æwˆūį~i'D蕈ŽˆˆøˆŅ'3Î÷Ff*O8ˆZĶ+cS}TNF$iõˇ3ēSAnĩu€ãb¨3hæv–BÎR¯§]"…ą6Iˆ„\ȄsÄcM¸,=؃žHŒ†4•čŖR0@7FS´\—Ŗv@tW'ˆ‚ƒDnAsN6T[ÚX|š´ˆ&8.°he<'mG{ʗ4¸X-„züEjķˆAÁc?€ølėˆnûxB”“Œ ad`*ÕãpuNŽuF­ÄS6ôZį¸2įäV°¸ƒSûg€ętd˛čhŲ֑ūč0ƒ&ē¨zíx„ IuüB8$Ƒ' zî#ūPOPĻR!t)•YÂtCWe‘ģ‚‚vd‚:ƒÖ,íD‘č‘Ų¨JeøZ”V…ūØ~H•­į1īH{ōo‡q"—pwo\™q[Éq7-ƒĄp–dų•üļpešq —–pŲp —b9—ūÖ bKųjgä“úôV¨õ7;ÅR˜dIF‰42UJm•VŪ#6ŋ2”á‚. •S‚"y•Ņ䲄žé™Ũ÷™ĸ9šÛBAÉ%ÕUķŗ”7%0f‡v|¤?ÖUH š7ęTQ3ĩ“9i~ãørēÆšŽÜ„Mš)2({ČŲ5ųX9한­wœĘéœĐé*#ŠĀ%$0‘ąūÆtkh™ŗ7„ÃpØb=Ԝ+}Mŧ•gÛ靔é…Ty™é–1ÕÉ%%՜xˇ=ŗŌa=ö.ÍB0Rä2aķ.Ŋ“‡xš– 1™B sš ‘/å!`SŲ‹ũô›Ix0†"Zh…ÍmÃĸyRäé öąMT>Ģx,ŦĮW[3uäuuˆToØb$xōIĸ‰æ,Ŗ[@›’‰BúˆM8†¤H:¤Jš¤Üg7õš%%)3ø$.#y>Ä?Ԝ4fŖ(_Ü)_.j™ĩ( ē:āȔ3Wbŧ¸…N衙Ŗ…ĻĻJØĻÂXšys§uÚ,&Û4=‚UÄNĖé6ūœ…4XšvTēmē;/įZ S5ģI…R)wLˇ§â7v¨cļGíˇœP'@&äŠ|8›*ŖJǧz9ĸWœēB€Ú1D‰Te7SŽ-‡ú™Š$sƒW•)Ļ éėæií’G8:ĻÛU‹­Čžī™Žˆ†’ęhrį-PXœAˇ3€€j1Ŧ„Ĩķ…9ÃO;W;H˜O .:3vœ9ĘëÖ'–7qrwŠ–qŠ•øÚ–t9–vųqaÉ'hI¯ri—ūę•û¯ũz¯nɖ˰ë°[ąą‚Qœ8Ų:ĨhŠ›ģdNę´VÅTĩ%Le¨šØlu%ūĸ"xV˛ô]DŦ¤YŗõR`Úgŗ:ģŗé24ƒEHŖ…lV<˛öŦū%g ĘĻQtb–úN„.Üĩ˜í„˜*ĩ˜EWãM˛e´Ü†¨53nšƒ0왏ÂÉ0Ũĩh†ļƒflY4Fš4u§¨’6C:Zz‡ÁūĘŧqšĩĘĘŠÁIMĨĻąŗ9˛Ž;T‘ī¤ZV´S¯b‚+ØcáxS™å-5ŽĒŽ/v?×Dåcō۟zôbbd3ĒJtĖûĨ×Ã;DŽ lJž„æŦÂëŽÍj’ķŗR˛M*t:6öS<Ā_/ƒsŒt %<Ĩ8ĸ÷[@oĢŋ•ķ§žĘ3ũÛtĩÂĢ9:LžŧŠƒc,ڞEŧ)šŊ=÷’Uš%QzĀØk2ƒ–A…Æ;ē”Āû`/e7‚:…ÃÁ0ŗēŅ矴­ŠtõŸųŪLĢĀ•ŊŨîŅxŒŪH´Ųf}šÄ‹ 6Zf}Įžīŧ’¨zļ–tˇ,ģĀŌŽÚ+\nŪ=ŖÛ,bdi=eyÅēKĐ5[OÛĐŗÅĸh›iZO0ŗËŨëͧŗÆknŧc’Ûˆfŧ;‘…;ą¸=ŗ<Į9îŲ`ŗÎmHm.^ä™-aë;ņ¤Uđ—‚0Ü%xn­õÚÕėKs•€Ā;§ ŨD'Ũ!ĶĢÕÕ-úGĢ'ˇûĶŧqĶČ 88lZīŦÕŽōœbÂR߂á+bdáŨgūkÖ3k~ÎFT^ÚiŽĶ2,­G,Ũ†¸mäXā9QV(2´ø˜šërfŖ¸ã‡…ã–Æģ:C~$ukŽGãĩåcíßsc•ŦēgyFcš ž˜›}ĻUģ|kŖ+8'Ū¸á$t%3Ķö[äeũč„+$RÍŦūģVÖĖÜȂ…4”†ež˜Ūšä>čĻyēĘGÎčvÎ/xŽ"ŖeČŖ[Dāęĩ fė#ŒÎķŒ3Ų7įZį˙Ŋ¸,ü‰’.é•LæļœŽo}û}ĀF:u|ČxĻgkŅtŽę¨ĢŪĢ>3é*ã~†Ë™|ČÛˇŨ .y°3<:7węŠËx1ŽK’NEæ<ŌĘLL:ūFö§ØKi7ĖŊ1iĖâŨdđØÎåKˇí$•a.ŦEÚŊČsĩÁeÔæ0ît1\Cāš 5˙^á,,^ÜÖN!ŸĶYôÜ*ĩyŽšĄ“y˜ĨŸ0í^Žˇ2#žß#ÕR_îËY´Đ،T¯]W3č~“R@ŸÉōKŅ9ZĻÆŊ‘ÎĐŗ+™“×>š#NĪ §TÍÄ/ķa/ö,_ÉrČ|=Ŧā4ĩY‡ī÷ôŧįá'Ü{ŦÖa÷‹¤ô=zPã§õįá‰ŋēK˛H N€ Äķ˘\īø˙ø/~‹ ¯˜ÅÎTE¯Üí;⧅vДU°Ÿ´öw‚Āū¸ŧ„Iå逝û#ö, 4}?>õ÷v.HüĘSúƒÚ*>”ĮUŠ2ĩ×=į1ĪûíĪ@Ũa–ž2˙œR˙ô˙öĪ)Œė#´ę hā`ƒĀƒ j8˜ĐĄ†%„¸ĄâC… 5\\hĐĸGz¤¸ÁÂĀ j¤ˆ’!˕*cž\Iŗd͘2Kž\ĐÁįO A…%ZÔhŅ5´Đ0å˓*_2|šķæTœ ›ædČĐãV‘,ižėjU'L´ioâœÉÕm[¸låĒ=ģ–ŽÍĩ { ]`ÖīߒUĩZŨjŗ)^°2CÉaqĘÅ›t\3Ĩ\ŧ#æÜyCƒŖūĄE‡îģ1°Č—?&ŒšpiDØŊš|ąimÛ#YËFˆ›7­Rg;;s]äÄßŪŊēwôsčŅ“‚]*Yfęę˜ž™8xæÂ/ŧ†)|ĸÅËĢÁ–]¯īûåĖãƟk×~ōø÷mŌԚīõšö̝,Š.0M*¸6ÃʤĢÜ AŗÚ =ūÔŠ, ķŗJĀ´8´‹§čB-)ôœj°Øēā$8š¤`”($¯¨šMˇŠ.’­Å5īC’ėģņ,øęÃožētND&›ė`ē õ›P<Ŗ,+Bģōq;ąvēlÁwz)Ŋ˜Ē’r@ •CōH#Õl3Mˇlō/¨žˆūÜ0ŋ ×´Ķ<û&›ąø°ZĖŅ#pŖ mōN=ß[ŌI'ë<Ģôhlq!k‰$ō"O][ĘĢNYlQ"ˆ:UõԏÜ|ąK4ß\ŗČë…ôÖĐHüˆoŠv-c›ND÷žŌiĘSKôMŨÆ&C|Ę7%\âT”ˆDOĨʅ(Q"(šž.xžĘ˜ÖBļ-Š0ey#™îĨ”rIĻzŪ2ĨŌ1ļ}Ņr!`CD7‚ud„1j jTŗsreˆŧQõŧįĸŲ„gŽwėŠ÷båà fˆŦÛGÄā6 €c8‡ŋ,žŌ5KdevRUA$ ŠĸlĨ(ŸHJßį~¤2 (sÖG?./dū!E˛Ļî ~:Ú[Āõ˜"Ôa”_dĻC‡aR&Āôãs ä•ļ&5ÂáČĩr7’ ~{C&‹°ŖĒsFS#—‘žąŠG/j˛x‹’'ÉõÉ?a‹ąTå@;rPĶ qU?kaĪTŠEƒbG&¸šaŧ\Ĩžne[ëĀķ ŌŽ Md6Û[%5˜Ņå‘×b&´ôčË{JƒÅURˆæJąQáW#jdŽ4JfBt‡*Ô]&mxÚ$>{˜ĪĻjĮ“Ų¤jĸvĨ˜ˆž˛ QŦå*ŗøU,žō•3"å*o9VVš)QÍŲ¸ŲAœM°Ŗ ķT‹îG=Ί­n?ãūkK(J ‰Žą#UgS€Ę n4­iLB7Ō=ĩ‘hKØ)^ÖSŸrâ;{e<’Ėž‰Õæ>Kģ:ūø3Ļ—äå3“øš@2‘ĢšÅ_éhËPÚž3†ëÔÔ¨E˞ĩ>o-`Rö•Đ2>($;Z :StŠÕ¸h+*lßrTUá’Vģ;qK]]•RkˆMĐ˜Ķ!mdõķвĐĨŪErɈŠC,TMk_ōurrÛĨĪ8ŧcŊ­R!˜ŽEĄ’5͘l|ŅšUÁ§ĘŖŒÅ^<ĸˇR§ŧ *a/R‘)&“_ģЏę[_ė^’´‹ũŽ“lzÎÄ §°:¯ū5}ļ(án_l’€î–ĮļžŋCæ¤F˛5Ä ˇoÁ%ÚŌĀ$ô@ÉfÎ- ôīz¤`Ķ™e\\úįS5ā]× ąhŲT™EúQĸ*’‘j‘i؆YÅ)æVÄZĖ$ē‰%BŌKŽ•ķFĨÁÄŪ"ZĀøs0c=YuC–ķ}#ėÔˇ‘NüũSCę`Ŧ=Ĩ*ˆfãîE¨ &zxõô‹b7M˜ĻuĸŌu ÷ڈÜuˇ5œĄßVuPōōy'*KōvéLéæÜšIƕlâ¸s(_ ĶæU€bĮĄëšJë}4SŗKdH/§BGūŸ¯ 4ŸŽíŒ~&ãąƒü”ŽfáÅ@DcWūĩCíˇĖr#vG§&LÃ'`WYëzõU?Û°@Ū!Á]; [:TzŦŨ†ŠīKĘĄūö˜{`8bP¨ėĒéĢO!G8JŲj€%xØåXwsV2rÄm$ēÄi%ß9šĩcē•yW-ŽxŸG§§QšøĘS?:ĖiĻ ¤Õ”–ÁãŊŊ/+\DßÄMrˆˇ‡üÆ4 tĐĨ¸“°sķ'ר餉ōkgûÚÕϟúи/@îpwĀ0÷ģįŊîyŋûŪķžüũîvŸģŨõNø¸ķŨî{7<āxÅC~ņˆīûãīwĘ#žî„o<â9ųɃ>î˜oãū˙wŠû„ØÍnÔÕîĀcŖîi•ÖÛSt˜ÃŲæī5|žzĢé­y¤ĄÂŨĖVŨ$Đė5$ Å#<¤ßä†htũđvŠí¯]íÅKíPŒ+moNöÉęŨ˙].ņC9Ŋô “U“ÕūŪ Ũ‹ĘųÄ`'•Š"ũvpaˇxFí šģ?Nãčs4›33Š:āķ&ëXŠš+ĮrĨ†ę­yr!:ĨQ%ėŠ+ŋ*/eB§ë 9|Ú>´9†PŸ’‹ŋVĶ™#Q6é~ĸA=qßK—•ģA— —ú›› râÃē)Ҝà I4ŌIžsAĐŌŋ°@AėSĀļøŊ¤ū˜”$š’ĸå8¤7 ’å Ã1Ē")’i3š)\Cņá’Ë CÛŖí5‚{ŠJËC‹: xS19[Aāŗ—ĀJĢ[ēœržßāŦ˜ŽÎ!¤ķx˛€+¤Ôž cą+Ė•žJįÚ"0|ÂY‹ĄfCŖŋÁŽŽ°,ADrăc;7|ŗ‘“ũē’Ë[ü˜á—[ÜE\äE_ėE`üEj;a F`lˆ¤—ûķ :Šō3Žđ,4”BR›¸Ŋ5ĘEĨĸDnt+ŧDī3"PÔX¤ĒāB3$, b•åJ4v˛"ĶąÆ=ėÆI„Åܑ4: äCļK#?]ūD€ä\,HHŲģEƒü˜ ÁƀH„ÔUË(ĘÁ 4š×J§Œ8¤ÚōĀj|‘÷ņ+Ŧ‰ˆč3ë5W<-KG¤Čœ†“āRĸPąŦ[ŗ!ā"ÉZSĸ-: ęk5ëķ26LÉ6D-`ÁēX čąÁθˆķŒÜƒAĀPJsˆü‘ü Š\‹dÄVC”‘(>K1ŗŪ˜D’žZ$4#3铐Ũ‰5ŪŗĮ)üF–ŠđBĢ&{šsH;\‹}ۚ’Fq2IdļG<Á ”BĄD;lŲ/Å`FhÚÉaĸī!Ë뉞S| ܙŽi Z›8ؐ°ƒÂÄ™û@qļ‰ėĻūŌ/vD¤¨ĀÖpˆâå:: ‹ŠFē-ޞ&j2)ā1¸Ät•™šKđ‚ĨĮė+ąÉlä:pyŖ-qÖ3 ‰{é˛ÄĮāÔ§îû’ęĀ,k&ķ˜¯ ŸuėŋķČ 3#ĩ Ԓk3“,Bš>"Ģ‹Ôô#ØyÎí¨ÍûLĮt,Ë 2Zk ŊFW›’Ĩš§DėC–CĖZI⠊o*ŋ>#Aš čƒ? ÉéĄÅøŖ§2é6_“ĐÃ\Ņ’˜*+&ÚÔ­ŨBPāč"͊Žu<Ą+ĸ@ļ ‚ÁžŒĀ@üœ*ŧŌ,- p€Œ€ĸXÍĶÎÚQŲøū0UyīņQÄĢãDģāÎČÎ{,”­dŦ˛@7ŖŨ1uÆž|¸|ôš3Ė“žd7ĨB¸ÜNáÚļYô DžÖXˆ?•DŽ´Nv„ˆ;ôLĢĢSRdzĸĸē.ÍLbiĐWSŅ`RĸčJ)ÛĐÍ °ō a˜,ƒˇËi éŋßDIEŦPĄ¨¸¤-ë ?KŽ­@OrÕ§)™ÚĄF^CĒ´cQítĒ~bLtGĖŌ)G͑Ŋą$ĸēŽ+š¨āĘ͏āÕ4+ĐAžØY)0]›aRM˜rUŽyÆ!u riĘņKšr;ŋmėꐓ{ēc•9ˇ‚Õpūœĩ‹Lļũ;3ßZO\u$Šú¨ķ›Šs›‚XDDlÕ|ŊSád ՂIâˇFĨM3Lŗė-čÂQÕčØÛ@žöÔ)d*CÔÁ‚´Tlr™yÁŖx  XŠ™-×s´ņŒŋ5ÚĄÔ`-8‚´Hʈu6‹ĀԌφseļÔXCĨ*Ü\°|ÆÁKzôŊ‘Xc Ķ3éNœ5/šˆ1؂ą ŲXã”[[*R(ĩũ›eĸŦ)õĀ´ČčëËëĸ8;ˆq퀛 M \Ÿ\ŋܖÜ•}Áč)¤a×qCĀ,ŦœÆÉ´#|DšŦĐ2}É>ŅŊBĄÖtĸJĮbĻūÖKİąŖÛ]Ûö(ĒV„X¯%Z•¨Øik,sX(ŗĻŸÜŨ"Ô4BsbŠLĶÁ[‘2ģbE’%YŖ \į5ÜÂŨT‹āCŠU÷T/ôŖFX1OrsOžiÜŖŠšŅZŠüâZXAÚn¤*ęSBÂH%ß$:ĸKe#)DyD™‘Å8ÍđÖÕ*ÚŲũ"°ŨĮ„\NvÃđˇĸãÎėÔĪDQrJäÄÂ8RŨ“•žũ[ĄxŪčåāÉb"ɸАũMˆ§8ŸãÉ›Zā˜šÁŲ:ōÖpÎ å#~Eׯ §ĸĀjՊS܍tŌZSų ČaÜ8ÕĢLōŊ\<ū`ûDų[2ĄšĀÁĒ N{=Ģ­74ÚÄ:>Ę÷ØOĀĨ؟@ãÁĩŲ&•ÔhF7Ļ$Ā)ˇ" ŌÛ-œ.I°aē> ĶÛŨ#ãmēa Õ¸ąēK'DŲxĘēЈÛČh…%ØĨ%v$ÉĒÍZɜ¯ûĸáŽĘSĶĮ›iL@:Z ō(ŌģŦ=1qátcUĻKŦ"9?!Ŗ‰œĶāzÁ]ˆ(> äĨ-1˛$ŦģŌ‘J:Šr‘)] _ĨŽŧßîF ŊáđšUPüēΚŅĖŠÉ›¤ãŌ-Ô3ÃŋRYÛ%SYÁdf@†â'Ž9ũšâ B)[Č`=åķĐ3GŋDCķ}“'ūõäkŲOŠŠ^Ž´rËÚTKƒVl5ŲØC’õÔøČxVEÅ|KLĘ\âŦËũŲ‚LגôŪ÷ėAہ9Ž{`œāĩøōdNžįņIį°M™¤ŧ1äĀÉk=˜÷˛§ÃásžØõCQ)Dß[áŦŖÖÛ*âąôBæÂˆ*ÍØ2Ģ­F\ŗƒ´į˙•hüzf~}1Ú:š÷R­ÃZ´“cúhwĩ§m<é›îäķāPFœf Z AOÅÕĢųą‰cˇÖgŽP5cûÃYÔŲMĘô֏åČŽÚ’1žb§%{—bY¨Žčŗî.BĻK\=™^uF"Ü]‰?_zR…}āúDiģ6ëūĄåļb_eú@JčŨ˛ÉuŦĢØĐø WڅāÅž šû‰đÚ7'kĄL‘ĸŒYßCØlēŨæĄĒ5”1ü4ĖzÜ#ŠžËzë­úTNˆ”¯1*Ãj—Œs2‹Kŋ.6Mŧís.•ŪGø˜ĢŪ Ã°(llũež$ڛŦ@–ŨČ4ŋŪkŊ–ģ[Ÿņ:ö˜ŖĀųž\Čۅ×6 ÚiJi7›mĮÆ7ŽlÕc8Z5íŗØ7i:ģ§Éąéķđr4Ļ{ĨÆ )™Ømg´ö‰¸ēXrĻ@ĄwŦIŽQ„ņ˛āūraŽFÉ .įNs+Á+<šûūŧ%<Îcr(O<Ī“ÕSf(˙B`VÆēŠ ^đX Î iĒā^ęäŊE“čfIĒĢ–ŪŽCczÍŋ2 ˀšß‚åAF3oüĻ])ž´ Úwl#uķ)C/ũ°LĻĻM.åũÖ핏íҏ;ˇėU– ÷(@ã9ڈ,=tŗu9”6 íä­ ŋpák88cO­!ûn&ãu÷‚čБ)6$ë6Ö_ŸUt¸mÖā–¤Rb}Pƒqj%ģÕFŋõčåô]Vķ’ĩ 1žƒÄÎsŠSt–‹+kļ:spTZÎ-Ļ؟ļÍÉd:(¸Ew"!g‡Vö–Ũsx×6fđĮūšØŗāV˙#bĶ,éjëj ĮĶˀô…cbë ™ÚĢ.í.ŅTl‹HĖS&;›ōæv1-õ'ÉBB¤o'ŗėáæ‹ŪøŽ%¯?ĄgGwå’Åôåpiĩ2$|‰ËląÎ:Ŧ˛?īķ!xčÄ7>; )Šhļ Ī$t×x‡øŖĩx›šŦēdš-løũų߂_|37_œOzŠ×öĸÜS;ßŪ8u)”Ģ&ÂŖĘšaÄÃrSqާoŖ3đ´*0á:’8q4´u˛Ü“gޏŋÂz[ĸž§5f¤BbcҰųQ9Žšz{Qīz‰îs~IÚh™‹ūã ˛/qy×Ģ>;eË—ŋĀĮÁ”Đųį¨H˛ēÂ+Üj.å"ī†×iˇķWž`–jX&i†ÜôŠę"qšk™lĄē}ØL/zËßú{Û%q˙ŪÄVpšáęĩūļŪöíúlė2čĪCÖĮmeųĘŋQÃ14j‘_ՆVõ@&ˇ-7ü´h‰ŦPoķėāΈ 6@đāƒ &D¨`CˆNŒ(ņĄEŠ+rÜčQaƐAŽt(qA‡”*;,¸hĄ ƒ^j$HĶ%Cˆvš|™PŚA5p¸ŠĐÂ@Ÿ9eô q¨É L5ü”ČÔ$ɏXˇ^Ėębūƒ•bĮ’-kÖlKĒƒn¸*iÛļ;yj˜ ā%€ˆH¯jl¨ÁÂԈkÍøĩ&WÄ]‹Ôēx`B”g'SŽlYeƒ™yjފ8!MŊŠ6ĨؐtŌ‰q{Eė˛kēĒŦŖė:Ų"Y0JįŠš ūČiE8ļõe}›eŲ#“Ą2‡#§‚%ū‰œĻiļĢnWRBĢ^{U×&„̆žiĘY8*ĢčĻĢ0Åj.œnd›­Uvį׈úš„°uBІ„ŲŦ‘Ü%%Sް2ėķĮ# ũ.zņzˆĨuĻ.7]—âHdĢ á&dPĖ1Ô‡wôÖlēÛ(ēŸLYp/ äggaœ1ŸÜn•Ąˇ~&ûķÜ"{<´~9;öŗsâUmĩÄņ…ķtF] Žp‘wgü=ô´ļĒ 2ؕ÷åë†[4p‹Ą}á‘r*]ĶrV—ŌŸ.°čÕéãéOÛI&Erûûõי‹Í7Z›_Gs_ƒēŗ9öšįŨ!knˇōÍ[~ A{ūķįœŽWÛÖĩ1×I*]3ąūú´›îËŖ[œõâėŪ&™|æĪĶũ~ЉõælŲ9"Ŧxúy—š{ĸõļvĪΨŪħ*ã îā'2éMO,ĩ*ÍNV†Ŗä'WŪōJÎŦō•ēąīQ”ãāōĀĩ6Vį˛QĨ¨2•LĩĘ_rąĘON§“/)ålâI˛"'ž QŽ}>ĖÕ"ą-āfqĘųØĻčP‰K|"Ą˜ą%Z­4 ‹"31eą‹NŲ] _¤-ĩPĘe?Ɏ§€åĪl‘IēúķrGÆ„îë Ã(§´QË ņ!Ü EĮAÂQ-nIÎŊt4$›đ "¤ūąáwŦ*0„–TŧÆĸ€ŗF„ĒųäĸtJQÆ\:‹$oF‰-Uvō#Éc ƒķžá¤Büš¸—åpv’ü ÃėhG–LŗĘ ÜdX•ģ8 BKáW ë538ēlpžŌ×°Ė…09v0ˆņģ#æôJŖõÆBØAšģ˜ÎuĒŗNôČÆØ ÅŋČĶ:ƒeĶR•ėČHI=Ō× ëŌŊîe,?áâ%7YGcsްA1ų¸ë}î_˜J" čÂ/`Ī"’“ĩ9› uh%ÁyIJvĨY(CÔūä×ĘR–Ō0­œéF˛)ŋšĒM•<ũ$>§'¯æX'&ĸūOϤ–+ŠĄ¯Ĩųʛך(aöP$Ō(•Ēį:­51õ ƖÔÉBŊl}zjaBēRo†3Ĩķ‹—+6ÆzŌ՞u]įŸ6g×xîŽQ„ˆ°j´m椊DZĘf¸Įēz!+UljUĨĒÖ­@T°SBæÎŽ2Ŧ?U´*†Scr|ŌÕÃņJc+¤'IÕo˛´­(bŧЀĖļļ pms‹ÛÜævļ¸ĩ­o{+\Ûūv¸ē5nq‰kÜāwš´MîpĄ+Ũã2÷ļŧm@sŗkŨæB7¸ĪĩŦXęGF`ĩĐ>UÕZ,äKƒyČĩ'…ė{WࠂׁNЭϏ+§F˛‰œ ūŲ,bĐO‹“=đcUĒ`öŒõ}0„Íâā/¨l$=áNŦ6P‚†Î…ÄJã0bÉĻĩBŅŖđeHHÍRČlüƒgÍĖ‘īŒWDÍq1‰KĖÚˇĻžA1ƒ\%!ĮŠlâÎÄHRŽyTy7|ŊŽ…Ä6eĮ܈vÁCIŅrŽ”ßRõ›ĒôƒŒ×˙Å)|{ $ë“ §×Œîå+ßÜƚ6čë €LŸú)Š>õwĸí_ßúŅī}6UËQSąÅ6oɓ*52|ęękūæã˙jŊŊ== ¤¤Ũv;÷9ĩˇAÛ)N †a1ßŋ Íi^å@Ę÷=Øôa_õE XH`÷a_b[đ 3}ÔNüҝÜčŒÜ_Œæ…ËūdČ]0KžÉžj´ŲŪÛĄDK€ā[DŌb}HՀG™ZЉɠ`ZãšĮ§¤Ųb\Z°‘×7eímô5`D=āöußõAā\DĄžœÁ]I¸ Á´Ü‡˜TVQ^dKAŽ2yWŲ͞Đxœ`-mUIĻ6Āo ˆÄ¸]đüĆtË}،Íß#ŲÔkđՋMDXEļā6Ę89!xAĄ÷Y`%N ÷ č\Ni"Ô~PÂÎŊe Éáā]\ŖMŅā$Đ#RRÔÅŲ™HĨazŠF0ΚđŽŨgqH‡ôÅiŨ2ĸĖ9æÕ@tžū$ęQfŸNcƒDÎ ŽĄ!*Ä"&”ŅŨÎ'qđ´O3ē‹SįÍ!n„–šņpĀŨŲ™'áŌ҉ŲĒhV D.é!— íG^^#ē LũX4&¤Áa  āב)YŸ•'EÎÍáHöÅūҚå%ĄAŪQ,FÂÕʸ0wpŖM[Ŧž1t0MIRīŠPļŦš?! Ų­ĄæÁ–Bö$ĩaےÉŸņ×Ôqˆm=Í_aˆ–#:ŸA `A#Ŗå‹āđc7â˜Ö˜\Û¨M Öbú#"ōSė#–$|-#üEÛkHĨOļ%„1¤M]V$Ų×ĮūqqlmeŦnׯ‚lÉvŦĘŌ–ÉúĘ~Ŧ†Ŧ˞ŦĖÖŦČîvũj…)ˆ´ôšĩ\…Ģ ,a͔ã´Ę#|lK1>œĩß >¤Ž:ėÔ:j”H,Öf­œh-ī8iĐ ‰EŦęâc0Âd!ĄËųFŠÕž-ÃâęÍQ,×Öū­[ĸŨÚm´ølgôQādĪ;ÍcÄŨÜtČëlLÖŖ?& nŧVmÃÆíkáœŪVn¯â­å'íÄõôĶ|bĻŲEcæG}éEIÖŦdëŦn×Ü ÂmäÆŽÜnKŪfކÚ.ŠÉ îFĨC ĐĐ]]ú%VŪ…(ˆ˛¨ ņR˜ŧ¨ĸīļíÁîėB.žÔîîölõž&^o,ũ]ÕVÔ$đĻŅúŲKŅ‹Æ$ČĐ¯ä%j5ĨäJoVõjīÎŅīb†ũnízhÕ õĘÕÔDVĸčđ]ʒä!įúN^™JĮFžåûBoüRnūN0ĪE ĪÚ-ēĻEJîŪūNņūMøf\H&h`đ’뀊ę2.ōš­ûĘî¸ĸiŽR0 įœ×đYlhĘܗM‚Đ(nę7PW‘ĻĻj‡Ļ`ōÁ0ü61Ņ\0Gą::?Ë rO'!ëi{*[\ZĸaW,°‚E/3iĖogīC ũ´qžž“‘)×ņ(u+ҧš÷ą˙1 ûÔŽ@qōŋ1œŠ2#/Ŧˇ*k{5ëæxLĄ:2$?r#G˛&c˛%GÅG&2­€˛Į (ëpŦŠyŧŠ*7†íØNcŌļˆR*Ξ,×r*ŅōG¨ą(īōÁĄE";éqéŦsu×v 1sūr%svuWqAW:Ws=3uAs1+2k—5ŗ2S31w35W—m /ŗe=ŗĮ˛ãë29¯3;ˇŗ;ŋ3<ë­!˙rKa^ĸHS Ec´IW/GŸ4HR†%’´ēt&ĒtåĻ4Ķ´LĮKcâHŋ4OßôLû4P{DK4ötE5#5/ÛôíSI+5TGõCK*G´T_ĩŽ2u›tÁi5Vĩgz5X[īXī˛XÛīY—uũĒu)ŗĩ[7é[Ķūs\į/Wæ\ß5^Ûu¤Ļu^÷5ņuXSĩ_öFö[vA5`öb#v;6dCLdĶo]OļP ļegļfßî^oļgcã8WöA6iûsiwíiË3P‹6i7vjËâkOļkĮļą6mĪŲl—sVnßļoŗsoĢkX÷oĶ6q;áq_:7sßksOIn=w›&w…aķ7_ˇug7v_wÍnˇvˇw‡7xëÖC‹ˇyƒ7zķÎķyˇwzŋˇ{Į7|[7CSˇ‚ U'į÷&_23'īw&˙ˇ€‡Ų0€ŠmŌ€xëw6ąP.8€38„'¸„+¸…ë}ī¨mūO*vxz8ˆ8wŌچ“ōūĻjˆ§xŦŽ—ˆĢ¸‹ˇ8Œw'´Jˇe0d 3rÚÎ%F…7ÚĘžĮīŲ Ņd˙āāâ”Ëú1̊ĩ×Îą’ō]ōøDĀŸ°īŲ$Y‹é]O ų*}Ë~šŽo1÷hG"×x„§yz†j‚ŲQ’WXHg)IĶúĪlˆ B„ŌŌZ…Or‰ēŠfŸ7 …—$l–ÖŅņąĢúë‚‹Oä iĸ+ņĢsdE›ã1…'„û噪ųãÍÆøk{ųbėėlĮŦŠ T´šũĞ’0ÍëbęHĖ0nģĘķĘzš ŦO2Ŧ-Ņ ņb{ąĢ\›ūąõ:ŦžOŌ­Ûz€dxVGŸ.!P]¨ōßã8.ų_~8šštTúŽč Ė} ¯Z™ “ĢƒM ,ž]°ßŒ)ö%xŖūëȑÁÔzņåcšÔB;;{h2,ū^!zKé`¸oXČå–×Nė€Šãœ p.0[™ųĮĨģ9–ČĻp‹që>ų Ö Âh;è..<ˇ˛aüŧ=CûĸB‰é(ė(rāęŦ^ÍßËę|] ci ×ɍ€" ×'AĄ;TY|DúZRjtÉÍsü†Ĩžâ4Ų|ļąģ΋‰čūŧé9Ŋųąí^˛ˆËGõƒßŲÉę…ŧĶģŽÍ¯ūũ›ĸÉsģŊūíü Ĩ=Ū;/”y˟‡×}ī=ŋ0ŨĮĖVN)ĒŊĐÃįÜĮ{Ú#ž)âŌâ‹{ČŅ…¸WŠĘË&üŒ=TSĒŧÖHëČĖä›āÔÛ{ȟúV5~†žú>ü"å=ܛS„X+=3ū°¯dÚOģΞäã<â~ļŖūá§ áģã3~)ēMØ{æ+uŲÛh˙Ŧˇß˜ë‹”žËÅ,yĮÚOŋÛcA9Ú}ö.˜:~@Å\ČøĀËKŒ‹8ū€žņ§ŊŖņ~îÃä/~u,ū Ũŋnžũ§ö„6lĐPđ`Bƒ 6døĐaDˆ5XhĐcF9vôøūdH‘#I–4yrÁI•+Yfl€°`Ė…2Ō”9Ķæ…; î¸á'P‚Byū´ ´'ΤJ}8´éŌĄDu_#ĢBŲL$1&8MܑB#YS´ĐÛ ĨĪŠ>ĩŧŽŋL1Ũ@*=ũÔP9:mÎKõ’2 5ô5 aēP.j“Į,‹mGo=UB9ÉÎ,OWi­ÕõR,yÍūUą3EsUв¨­6 ãj ZƒE6Y?Ã5V5D=ŨtĖÅRåt"3ŨlmUU‘Äq& ´Á/íRDM=6ZƒîTW#v}ØT^éĨ‰Ųo™RČ_e7Îo+žđ&!]ĩ&8×÷]‚•ĩ”Ŧƒ^™E•YéĨ“nׯũbkôÕW¯õ¸f0éęUģÛļ™ÛUKSŗ;Z ˜vē˜~zŠ›fÚjĒĄvÚj¨ąžúꎧv€ë¨Îúę¨Į6;ėŠĢ†Zj°å.ÛëēãŽÛëš×Ž{ošŠÖÚéĒÍv€lˇņ›nģ_\lŽßúk¸‡Ušō˙\ŽūÜ#Rl’ķÍ=Ī ŌgaėpS1i&éô[ÍBŲíâw“d&ÙūŠW0ÁĐ*NģZÖđŽöŽöQË>rĄ•Ã40AŪ‡$!¸î×Cōđ‡>ŧûˆhŋ"ņˆ€šP dÃė0}e"aÀˇ'÷lNßūrWĢø•6õĢ…al×­´h4–ʉ9Tãd:7žîœŖŨöâG;ēq!iÖŖ4Džâu‘Šî+Hę°č/ø˛5—"ä•’ƒÖņ˜™52ū-GlL^&_&FōüS #øIĸ)P”ƒbâƜW ZAd–UjŒüÁ%-Q4•‚}ga‰’‰/5ŗ^GŠ !&$§IgŽę™Ņߨ9MkV›×Ôf6ķÆÍm~Ķ›áįÜâ66æIį=‰åŲŲÎ/U…!SaæCvi2?á2N\ņ™­žC{„@!a`hLąp2š,[eBŸšP††ĘĄŖ˛ūÉęK­L‘—ÆŦІ.ęN˜t4ŖÅé(ûFz40Ė šėI­4Y#Ÿ—5•špw‹*âC÷ēq ;”Ũ ''ÄÛMoÜ2—94P:3šÛFŽä~ėņ Ũƒd Ķg^Š{U[įĒ‚6ŠkÕ* ūŦ‚įķlČˆuO]‡9ŪēRRímŅb;ĨĒĮ1‘žL~֌fO?T͟ūO›13˛îdZų šĩÛXŌ&„40ĐPķę}Ĩ3W(ŦŦŧe‡HŦÖŊļØõ>x+"5gbé,ĶüöõZ4ŠÚŅNØFH-í8Ņy>Ā.Ę/hKHŽĀČ4ÂŨqčŊąFˇAŽÚë ™ą‡ŽĘžJŗH?D\*ŌœRƒYāhžS§Ū˛7=Bb¤l&&“Ųn,Œ=Paęûâ×`ĸņl}HâR ÄYå,I™ˇŗúíūˆR‚|i0ÕĀų €ØüæÁųÍū’‘žë<įås÷WŨ¤œ.ŲĮz–Ą °åëA ã9ãđ rĨ¨ŖĮ L /T‘ ĒlfS,æ.f1a*ķ)ŊÜė™3x~mžsœŋ}#púÎCĶē"mÚP?RĐZíĪIÎĘäGQĮįMëRŅŠĶø Ã§{^_§÷ŅžöTÛōžQYåĶÕvŸ]įnßÉįéŽv”h镇ÍTY…œg%J9pš Ī@*̍‡õuž"̐#1ÆäųŦÚr}Äy&kjáÖQˇ *“.ŗc•=ķŅgčâōÆö ËũķA'=ąTrA›Õ[ˇn–ķ}-&‹weˇļ<Ž ,÷›Ÿ ´•­ä‹ū“ŋŸõЎ˙bGfėn‡4K8Oú=côxŽîĐ$Ē Aĸ€Âĸ”nüĸ'ô/ŸN-QüČ_nØđŠŌR¤C†/ļ>ĒY†¯øvŖGž(ĩp"€ī´ŽŽ„Č,°kp]l@Ē‹Î ŖģŪĖ M=ä+Ģ mĢöėĐdIÎ2-ū&ŠęËŅRėĪhÂ*üĪ ĩë…2ęŲp4hŅPæōDā zj´ĐŊÂĖΞĢŊ¨ Äō0ũč в,ÉЋ´t/ÉR+˛ąĮ´ĖŧņŲĩ€#†îĐwCūȰAÔ0ā,1ú01ātĒ  'ū`¤ČCĮæ‹+.K 8‹ŗ(‹­ūpފjž’˛+Ä8++čĐš†É—LŌô­ŊhņŌ>nW kįc2.ę€EĨ ķĖP-˜ņÚLãŖv,ļĀėâėĀ&-ūËY Ëė°íL˛”,ÛÂËâ+K ´ëŧ<,™’Žģ0ŦҚ"{ĸ§đîĘī‘y’ņ¯r*}B¤p1 lÁN‘oqĨt/­âĪJwkŠŧŊËÁl´†LˇÂQË‘ J*´FæÉrBāb~lÂ| OĀPšNo ãŦŌ(’ 7ŦÄđN–đŒČb1­0 ˙¤Š¨ž‘ ˇŗԐŦĢž(#ŖžūÜdįJļŽ)žėÃDU’*ũĢ*D "~đ8 *čåøĻgaæ1‘ŪΊf¯Ûˆ6€mxčCF˛-"Vö-b8Äü¤(Ÿōi¯˛ųr¸üR-˛Rí]`p?p-—ä„FMØiܐÎä`­ÕvRHŨrä.ąHØpEäē§DÜd*E-4an4E šjि-}ä1•(ėPN8\E…ŒD1QĨŲÎäĩ^OéDN…øH~œRņ$K Ū Ī$ŗ$–9§/đ51=ā-H>Iøí…Ä-6lįŪ¯:$odP(„RŖū1K,ĐKŽ~Œ3ŠÉ䨧4—ßSūĻø+Øã(HīRĀëXO÷BfgpãŖ¸ŗfūĮ)).iQؐãÛ’,ôķ´”J^Ę -å”"Š&ä> CĘ9-N™â°Ë o69J<ŸS`~PEm„,,ÔãFōbö郸lKėĒę€(ˆôįC;Tú†tÆĐÉFā> ō6įÄ.Â1üد<—OzÃÜ"+ų€IũÂ%ÂôŌ8Á.}t‚Yļ†2Ä0ĶåˆôÕÔ4ØôÚĀ˜Ëł)5Í0"ņĪĻ*((%!°JëtÅî”R‚ŖļØ+B¨Ē'Ą”ǞŊJGŠā¤ ×J™āũ$ÎŖ’ÅHų+S?ūmSų‹w° ā0AŋlŠ~oÃPëËä#Yąũ ŅUs1GŋËū˜,Ŋ<ŦI1dUH- *Āp()QCČMcŽX›Į/ąm&ā/zŠ,žLŊŽL˛Ļ Pû1`$5ĢĒląBo'šPÁ”Ŧ[°; ō—đRKO/äë8ėk.•&:õX[b€ú´F_Ķf_rūĩ_ķ•_öpô&`–`Ö_–aav`Äi$v4‡b]‚i.ļÔøqR}’Xģd%’[•ÂFÖūōđũ  Q[Ÿ Ÿ˜ ´Ūƒ'?ė&!ždÕ+…5\čĩ^3‰‚4h‡ÖˆūLĒh‘čh}ˆhÁE9qJ0ŖĶŗØíCžČã ¯ėYÕÉz;īđ˲5ĘR„ŋŒģVkkĸkËĪáTŖˇ*˛@ëP^y ú~Ôb0SXŽ^lƒzcGķN,ęŗwÄ3ßnéĀU6fˆäRî~úV;)ķd2õS}"՞Õg4ŽŪU uŠ8ĢQgËĒ­r9DĒn)Üni'„¤Š:vëŠBü(­åX%Pũ1°*Ņ ZÃgkw¯-<[ˆâtS8!ķ˜ uKnOęJ¤+oÜxƖÚDØ=į 52• }Â%'ķo’߈(8UJøĀÂÍOD܂ÍōĨ4(b~ŨžDū6IɊr7¤zw¯č÷#œĮßČdWÖdK†ĸoSÖŸW.˜eyßëūę“F9Œgį5y<ŠĒļm\ú¨ŧV“Ébæaîí…ŦįūæäM&Ŗ6ŽņR4ngfnļiYĻXōWK\åIĪÍŲÎ ŅęīgŪg0â„vŠÎؚ-ŠÎ='uėļrQ ´­žŌüŽ‚ÕvíG)-8yX‰Ũę74†|įÖ^„oÅo'ī-×6V}Ļ÷4j–ė—nUšŒÉd Qœ6đ.ė°NDŖŨõ&bXŲÎcBĘ)éx–`ĸˆ‹fM`äĸHyÛķPDPmĢe !Ãø|ĢÃyĄ…ÕūIywūÖëēsXɌΘ#&öōĈ„l+Ģžütc2,É+3dpCj¯đoÔâtLˆ}#JÛŽ˙¸ˆ‡&LŽU>ØZĀD×VGąD/ĢY†m‘ã…ÅE3ûĨÄ(…=™'ä6™âÃ̤á-ޘb‹Đu)ĩŽÍ (˙,*âC )Eų+9ëÄSbØÄYŦķ‚™D˜..%dZÜoZ“#B[œĨ,Š ›û؊?đõ y„yĨ“gjj$cĨiĸŸ”-z4ØFĸkėĸ#šĸkŦĸ=Ŗ7vŸŊ¸„BŦã ŖZÕŲ/ž‚Ĩ%–ezBe/^ú'‚b;Í]ãc¨rš#ūMú Ą/M–N™ũ„īüOmz[ŠúûYA,;õeŸÖ­‰/pˇŽ—ķ…:-yŒšš%ö‰ėVNüô1`ēŽģ–ÃÃĻŲ5cšŽ/ÜÂŌCUž0hy žŽå—:Ŧ×ßđƒwžĪŦ]CE ąŨC쁄H“™/š1JŦŠŲl\b°É„œ]Ú1`ž\9>öbĻš*)RšžÔų.ļPO锧Ŗqļ)Š—5{ė‚ö„čd¨7^w{ˆD˜ŒE™ˇŊŦAsŦ …ûŽ™˛\đ¯Ųz›ŋ91ØãĔРUq<ÄĐv7¤QIŲ•Ũ™9h[ģĮ{ˆã×ģ%›Éģūļ'{ŊKϞ‹;w@&EŋĨqé-ĩ`žĻåØŧMH,ôöˇ/žüŧû„ü<Ŋ š]8ĨŪž[¸;Ļ‡Æ˜ë™2đYmæKŖL+¤7J ˜—ķeÁąŧ‡›ÁüÄ|ÅÆÉ{¸g|$ŧ¸†ÆMtHō'ŗBRđ:3K•:âžNŽqEA=h<ŧÛÅ]ŧśĘcÜÁ§ŧŊá›ĻʛŠ0îgĖÛKY¨Åč;[bGYīz:S–…9ȕø„i[ļŸ\Ę_\Ŋá|ΝŊ­ÜŰܙ(ŧĘ7¨o_´‘—xeģ—|¯N} ]1eũāRÅ7TĄ6bîĪŠūœÎ)ŨÎŖŧÎ1ŊĄsœXõ|fŌ2Mú0í'ŊE°c÷ŌiĻSX8Ŗ!|ŌåÜŌ5]ÖkŊŌû|Ŋm|Ŧ‘TĶgIĨœ}ú’âļŅĩäC'V™<ÖoŲW=ĶãŧŲaN<ŊšŸ]ÆīüÚĨ×˙˜Ķ%čjØ&pmÆŨpü&oĘŨÅ}ÜŊFÛģ}ÖĄŨŲßŨÚå}ĶŠH׊™Ī…=ÚåØŲÛŨšŨßcb…$jâ;ۗ=Ūm=á÷}Ūo{˛īŨ“ģážŊžŨ°gÜ\X‰@@}ĘŨ]áiáé=ä+|a ūŒ!xáW^äą}Û1Ūäé rƒ]ŲëŊåoŪq~âãŨbūPžn=^ļK~įaŪæžč bãIãį†käA~䅞䟾éÄįU8ęY>įcžčˇŪâ…cā9ûĖėË{ũčĄŪėĨëį=,Ēž^'ŨÉ]Ũãîįūíë^îížîī^īķžīņŪī÷ūīĮŊ4JOķž§Ž˙Žņ_ņŸņëČ"¨]ōĄM—ūGOôŋyL‰ķ;ßķ?ôC˙ķ/ é'ßô˙JA/ûäŽõAOķuČ˙_öökŸöoßög„íOŸ÷AĸôZ˙ú\_õM#q'mĐn¨ų#Gk–_mūÕųŖ_ų§úŠŋų­˙øą?ų̟û¯ŋûŗ˙ûˇßûĮüEēo÷ĪõãNøƒŸũ_ũßū{ŋōŨnũ3?ūī˙ķ˙$Ü_˙ûß˙ĸƒĀ <ˆ0ĄÂ… :|1âC$Zŧˆ1ŖÆ;zü2¤Č‘$Kš<‰2Ĩʕ,[ē| 3ĻĖ™4kÚŧ‰3§Î<{úô;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/BasicDataSource.gif000066400000000000000000000373111447311732500306200ustar00rootroot00000000000000GIF89aę÷˙˙„{{„„„”)”1œ)œ1œ9ÆŊÆÆÆÆ÷˙Æ÷˙Î˙˙˙˙˙˙Æ˙˙Î˙˙Ö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙,ęū%H° Áƒ*\ȰĄÃ‡#JœHąĸŋ3jÜąĀx)˛$ɓ&Sĸ\О%˗.cœ)ŗ&͛6sž,P°„Ÿ@@Jt¨ŅĸH*MĘtŠĶĻPŸJJuĒÕĒX¯j}p §Q _Á†+T먠fĪū,+–-Ų´nҚģŽŨšwÛæ}‹ˇ¯^°< úĘ nÖÃ[#^Ŧ¸1ãĮއH`-]ĩ{ĶōÕü—ķfĪuAˍYķeͤC“f;Y ĪŅqŨŌ•ũYõØŲŸcįî|›7íŨŖm˙>\xm]÷>>tPĐĄūéhuéa…F—^Ö­sėEÅūF[Ũ2Ũ­Û^Pt;ōëšĢëœ­næ˛[Kx}ŋvwč…A^Qå=žĪŊ€dĩ@Y… %Ô žgßZč…FØtįq(ßPJØĄQ*HÔ…X×ėŠ…[gú œ‹fq‡ŨvFáxãx`ˇ ‚8ū8^?Š]€@ž'Ũ’ã ia‘`Šã”;:ųx~ÍhTŒļ5Qî}ĨŨƒ>ö¨¤…)‚‡%”Ø…Č W>øŖ™q:Ųä˜CŲäugY'îéÉ[—gqyĄmŅ9§fF¨‰c–ĩc“ō…ų“uVØgž ~gŠœųäyUÎ *‘ũiY—^šž ūĨâ‰)[‚–h`•ŠV(̜˜é#–zŠ ™ˇöI+¯I f“ˆ Ą3ĻúaĸfzfûĻk‰Ę,V+ęQ86Ē)ZŸ:Ē•Ęv;jĢÍ>ëŧŅNĸTcŨkTŠráá}ąé [„sũK°RĶĒF„žÅ%Ÿ´ŌÆ^dQ! ŲÅgĖXc끊ąPúÔÁ¨ĨæŦh§™ŦrĘĖ5Ŧ2ĄÆšŒrČjlķĮ7įŒsUzáĖę…C™ÎZ%ÖXÆN‰‰VRŠég@(!ā‘ÔM="Q­ĩÕUg5×[w öØ]‡m6ŲT€ĩÚdŖŨöÚg—ÍuÛ-…­ö×rË]ūČ'} žL7¸ŌûmxáAŪwŅ‚Č⃃ŧ7† ą\ų˖Ã,ķ˙e‰yf™— Í1wY\qËzēoĮ­N\–/–Ncĸ_Õü:ŒķĒWžĢKĢēį—ÅŽåėõÆÛēįŧ#ŋę䆈 ņŋ;+|ôĮK¯üõÆS{ö.ę’JjKíQJäŗ}€Ik—T>Õ)Ĩ}žųč—¯>ü$šwü$­?~ũų÷ĪūÕōÛß˙Äöžڏ~_›\ŋ Đ"Î9đŒ 'HAąvĀ‘ë4˜ÁÔypƒė G(B˛„Œ: DŅđϧ=Uõî…Øŗ^ Ģ'Ãf^*šĐtvF4ú°‡ū@¤Š~PąP…ĢIbjB:͝Lt›C™§ˆ—ŸQĮL 0Ņh¨ÃŨ•Å‹īĒ]zčõ0­>kQzîõE§pqAšQPv0X<ŲaƊ"@íŗ0ĨYFNî’cTČ ŅfqdÂĘ)˛ė‹cœXķāØíÔq…ĀKžŧ”–ī4 ‹Ŋ)Š!ôŸ='(öIŠ€ōȑC„d`v^t0ļÔ,ŒÂŅ"Ŋ\hC/áq_zTd*2‰)Iį“ ¤e‹I“JĐŠĸ !KÎQ.ēŧd Ą–_J(˜ĀĖ‘5)ų¤W"RŽŌ)™§ē  í$å´cÉ[])Ļūt‹œøĨ—#šn†Ûœ õųŧ)‘7:%ĶŲ­{š+´’§C) Ĩũ‡R E¤2=ĮTȏ4äeH79ūŧE6ėd(ēÜŲĐxōœoŅâ+!9Y”`ęŧ§Cßķ+ETqĨ GĘÍĸ.“ēŅá7ī4L5ŊÉ\’ĘSĢÄŖr&2Jé¤TšÉĀrEéšKSd/Šg‹^´ōŸ„­ŽhÛ¸ P66˛dA'ŗčH[ u”ZŖ|žtŲō7¨ãāgĢ{Cå¸e=údĪ+KYø­t=iŊ>z›)ėyb5LT)<ŦÚØõļņÕKČž(€ÂāД&Ĩ¤|ÖNžzĻU¯%M`‚ʧūˁvÉC –ēŊdÕOđ€ķ¯=úNTũŲQ&4Oõ„+OÉÉSxv´Ŗīúbņ;QnB,“ –Ąū’ ôŧXŖ:đCģ*ŠoIę¯6Íęx¨œįbZØĻ@°ˆōš^YĻY¤đ=ôč ‹Đ2uÕÆ˛dĮbšQƒĘYËØ<¨NÛN=§?'R$ę|GjM"Z5f ÔËE-p-i,3­”ēúčŊ4\wēT†+KĪØš—Ķ+ĩôD[Ėŧ’¯¤Ũ]Aē[8ō3­Jy#[Rk ]ēŒnnoĸˇ-Ø_Û0ÕŅ1vX˜Iîr›ûÜčNˇēŅ-WokķĖÜà ąÍeėīÎņš†öī{ÄĮHzX¸/XN[b7¸Ü†÷ģM](æ8× ›ã{įŲ¯GŽÚ ë?=Ė/ nāiŠŽÅūGÍp…'œwkŪĄĘg• Žo?ŒšË“"ąe_n‰8âįnä'ō<į&kbpb$ˇ‘]$G‡Ō—ŽôĻ'ũéL‡ēĶŖNõŠ[]&RĪzÕĩnuŽ{}ëUረĮΐäũėhOģÚ9ĸŸĩģũípģÜįN÷ēÛũîxĪģŪ÷Î÷žŊí~ŧā7böÁūđ<âĪøÆ;ūņŧä'OųĘ –Ī|ß1¯ųÎã]ņžŊčGOúŌ›^îH{ęOOųÂKdõ }BdĪúÁ''õĢĪ=t lG ģ~đûá÷Ū÷Å÷}íņŪÜ$÷Ā>ī }å[˙úŌOūõūŋüģsßúÕGūķy?üė_øá˙}ôißũšsŋú´OŋųÁ~øŸüėoŋ÷į|áŖūâW|Á'~ȗú'w w€ hގ€x ø€8XxØ(¸Ũ—€‚"8‚$X‚&Hv x‚—‚*˜y؂0ƒ28ƒ4¨,Xƒwƒ8Øx/¸ƒ9(>Hy“ĄƒA(xA„Ečw%‘„•į¸?ķ…P8…ī#…UH…t…Z˜…YˆāÅũc…`(†aˆ…e¸…g>qŠĨ0Úfdpø†rč†tØXũE‡`‡x¨‡y8‡}h…Į7ųVA„Xˆå!rū-SˆŠ8A…÷ "s84m‘X‰9Ķ2r2ÁĶ9ôXkáĐT $^‡RÃõˆÍ!͕\ ‘Ub*t›ˆ<˜qTށ‡(ÖAŪÕq“čqza0Ž=FĻJ+rEÆUZ6ŠÚ#lĮƒ‰Ũ†dņâLŌ1q åhÄQąØ.ÂU~ËáZÁUp*ԉ&=āŒĪČ`ŧĄ'käW‹ãJY52†ņ0„”SĮH"΅Œ°trŲsÎhdšxjRU'NRgŗ‚-úULÆ.ʂæ'ģb*Uĩ_ü¸pšŽå8X›!.kâ+ąļ(uæ.ˇ#"kÉō(œb'>Ōjō[ĐX‘ĄņūŠh~’+T‚)Ž&k Š(܂BŊ" $Š“×ČQņVr&„TF™bA1?‰&YQÂÂ&ņ(•urD(‰’O‰'‰`ęh‘­q˛Ø•ĒÂ'Ž‚$ŅQ"Ĩ‚#h‰ˇeŪâTúÅ ­v–ōą–¤2Lh6RОč_–(IŪ%&Մæ—į!Wæ5Ũ‘VÁØqæQbĶ5sOņB2:E{Q\Ĩ–īØn –*¸Qp˜D˜$tĒˆˇ=Ē š'UK˜UK˙–îÕ^įšú˛ŠrĖ&¸˜`$Ô`Á†$Į=ff/õHæ^˛AŒĢJÅč†ÍæVûxî3/ˆ‡)™<ūã_K“œÂH›ÜšrŽaa™Ô¨rų•û37p#@îI@v“>[ã…îc5WŗėIu´žpõŠéķ…'ņŸæstx“6ō™Ÿôc7]#kHd‹˜™•¤0–yĘŠAmĄ8ˆš@>÷s„‰ÃÅ\ČW#ę]ŋEpgõœm„_ž(Ff1АäQŠëą/¤I ŽŖFĪŠZ„Ž ĩ‘­r!Ž…^EŽikԋ˙fsOņ/öÖ!EĘ/ú"΃›ŗˆ(29K9ŪȚŊéŽT*¤dj5㘴Č4’¤šÄB1l~qŽkh傍ąuĨ–ŝ˜h°›uq›Š!€‰ĻūÅŗŖ¯ĶGUĘĻĸŨŗ† ŠĐ@`ĶōJʸ-\II÷X˛š§mˆJnEžRdĻĸ{ZŠ[&‚ÚPÔ¨Œ&÷•˛•ꆞÅNŦxĨkĩ…ehus)°5|ôr6Ĩ˛búU`_š ‘Š”jŠPĻ^đ2q0uJĸfhŖÂH§¤\åÉWÁŠŠœ*Y*eũBZ§&§–îŠPĢĶ6cȤgĻ”mp„-O8Ŧã¤"SMŌD& bQ^uŠ ƒ*āŦí¤Lîô!"¤9¯&ĸŽWäDö˜SniJūôRdžvâÄŠ^fU֔SčQūD€´VVÕ¯YĻRÆzŽ@æ‹Ī%9%5‘JQš&˛üZ°>õQ0ő9%˛ßJN'ua)ĩNđ´˛@6žžš˛Â+NģQå.’ŗ"ŠUĀē!5{´[5ŗWb˛`ĻB€Ôą:ukrâOGD-#Ög›ļ`"iâ‹ģRPģS âąØÔR#kŗ$%"cH’j˜^´eÍtU ĶeŽ‚'hY;ā'ã”˛-ĩąé“K3—Ŗ’kŽ&´ĩ1­Q^K—ŗčUĸúč’ŠœČX˜…˜ČĒ!MĘPęk†ļ!Ēĩq$¤Gú_?fģĖÆŖ‹š(Ķ6WÁK¤‰š'æD4Ō]/ūēCãÅkuœŒvHŧ‚ĄqhAf÷Eϰę‰8Œ¨-ĄJZ›úŠ͞|o.ÂV‡Œį5ĨGųމ•$,SžŦÚ€ĢŽÔ ˜›ēKęŧ€)ϟ¸žkå˜ĸôkÚKĪ*Šō:­Ęģ \„ žR;~ÉaЏŊ DhâĒSƒ(^üÔJ)ėŧbęiĘfĒ_6ÂF4¤5 ÂϤeą[4T#Ų]ķ4eÆúÅ!G )ŗ6ĨCK€i!w:ĩ<ÚģF\Ļc!̇‰ÁķJ¯gĨEĒ;ÃÆ8`Õ´„ãZļ„Â*‹b5Žv(Â^‚pÖÔŧcē‘ũeĨ,ŠÜM–ŧšüÞųļ'\WķqÃ%†XTLū"gÄYd–ŌaŧC÷ōŠ”ލ§ŖI:Ŧ đĨ0}lüŧ㛝ƕŲn6Zqlœ_K\Ž{Ô ÜŦYZ<[ZĮQ4Ŧ¸ÛđĢŊÍjĶtÁ˜cZĨ=×3šåēã8šÅKujNKÁœƒ[g|ÆLl˜oE_0Tž ŌíĨēDģƒöŊՉjŽ*)Ņ:Š\,fēYgEmŧƁˆ{•0Ø:äKžĀûØĮĄ}ûģC0GŦ%‡ÅXkąŋq̊äÕ_eQ;ŧ­¸¨mOáeĪS`™4Š™Mf;ËÜæn\ØĶš4^ĖR÷­öčRJēĸ TĸŠÂmeÔk:Žd–ŠĒ Pîūœ•Áad¯´FL–¤¯€ü´>…¯ąqé˛Ē–ĩqy`Ÿ+—LÕcVōgæl/9Ũûa$=’É$gŊfĖt*Īęô¨tšlVFĘ3J˛`ĢÖ¤O !ļ;r´õÁPÕāíGGššû{‹äŌŗĸÆ´Ÿ‚U7‚ļ‰ŦCE`ۑm3›ŪWÖËņˇũúMĮŌRHÛĐˌgM\Q:]ëX|m`<Ίcûe@rĘä\­RÎ*ÎŦ˜ËĘäßÚ—â{›­\ĘíņiČ}ᄛ=ŌŗŠãĪG[2’IÄà ´(žļTUĩ•ĸP{6kÄ„ŅŽVcčŦ&#ļ”'›^…E5 Žū„ɇŅ9‰‘Æ›)´" ÜÂt•Ĩ"Ũ Kƒ›ÉHÂâÉ0AĘĻúŽzüŠ”ŧM1]­å8llá#ŖYržĖĮqhËĨÍ; ’× lĪŽ!žÅȕv}MįģĸĀąĀy é‹cŋx=hBÚĄú<ĮFfŠĒTũÅ2žŅ–ŽÃ.,ĀüÆUŦŠōh×ēQ=Įœ­§r,×V}¨`‘"”Ĩ[‚”ZŧÅ­´Đ§U2íŠxšoĶSļTYė‘ÜŪ¨ŌĸÚWžŖÆí œ\ø6īĸŪOΉpŲĄÃ’ɝtŨ˛ /ąmOŽ§ ‚&qš#IÖKWßmįz‡A†…ŗÕ8ž† ŖÅģmū׿”ëŗZ fåŊ-ÃÁa#Î9ŋú–B„ĘŗEđtÔxãąqĮ֍M…Ë Ņ4ĨĘė-.ŨN7&$ŒkšW%Ž!æÅ:˛¯5ĢbĨjĩÕĀ›!“Ö‚ÉR_Ę˙œĘŨ¸Ŗfģjå[Ĩ$âË(K*ų”_ö–cëÄ&Oū_ŊŊÕÉų"Īzˡv˛Ž ¸+˯IũMBû'i-œĸæ)^ä\F‘×KmŋiMåj&gŖúŦÄŌ2ÛâZéŗn_ĘJëųsŋi ŽāGûĘtĢfĐžSÅļËz)õŗpÅ5ÕŗÁNÄømøv™ąÎ$N]¯)ē—[UsßāZûöãV—¯ūâí4ŅÖ¨uîŨCˇŅP’ĄēEreW}ęģF踸V]Ėļu2]Âdú؋ĒK2:Ķņ>šōíˆxBˆõlˇŖqO˜ô Ļņ  <8° @‚ *d€đ↠&ŒXPĄD āøpaF…& 9ņáƒTJ( 2äK—$E~txR ƒ‹5gzÜé’gÍ}.°čąä@ĸ#{ŨôÄ 4KĘÔh2ŠM)W(¸€cĮ‹ŠÄš3*ԞS•vũX–aÎĻ9ŲŽwæŅŒRīÖ\ķĒČž&ũb]ŠrĨ„!p˜c€n^t[ļíQ‚–*NJ‘'ÜŧūS‰–ėĖ´ĸĈBj&ŦÖįM‹!¯æ”œ÷¤\†ˇJüú52Z tͲ€ycAÉŖuŽmj˛véãË÷ÎôĘņŠËĒ4ĩ+ 9ä׃’Ąvm2ëá–7†,^øZŠŠ ”\{§ûЧCÃ$8ēyN’3o ¨j¨8ú`đ3„ŧŗ,,…Ü“ŦĒ'N7•¸ˆŖÆˆĖĨŪ‹ đâCp1ˆę[¨7đÄĢÍž:1<úJėm$íÛ €&:ĐēŒnė¯D‹“ŖkBPH°āĶI+•ŌCÎČE:€Ņt$ F7АD+‘ŖoKúvä¯6‰ŧJ0ēį6ë/ˇËãÂūНK4]|ĖA4QĖÅϊ@šš d ĮÆētHÂ>I$ŌΙüŽOí\ėF˛CčEõÖDČQLÃėôRđ,U“TąÜsTJ%ŦŗÁ×2´€’š jÃM LƄTŒÅđCđÔKwŒUĖĻ8=ÎĢëfĶkŅVīrĩRhËL2ŧ/ËdŗL0ËėĖPŽÜrLē<ˆÂÁrĩ¸Ģôœ°Ŗ+uŌMj ēAH‹-Ē*š" Õ s5ŅFdIŌ=€ˇ}UG %ā![…ē¤/šĩá^â×'?e튍47Š ŒmĻ G"ÔĩūĖöĒŋLÆ1%Æk­~įĘŠ´ÉjËcĩūX6 gƒ”ËO&øB YĄ¤*ô °“g‘)œgĨŦ(BËË-;㤗9隂#ũæz9ĩ +ų)ƒsĢ˙+ZģĀũÎÆîΧĨ N5žmģ.hˆÂžS;’™ås ÷IbŦ9v;kxžuŅÆ:lN7ËԈķĀĄîU[Íä#ųsŗūrļŽ‚4z ë–ũ’Ū–ãíŗAÊŠj÷ē§Ë7eņË\ƒUÁģu<Đ͘š× ŋ‰ĻzbŸĀsëįÜæūÎ@ŪūĩWø(7Ų'ģAZĪÃ*IĻ;{+}Įķ-´iĪŪujŠĮøŖįĐē9´3ãÉU>Á&Ø†žE9ÆCūúØW6ô¯+Š'yĘ"Uŋ,e‘$‰(U´HŽÆ‚°ūhđ`ú#R}ōÕ"Ú¤KOƒžŊ€c‘ËQ^U2Öžg&4°QÔßč č"dÕæcīÁSĒÄ Ņ]đEĘjô8Õ­'ÖËx0 ^„“¯¤L(PÜXŖ Ā%ZīoEQ–Ĩ¤‰Č•ēÆĸn™ąZo ĸ ØŗŗL¤Š™ŅKÄs­-–+`ōXĨ€Č:@aˆdRTĮž•'m‰*Pŧ—eçLkI@d‹Rž˛ŒË…œV‹C"PĐSķę yų=īQí!YŠĻJiË^ų+3DJ˜Š˜ÄĒŨĒnūŧÛI`gģ7Ų„gJ9MDԔЕņN)/AŠŋ6A LĪŗZ…?ę$tŅ…ŽôžW[0[SĐFÁUn@ũĨĒéûÅãX†KŨēW$ŗYË.¤ŖâJTO аū6 —*Ü ūzKėĨ9śŅā‘ŒØ­„1*], ”XĸÖĒ(€t=āJĻ`9)ŖįKįB Å^o$8eڎņhĄŽš ~šh=מ,­y3ã o ŨÄ?V.Ēú>ÃTū| #ōŅŪt‡×ü'*fC“æHŒÄj°JkSķ,ÖšĄkĶÉĻ^˜šÕø%Zd˙ĨŦC¯ÜåŊÅÔlĄđK9äŧeļ}ÆĪ¨~äb›!COļĪvMĄ@nÁJŅ4ÛĨpŧ˛Œū^%ËņIou‘ÉÄĸųÔTâF5î´WŪx{ĸkĨíĸMÎP;ĪT­­Īžˇ N­"j9ßņ$š Ą`÷b'ŧnųŠÛÁôžâÁÆĒ[Å}Ŋ”gk/ ņ‘W\4R‘üĮúpШøSOʅôŖŠĄŅĩJz8 ũõGƒ•É„*īRĢčTį‹ĄáŸl(5ŌHE]•ũøŗ'Ē6Wíe]b[YAEEqž"ZīēĄN,&+•({\ĖŨŗÜy‘•y3Ą¯æÆz‰氌äĒžWsLņϰļŧĒĘņŽ]Oe˛NbjŲf–ž^õҍ€Ü$Ž“V´ ž[‡ŦŪ˙V‰cC iëûø¯:ūĩXfO<ī; @^ôœbĸ´Í¯nYĒS^2ÅÕ9|,ëįàF1Ē'Ōۚ'‚-Œ`K–ą]k™Hč 4Į¤Ū˜ī9nFNŖųä hĀmk„d­8ôs5?e*Mm_<ŖüsöS“?SŦLįÔ:ģŒĮ­Ņ*ņēgxĶ4ū)3üŖU#ŗØ;Å"+D3ȇ4ŠΊ¸GŗˆÆš4ßj8Ž69ŗ2´Š3ŗč¨Á=ôÂÔŠVk™Ų(Ę›”ęĩސ_ŗ(gĸ—}â5Ä páŽŋŦg ĩ œĀęƒ*­"™vĸû˜"mljcK ŧĩ\#ū ō'ũ‘¨ÍâŠîéß˜ŠúĢ„‘Žüû‰ŧTŠŽ" ,"œŽÁ‰'$ŗ˙ +€ĸ aû+ B*tēã sšˆaÃ*TžŸĒqgĄ‰'ÔĢ´ā,1šJšā#įâ;— žPĄãؕŠųĨÚ R´Qė1ƒ°`ESššDú7éŲĀaŠ?Ž6éŽôBģ˛{:qŖ-Y,C ˛Ķmé‹á{1ęqļÚŧ\ņŽéŌ¤MŠAF2+; ¯<ōō"9ķ˛ģĢŧՃÆ2\FũĸŧäK27Z,Ņ=ŠÜCŽü2-.*Oķ¸RÚ* ,ô¨•3¸­ūƒš…Q<ķĄŖJ¯ŗÚ¤8:Ŋq0žãē IĸÕģ: ķ“( ëĨP‰‘Ö2<áÉ°Ū{%ō(˙›EW”1†d2‡˜kŸëģCUkÂd‰Ž›ģČ(Ü5´{\@Ä ™ˇy œ"(œ ÁH!Œ6až!?1s›ˆ8Ķ) ‘ŖĒlÁȊ˛­jŦ˰ŋ„Ķ´EŠØéš%ô#´¤ "ēž„Aĸ<;Ļä´ŗ¸ÅüĀ\3ŲhB—9ĩÕŒ<:,ĸjDy dS§0ķ:ƒˇ§Ô1ßē4č¸ÅKƒâˇū† 6’ļÍų&ĻA8&ëû“'0cL@œ@íë2t”ˇŪüņ™6܌ÂĀÁ‹rËâAĀĄ\ ^ŠBČ랖 •NĢ>=sN‹ÅÕ ŦM3ļŅsĄqĘEķBķŅÃáCū•īqãd=Ü/Ņ$Ī"œ›|ž,ČũëÁâ5ŠPÎÖü)ē™Å-°Qr— É$°¨Ičő„Eĸē Ĩąŗ’IŧQr ^*3ĐPē—\ ˆÛ:؛°–Ë8ÔKŖĮ™´G.9Õ͈‚0Ą + ƒČ%š-Jø‹%qģHËHšÉú™ÃųB•랖,-´ūŅäsRn ¸Q &Âŗ#úz1‘ÃĶ›ŪÁˆōŌDФŧÛĨ Åņh¯ŋëŌ_>ô?<Këūú.ËēQ0ĨšŒ$`b9ī$8ÄhBÚã—?4ĮŖ–$[‘RÁšų:˙)ÉÕj’ kĀ­U„ŅGEÅą3Ž*ĩI/ēé말s“{ãŸb•ySJãPŒŽąU­ĩîsĘDCžõCĻ{œ(ŅrŗG¤h°I™Ī Ėk|NĐ O›˛ ĀqRJ¤›xЧ‰Á^MĀ–JtļSUK& Kl:¨¸b? č‘;Q[tV+Ģ UƒVÃ1 ŧģB+keĒiË XË´@kJū˛‹˛ŲM˛ˆ‹t‹ÍL8ŪėÁŠųAŸŌœæ\‹Ļų?<ŗM㍂åļ—âšYƒUkŽ[­ˆ9Ô˛äô3>\ÚĢÔĀķ --@\Iūû ÉŋÁÅ!šu¯P{?¸ü4GĨ“›ĩ‰’SÖĢ.ū…GO\=%ÛŖĐ$įJČÍkÉw,$ļɤA˜ĀĖĄŠËûĪíFØúEâZ“ ËŌâō04:Éŗú‹ĘÚ-;ë°< wb*A˛¤ƒRša1;œžJ-Ļ|k=€ÉĸeÆ SŧîĩYTąW;PŨPëPŊ´#ĪY>Ø]Ÿ„2ˆŖŒĢČT;{KØč3˛J Ą&˔ဨËŅĖ0zŗ‰Ō)­œ>ÁÜ´ũá—iEBtS8|ÛĀė_gŊ/ `ĩÄWÁŗÃ$'KĒģ|Ãŗņ6ŧUõ|œmÔWŠ’ÖÂđÖt#0’ `ķ(cАLŨĘAzŗVlĢEÄMŒ1ūļÆ|āŽŦtž|5?õé6YÚĮėų§ eØė*alzJ>“Ÿ)üĀã´ˇđ[b1ũĀ6×ë[ á´ļÁHĻ:Ļ´q2ˆåŠ—ĸŊ¯5Ķ::„0ÍbÂŅ{ FRĻū9+1Ũ3Dž8°‰N~ëÆŨ8OĄmXēš7übHÛl0ĘŲBÖmc)´ÖÜ1Û¸#†ĀH3°ę§yŋĮK “+­ Ąą5™üÚŽ>É\°"YŠč! M—IäÃŨæ“ůšSZ{§¤#Ļúeēģ9iĪ€Ķ,ĸ”ƒ3’ČņS“Ô čyÛ@Ú! ZŖ#G)ZĘD #uC*ļsŒ|a#.ĩ`ėū-;ŧĸ +å:ÔU•1î<‚Œ oŪ•{2­_ëdžZŦ2<ôFAÆQ‰ëĶ7NTŌzą ģ¨āŧ|öäQy(˛gÎûŨĐKīČŲlÆ1CPō+÷ĐāŽPĮ u”ŨzĐzãLŨeá{F‹d %KE[[Ļ1–ŠĨ)[ãĸ”‡ŽŋB‹ß™ZĩszĄh*BŽ k̝SJáœÍÆÔ§oåžčŌĢY6§„X€sĄš°>X30;ÛtÕ wÍ&JLŠ˙Ršļž}ķKCS×wea"ÕÖÂ@CœQŗfZ¸|á˙ē´ÚËėŠw…ÚĻō3F,Úŋ~žō(ܟ¨93L™Ķ€Šū}sZöéW(´byĒ=/MF:„õ[žŸ.ø™'ēØGŽAv’MęŠ4ųËŖ +”J{jϚĒļ^•ŸŊEŲkæßhD‚ðĩ‰T3é>EŽ 'Û+mI<­.ŦæƒÆėŨĢ/ÂĐ­Šú4‰åŠ”˙Íh´ĀBžU_œ4ÍĻŨąfäôjŠ9’ņ`žtĩDųZ˜TPšåŊ‹ŽĢ]>Ž!Ģé.‚=MHōą”\FR-%ŨŠc“…ė[=.§ā"ŅÃĸĘËÆqT““SeĖ_)āÜnXBj&z7€î’ä:Ŋ1Éâ]éÁ’Š iš¯ Ųˇ2=¯˛qy´Ŗ?].Iū[%7Åo…\Tåžō5ÁŨ:ę;‹qCĘ+Ā ŪÖ[ąĶ÷įzT¯°íĘgś3jS^č5qjdÜũJĸhæ‰;@‰땏䤖{Q_ĘPeļ9 ú#V„ņl™˛[œDŠZēs9ÜÉ&jcŦŧmf¯ß:Œ'›ˇTLŌæĀâ2¨’a1l÷‹ãAÍ)D§ūV$Æ#ĩŧ¨ÁŠ`S­aēp×GƒÂ„cž&ėSŋ•]Ÿ4ᨌÉęl‰Y´4ŗōlaFëŗéldžkbŨo珍y–ėÕ˙ŊÚā­äŗ„æštbgîBU%SõŨtåä rį’ ÖÛ$Œúŧ?Õūˇe'?ÛūmĶÔadM\ti0ūã1ŗj”á›ėđßĀ í 'ߙ´ãöē’ĄÍ\/K˙œŦžˆX§šŸ=C:`Øâ´kg{9>/› ä™CAå8i!äeo´Ø°ĖÅH”âĀ–>¸ô„6$Ū2č1ËHōŽŽ~b›ņKØYŖ ĩíĄ/Đļ'Åj@ 2 aГ2QG]Éķ%™:ŒN\Еsås- —I7…]XTãI\/%ĨVØfęiņ’# ÛHf­00q\äUj='ģKŊ1ÂŲ6­ôeŅûå9¸Č:Ē5 y6ŌÚÉȧcÆ]ĶŅę'4yI¤Vō=¯Č(Zi‚žņūį]äLßOjĢHöÖ!‡hÉÛēĢq:ĶųÕH‹Ķäēr=ĄlHĨÕs6tQ?-Ũ,ũčZléļ{鯞PE–IĮî°E9÷…ĨJÔ z_@Qįv”éSeŦč€ÄŲ|!Uiļā5–;VõŨ,°ĨÅļj‡*—ĸŅËĸÅkÆzøsZĂWՀ~íŽōpGŠˆ XP ؐ Ã‚%.œEŠB„˜°á…CbÔhq Ã!.PˆđdD1#Jœi“ãƒvJ(ĐŅäɐ8_fėøķ(N‡72]Y“ Čˆm>(SáTŽ ›ÂhÕéūS­7“’ĨǓᇠ°@-Ų¨A ~5ēU¤J• ŗüH1ėR‘ †í[æm8U(ĘČHĄ–mš“§„-pЙm€nGŌũ™•``šŒ'ŗL ÁmUˆ°Õ}úöh™ .ÖÛxeJGĪ–š:˛ŪąĪî< ˛m[҈ jĖõvÛĻŖņngÚ] €äāáĒ$v-t¸ÅĮĸn—sø×ā9͝TneŖ™÷tīŲshëŲfÜLÖWQiķ­4Ņz¯‡QqgŲ[J!h’PŊ5Û{SÅĄp!‰§‰ĩņįœAly€h?A‡[ זBŗ)8!|鍷ūt˛9ÔVpņmøp=fŨŒlĄ‡ä{ˇ9čnõE9ä‚vÅÕr˜ųÄ[ˇĩؑaJéãkŲ9¸–”š…Ņ]æUč$œVĸYߜÄmUžõYienČø$ŸoNˆfU*ũŲҁŨ[ÖčŲž>ÎŽÖW#„ē)ŖD/Ę7&Œī9¨ām“ĻĮ {ŌwcZĒĢe>ĩØj×-ēŸ–5‘‡ÚA<Ęfj“‚éĢ“);ĻĒn^$鍪âØÛ§Ļ’é š į„ÅfûŅhÁE*áąVf‰iˇAJĸ¯Éę™d˜–^”v9†W-Ģ–I䎭ļģ랰ē[l¨Ē.ûáĒSšūŠ×w‚Ģ`Dü°ŌŽąÄÛUŠũô×i›!†_‰Ū—iYõļ›Q%ũF낃ü›kR ˜˜U8œĩ%V™_L§ÕT˜Éqi(ÔĸCf~…ŨŦ‘IŪĘuSv]|ÜÆ įZZCŪ…tbâõŒØW}š$ĮKÉT‰…^õMŗ–Č´Õæ[Õö5}b§fvWË@ˇlr„íÖÄÖ%rÛ;7= ŲĻÍ5P:FŨá_ƓŖ¯ũšhbû&´l’URwŪŽĻšį´j‹(Pį*4pų REÅŧŦé(áí^*KMyDéąŖŊ ŧĐÂÍöŠįf8.m&˜o;M ūĪt+äBJ”ņL‘ėÕĮˎlŨ#}`‹āæL•ņĖF‰ĩu%ĪfÁ­]ũx¸—|)u~q÷â1‰‰}ĘpŌ(÷|æwŊƒķ`t¯(…J):˜ōę%°PGBüR‹~äŊzA¨IEÂSžFĀV5ohŒŖĐ@ˆõ| !bz Ĩō×:PU§ûÔņ8e¯‘jMÃąˆÂ8SÁ‚ũĒZ Ģ™ŗ~4?ē\'IKûŽx&ĪÄéGdž¨rƒ&Ļ(6Ķ Ũ•Ä‚Hx́ ąĢOv3ß OąNéį ÃsČ$¤“¤K% ÉVņŦåŽõų°WJTס dŸãÉįFVū#]€7%ųhŽŽŽ!V|ŠÕ/bE܂Q b¤)P6a’PE2Y)S’^ ÜĄ+Í05e‡[üråŨØĘi…/ÕŗÛ¯ô´jĐ)w<Û U6Øej:›yõüļ,۝äŽOlŒeb5j2íJ6{YĶp&<šr"ВXä\ãĮ°=#ĒL6Ņįļ*‡~™Ũ2õfÉü.œQ܉OŪ}˛­¨Û˜ÎnæOŗõŗ&VËN¨7´!ĄiĢR?ũYOĖ %¤R:Ínšf:ËlUā†;ū‡¤OlŠÅ´&"~ļSœ5%ȉž9>ĖŽsZQŌNÃˇ•e’áŒūMÉԆą=Ķ„ŠdV$ĒČfaéĻUõgøvLžôc-=›E%×> =°O&éÖŪŌ:™ĨĨ7ādOFmĘQ-ųį3’ÛŲ–Č΂ĸnA ęfĩ<Šŋš(Í)[ĘC}vČ]UŽâ ߆VTž˛îqƒJĸŌZéÁ3yęž´—ŧ…WžR*žkĸĶĨŧÂÕĒ&ĸ+—øĨ”ôŠŠNš*éØ@ ąLB„ĸ@›ʡ7ŦĶ´DĻ7XŊæOŌú YÛXNJņQ5“fŗÂ1‚G W(ÕÉ7irJØėNۚA+[íjtĶÖ(]Ųč#ėĸ¸Ŧ'ŽK9đžČŠū5šB%: ¸‚2_ņVö‚l•đîƒ;23ŋ|F{­ŌjŽXŲ€íã-”Qō”Ŋ5k~%C¯ÎëtĪåĩtŲ rt/”ĶÂZĖËëäˆ‰š°Ą¸ŧ…YĮŠĀĀņAēĀ<ŽnžŖŌîôûdL$ęX“Ļm’oå=ÄbŗëĀŪ—Ár>pĢ|ęÚ#&|Āū"ŋfÎoVQ–2á4’XLÍ=Į­{ĢI+ĸ1ĩ0íV .ÛÚ.×[ˇ×í4ŌB)i¯RzX^6VđliĮe{āD1=ŋLæeØŽ ĮėNÖgž‰zßĐãRģŝ¸ÜNĨ|I›_Ēw4SÅšbBĘך¯Å Tŧöˇŧ ŋų{šį§ék‹ÜąęNÉŠ„<}Wæ—ģ\öĩŊWRĮ‘ÃŒM0Ga'4QäđķŠ#L\Î=îĮĩŨ™yNz¤ƒWÃíŋōËDĩj¤ž‹G`9ŊáŪ Š äqIđė\„ ZuYŽ]1ÜáUS÷9܀Íˈ_ŠŸ•BĨ[BųY•Á_ū)ŪÛÚÁÛzy….ũÚ|@‰Íe)ĐÁĖg mŅĖB|Øž ՒĐÅJ–YßL|xÉvüQ´DͨVü܆ԏ—jĄ—~\žī‘ŦĐËË]‹ģÖLqOÅqƝŅ>å\ĻŲ_å˜ËuÁ‘iyHvY!~ÉQL,FjX‰Å$]žī¨&-ÖŅß{ŲšÅ]뗁‹×Ŋ áĐ ˛ēޤHR&ōąÔՐ‚9>"?M˜uąšžˆJް’˛õĄ1‹QXĩÜО|XZéĘ´|h‘ĸÚáfškøŌF菡`cąa]I¨Å…áX‡ļũÄbÄäí¨Üą=Sû1#äĖŠŅ@z‹ĸ…NŽC¤ÆĸœÛAܚī”~¤īõbYD‰Ŋ”Ë$¨ĨN† @ŨKÍõE͐ULĪÛčŖ˛QÄÕíÔöŲ4]û &˛Ÿn4ãĩDŠüøŅ>cÜŦh-ūH¤1âŒÅåČUŽŠäZÕX\žôViieĀpˆa‘ŊņÖ-r! ŨsÅŊņ  ŧ’ņ".eĸžĨéĄ E!d:]%Ōۚph‚ ƒI‹ŠÄŊ1WydŅ ĘÆ5XŨ^Ļ-ū„ĪI`œ$Īē“ÍE&‘""Ũĩ׊áæ9åXŠŊĐéWĘ=U ūurœĀíŽģéŅrŨM`9WÚĄaÅĐ-VˆsĨ'Ŧ–ķø–wLOˇ( kQ‰-Ÿ!UÅ+ÂpĒā'eŨ°X!ũ†ÅŨ ڐ ņ˒Ė'EDfÕŅÂū•aĐiæoD訏qŸ§͸Čą^ĢūAÜĨũ°1ۋíŪPD]‰† 7jÅĀ–“•ZÔÔhQØ(ŽŪ¨ŽĄ‡ŽFÍ?ÎfiŽŪ č Š‘ú¨ ‘Ä@é“ēč‡ļčWáŒÜĩcŠRŠcZŠaÅ(ZėĨjāŅ=ZšŸŠœŲ%Šš)ŗ"šĻaš:—6‡YāŦžÎÁ˜6éė‰ŠÚ8ļ)é­Äif”KF)ĸŠ‘_ĸZHŖ*jŽjŲŖNjHœHĀĀĨnjĻ"§zę€j @§^jŠb捚ęĨ‚Ǎ†ęĒn*ŠĻ*ǞjĻÖ*§ŽęŠžjĢâęĢēǝō*¨æĒŦÖ*ĢÂęŠję­k§Ģūąö*°Ēj°Ę*¨vŌœÎŸ“^+ļ˛Xj)ļrĢļfk=y+¸fkpĶ@V@Д#QŠ™CN6)“6!…mŲNĩē) .$žšŠ]åhr˜ŠÕSÁŽ\H9ZCĒÆ[‚`Îãš$éE,āgŽáÚü?.ßŨ5Ԑ1ŽP#ČæÕžRČ*ÛÁŨĨ)ôPÆė”ŨĶ ß= Ņ\húYšĸ™lCBŦâQl™4ĀŽÎä+†_]|Ĩ4õłd…ØdciĄųā,–lÛĄŦ(ųėęuŒ~QĨTĸžĀBå!]­;á—ēnRÎ: ÎF›Œâ4€Ī>)Ķä‰~&ãĀZë žūãôe,ŠtÅĶB­ÔšíÉūĢ˙´-ę…žtÉĪēdb‘ŋ%ī8Ў¸ĸnčcHnԒ,ɖ띴-mQĸ˜āZ Å|îĀđËĄ„núĖ"@^ÎY.ßēî8ny`§Ķ=g´´Í 5gl' Ũ‚¤‰ĒčŲ–-˜ōėjøsfčĸĄĻ´æō"&ÅšĘķ’ ×!lø1ÖënoņRmFų`b†Đ yP( ˇՋzôí-bvų­ņV.Dg‘ĩ+Ų†í8F)ņm#;^Ī[Ž”ÂRU÷Œ^ņĘ/ëĄė‘Ŗ~ŲĐ~Ģ īŖÍítĖĐÁ.üp Ĩm‚¸Æ•ÔŌūnĪFl†mōĒe`WŧŸömüŠJBž—*^ŰŨŨ•^š¤ÛrōIŨ [pü–kĪö%‰`pL¯ep•îÄú"ņ^°Ô"0xX-úČ?2Fˇ l  šē)÷Jq„°ĻĄ¤âŦ­āŌå2,ŨQ8Űå’qˇ°ëB` Eĩ´mlí•hØãš/ c0C1ÃũVmæ Ą| ßXJy¸˜Ŋé‹q˙đ%“sÉĐXy×Ũ,hWÂqKΟ 2*G1›ņ7jæ%Ž ßŊņîō ߲ãr QíŧŠRú>îģÜiå­rr.˛é.\*Ļä¤i›0^YŲ=ŗ5S*6_ŗ6ŗÄ= _5/*Ķø”~˛ZYÛÂö%ÍNG8ĪÅ7ŗŗ;;ķnĻķDäQƎĢ=7ą•Ūŗ>ī3?÷ŗ‹Ķríë›ĸŠT6_ŋ 4ž"ôAķĢB74CĒOŦn6#ęųčøm3FOtFotÎš|ë>‹k4rëíųŗ”ōŗ¸ŽkJw+€–ÔĒ­Æô­Ę4MĪ´MgęMįôĢjjM÷tNû4P˙´P5QĩQÛ*`†R/5S7ĩS?5TGĩTO5UWĩU_5VgĩVo5WwĩW5Xou@;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/ConnectionFactory.gif000066400000000000000000000127361447311732500312570ustar00rootroot00000000000000GIF89abą÷”)”1œ)œ1œ9÷˙Æ÷˙Î˙˙˙˙Æ˙˙Î˙˙Ö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙,bąūH° Áƒ*\ȰĄÃ‡#JœHąĸŋ3jÜČąŖĮ CŠI˛¤É“$ @€Ĩ˖0_ƌIsĻ͚8oęŒé˛g˝@s ĩ‰˛¨ŅŖH 8  AͧNŖB*ĩ*ÕĢVŗbŨęTÁĶĻ]đĒĩ,×ŗR $]ËļíHaŋz—îÜģuÉŪĩģW.Ūž~ŋˆ›woáÀ+āļąãĮØ5K­åʕå†Ũ|š3fƐC‹-ĀāÂ}Q'ĖZujֆÉ2ÕÛÕulØˇ÷Ē%Íģ÷Z~ ŋæĢ7wpãÂ˙/~¯c•Ÿž<štģ}kßNxāēq ūpN06ķšŅk‹]—ŠķįMĶ@˜ŠøŽžËŋėlôÔ}÷hÜhāFŪåĨā_î)ŸƒÖA§œTĪqö| 0%•\NE`c=ץ‡ÖEā(ĻQ‚× ؕˆ_UčāyMŅįā\īŨeãŒį™—ŖŠø^…?†Øã^Á¨Ųpʝ¨â“PÄĸqĶÍcX:Ũ…b9ŨŽĘŸ˜\Θd•cÎĮå‹7’a`‹E)įœĨQ^kæĩ™ä‹9ļ$’ô9ä™I‰%™Q I¨ ŠÖ˜į†Túå$”8e‹ÁÉwĨŸd&›‡â˜Ĩ—!†Gfĸšjq0Άڂū^MZéŦž]*`{ÄõɨsX6×aŖī 翌‡öų\Š fhĄc"Iâtwâ%+­ÔŠfk€ˇĘ%_x†ešŸzÉ~ĩ!aÖ~ĐöĩírˇN[íģŲVzw‰÷Wy{Ų‹×–ķę5ۖėŅëÕøJ%đ‡^ŲéU #ŧœģđFœÔĩOš:ŲiüÅ×kquĄk!Āڂ%Ũˇœá+îzyŨ—î_Kė2Jōō•!ģ—{ō_ã-0.Į+7­É(įk„-ŋlô[ØâgŗzNiߒc9MœĶũΌWWëŽn´ĻĮ4{-&PôŅd{ķ^žŌˆ0¸ĩi-–zj›ų´Čyė×qõčæūÍÕõkŲ€›DąSŅŅ÷Éuœ­Ū‘+6kÆĢ„žKĐ펚HgãhŖĶ€ž§ĄĸģŠü^~ŠųVîČl…ĨÛÍŖįžy¤coŽûŠIĶŖ5 ɨ™ļ7ËŪęĀO^|ą?ļ^¨Ž6ŧô“W.]îģgĪPįFę…ēÜŌ/dŽzO8¯Ō¯ú^˛ŸW¸˜ĀûJ{‡oŠ­ũũ ~aŗ>ʏ~ôĀ“›˛0DŦā=zÆû™|ųxį;œÂ‚=üYp Û_Pgŧ#AGÍ:Öėôö#é1poJtJčÁų<VŌē  ĸ?žü'Ywj€ļ$hņ+6ūįÚŲ´­î †qšĄ’ÁąÍ5ŠLšŦ&ÚX dlka¤ˇhąl‰`4H Á,~ífYcÕ´r3 Uåˆ`Ģ ¤ĻHĨ¸T0ŒēãĪNvÂá,\pŠ#Â\Õ´,õå‡ĪęáqT?Ã܏šĢĄļšV/ &Ŧ*Žú–`šōC*Ž67$‘ÁbC5vÁđ‘\ZR€ČD€‰,Y2K˞´ .B\Âō%ģ¤%.c Lš°’–,Ų%/yL[ū’˜ÎTĻfŌʛĀDšŠ ŖdæÆ$:î1‹dį’ÂųÍMq<$ŖĖž‚Ęlm›…äω-7a7Ŋū[ÍņŲ3vĨĻî|YĖ…ŠFžĶ†<\dA̍H…ŽS3:$@*1ÉĐË*ža˜] vI'fÔ,dá(fžu'‘6eĸ…\ļæ*úņSŸ˛˜:qc&Ŋ6žL$`PšŌj `gÎAˆ"DT@ŠRĩĶ]Ō¨Ôę4GžzXO/¸Mī9H¨Å †¤‘zuGOÅÛVô´F5i…§SU‚`u:?´O%×##ë…IqÛ'qTĖí}ڈî‚Ö´RŠEäé”PãI>Émv |žyjŗ%ä…Ioė’ŨD”(OŊeL¤KįRXÃÎ)Aģj ÎÔYBmÕKŦUūŌfŌÄ)? ëQ/<Šh–ĪVmQŽ4­ö+˛<%ĖF…{mˇÂÔ=Ĩ<°Ŗ-‘„ÕžéHOc Ģŧ¨Ļ•V¸PbҰøĢ25-MQ­k›žZ[éÆÖ.Ôí{;/ÅԐ7ŠÖwÁĢ"âHųŪøā÷:f酄ˇ…-KGŧÖĸj˛|ėxÔk—ũōE—JŦ(q˜Žåĸ<‹J)GIœ ]­:KI¨ ‰k´„Ŋđæŧ“/ÄIMh2ͤŠ)š°”՝N,ŋČČ:–q~ęΜ ōM7]ˆ)HŘĶ0ˆÔë› äĀÁS‹SšaMoŠĶ˙€ ÅdNķūĶ÷Ō$wY;õÛ9æąëՔs͝›ĒTᄎtqķ›{C1/U5HlrnB)Īz&ÚŅFĨÎ=“8hŖššÔäå5_ŲL 3&Ÿfæ4—éË^EÔ ļI¨kšędĘD™•Ne2‹’ĸ 3Öf‰@}Æđ:!r ŽĶēJ‚üē ŒŠ5JœDËaģsšČļ5Ž ė^ˇÄŲÚėõ˛1ˆˆQÛ)ŌĩAžÍí]'eZ䡁ܕnfw[ÛꖡŦ”’hŋÛØņVâ¤Ō=m{ßģ4ųÖˇŋK"+~ãÛÜ  wĀŗli{-É>øÂņ~œ-\øÄnņjoüãL´uMūFmpË;Ĩ%7ųQRN'–ĢÜ$.WHĖ#2ķ—“­æ6ĪyŋuÎķg+ŧįžÁyĩ~ôŅŊč?ēĖ‘ÎôzËIéM_wËŖNõ@ŊįW¯ú°ŗŽõJs}é´Ęx×gøõ‹@{ė$:Ú×ÎvĶ–ŊíÂ}ģöÎw‰¨;b—ØŨëîSžû]ŒüæänXÂg[đ‡ģáēø‡4žņËŦ%2%īLĘķ%—ˇ<æ7¯ųÎĨķ“}åC_Maƒäņî¤ņŌėĖz9;tΝGۆû {ƒ ${wę"™G[™Ä_҇§œ×)§‹øŠÕë<=DŠė~Ũš?З¯ŦčA>ôš“Q\×vūœĐ Œģų\hWžŋņŪGŠų=öAåb/ĮÍĒÖģZä|oĶڐ?éÔ¯~9Õ(Žä÷ŽŠgfEVõ_s•áˇN”æ÷ 8æg€ûÄ7˛s2•õ ˜`;Ã5W3uļPįgIöszd7'͇g‘‚NëÃûcIōc\m´GÁ'Eũ”-úGA ˆĮ„j§öy;؃<øy‘įƒBøƒ6ņJ'ō€4{¤6Ęc,Š:(ÄB„@t8ô÷QņuHØPĩ×z|{}cf åz]H†Ŧ7ˇį€~CT=‡Ķ„ã†)>Å#;į@˜‡õu+…}^•UčU˜„Iįˆ€Øū‚ģÖPI¨Īķˆ89iS=ÔAD@r#›e‚úˇ~Š(UÕ/|4~„5œXĀhY0Ņ!|)æ‡}…Ї$‹ėGO–Di¸ˆXGĶYÃÃ@'4‡ŲÅ@-‡îŗ@ŋȉkøãwƒl#|ČH ےCÃ7ęÁ/ ā‡RãFü$ĶQoc›QŠw.GȈā÷*ž,Įĩ,#D:$đC>°ŗ` cËØzŸØ<Ĩz+ÃbÆeŽØCb|täG3čŨ¸š2ŽCƒœąŽģ6<„9ëâ7lļftQødE Ķ&، }2wpĶ(s8bhū!ēĸ1Ą¤g€‘‚ÄQÎh•.˙f@†ÆÆŽŧ(dF ƒŠdYt/×HW¨‘Ŗ…}s‡’Õ- Wā#O:†+ãÄ8[Ķ0Ŧâ: =Ō8Pš2ŲŽEŠ5íWI"d=3Gbø‚tQlø”{ČHNÅ8>Äĸ:—8;†ÄBÎa$Lč@øh‡N‡Ŋu˜0‰ããô8Ļĩ†„j •gôŠU’ũhgčI  3Ev—6ÕT˙Ą¨T})<ô—&$™â3›¯ 9<ĩš,Ş@˜<Îņ@I—i’ų‡T0(eõ‚œá4ĒčOJx€{$hšHVŗ>…I›@Œū“›ØI™T(Äč›'ÔY˙C!üC‡˜H‘^1œķWŽõ¸EP3!’æ`˜U%čaę5/-Š/Vķ} {(iu8˜“ŨĶB<Ō=´ŒØ)>á)!qĶ— Ē6ęķAˇé›ŌEōšžCIƒī\3cHÃ1ōQgõ(&jĸU9G`9:ôc&ŽsR¸‡{š„¤ã>€ŠA˜¨+Røš‘`šE˜Œō ĐŗŖąãA|"aȞ&h$ũ,9J)ô„Š,ø™Ą/ö#ö¸‘%>Z’7#•!vN~…_ĸ‰0å3Ę b¸} ĸˆ_>Пœ¤6Ž˜Ã™„Ä'•ø§ŗ¨+›ūS˜@&ä;Ƹ‰ŧÉz Š ĩ44—Ūä6,ú[`ŠQč„Ļ7Ļö =éHZCŲžûSJjš‰˜uĄāŖxhž”i:†@ģōY•™šąšéĨTŠļ1gäž.ĻEč’FņÔˆeח%Ar[ÛĩËÄi\ûĩbļdëĩeËckļj‹ļgKri;ļ×6•! ejv‚{ˇcÆ Wá5?F8N1ˆ—ģ ĩ†x¸†›QyV%™!ǃË9ķäœļņ{y뜐FS• f%FOęšĩų¸LÖŽ‰‹¸¤;ēcb**č" ‹i9Ņj­–j5ģ—Ļj:ģžfģ¯KMŖ6ģŧĢKq+ ;ŧÄ[ŧÆ{ŧČk ˜ŧ^Æŧ]wŗÎŊŌ;ŊÔ[ŊÖū Š×[t˛ŊīŊÜûŊāžâ;žÖģŊäK‚įkrŪ›ž zŖ÷ž™—K`+ļŽäņģJ“×J­TKņ ŋœ'zũĀ˙ëŋĩ”Ŋ7—ë—”INIščEŪÔĀ<ÁÜCë‹xāŽ§yš•ikŸŪrŠ’›šUF” iæ[xéၑ+Üõ–øĘ0+ĖÂĶēÁIåO)œVĀaRĨ{ZķŦåŽ#ĶÃĻÛÃ,xĄ{ˇļˆ+tkC9ffaĩ8ĨfPLŰq⇙^h‘Ö( ‰§DKdčZ˛õw–eĖ’9ŦĒ:Yj†[ŧ‘œR’4ÂÆ˜=аĘ%<\‚žÁ"ŒąZ‡ø(Ļ%\”fĀø…å#Å2<¤Ģ 9ė•!˙ž}š›ÚÉCkšē|ʍēŦŒÚ<Čã;ĩJĢæ¯ĩŧ\U°”´™6ŌĖxĐųœ/ÜĀģNPÖ~‹1Āg°IKÃhƒ×+z΅I¯ ˜|ɁbYDđĮ“ŊĻHâMüBŅ$ÔATĶNI;Q¤ÄųŊDUEÉp%€Ö6 ŦŽ2#GėĘŪ!)DoŠC0:{ūXüw;œ¸ čÎE’åuގØĀLƒ1NÆ-DÜāúÆßņíO" â¸-SˇęÁšËĻJ‰ãĻlĀDȃ­Ļj¤æĨæļl;L$‡iM.ģŽFy;Xj´{ä7Áž\Ūå;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/Delegating.gif000066400000000000000000001052011447311732500276610ustar00rootroot00000000000000GIF89a­÷˙˙”)”1œ)œ1œ9÷˙Æ÷˙Î÷˙˙˙˙˙˙˙˙Æ˙˙Î˙˙Ö˙˙÷˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙,­ū!H° Áƒ*\ȰĄÃ‡#JœHąĸŋ3jÜČąŖĮ C.L Â’HT)eF– X–´“¤Ė™8sęÜÉŗ§ĪŸ@ƒ J´¨ŅŖoŠŒIs ŌĻŸ•)ŠÕĢXŗjŨĘĩĢׯ`à P`€Ų˛hÉĒMËv­ÛļÚxKíܲĘÖŨ wmÚģ|÷,ØmŪNÅ*^ˏąãĮ#Kf\ A–-cŪ|š3įĪžCsļ| 3čĶĸ5§FÍÚ3fÕĢcˇž-;öe&ëŪÍģˇī߃k:ŗiãĮ‘wVûĩrįÆĄ#‡.ötæËŖ3¯ž]ûķíāĩūįNžŧųķčĶ̧Œā2ƒö´ã×Î\Zūč×öįŋĮ_;ŋ˙ū™!ļŪ€hā&XPeÜ}‡ƒŪ1Ā@}^÷Yi^‡f—aw6vĨ`“‚(ύâŠ,ļ(”ZWuŪÕh`#ĖåČŖuÉY—Ŗ†@θ#‘ŨI÷#šUåâ“PF)å”+2h#ˆX.÷†9ęh™ Äč†ü‘ؐĒ&Ļ–Ũ0d—]ļiÚœuh…Ŗye’– H埀*č ēUÆ'’@ĒÖŪrqN8dhxvf§i˜=ŠáššŲšč}CVĒcšî=¸ew“&j$‘LĒęĒŦļęĒOūVšŠ(–zzĻ—pzɜ_ōęi—ŋâĘëeÃâįk`žŠŖ¯ˇv:lž‰Ōęāx¯VkíĩØfģ`‘FëܖĘöJ맚…{ëšį>jîēË ›™ēžÚú¨­ˇBŖžŪ&G­ļüöëīŋUf§$ĸ ā@ŗÎē‹0ÆĘënÂįîÚ.¯ #ĢŖÄĒåŠn¯Ãrģ'w¯í đČ$—l2o†ūˆīĀB’Ë.ÆõÂ1ģčú8¯¸;îģ€_§§^ôr"ŸlôŅH'TŦ ˛Œ/lĻÛąÆ>JŦĪī ŗÆ w&ŗ×ĮJœpŖz:-Ģf~*­öÚlˇíQĘŦœ™{†ŠōĸŅz)ū›™áY}Đ6PĒā¯á͡´B{W´ÛŒ7îøã$PĀŊūíw…iŪZj‚zÜšƒ›įĒÅW_ڐ§Žúę%3hø‡É•*ŨëYÖî­Ę°įûĶĪnģˆ æ$ëÄo| hfĻ|Ąj 8€ĸ ũôŅĪGŊm¨¯ũöÜŗøqŧg ōîĀÛ|–Ŋ>~…ë‹:ârę(!nŨ×o˙ũÂ]úõdÂ7iõĖ“ĐūxŊ†@‚[ūČĀBF/z1ŒZƒ—ŗ¨…,s!K2ø— z°ƒá#—ŽĐ„lÉ72ž 1%F‰Ĩ@Îi’oēķ“eA°I‘:>€íūŠ= °FCÂķŸÅVZč"ˇ\0.H1(ĮІ:”‹ÃDJDJҊĘ&ę\JJü4QŸ’Ŗ ŠH­ÅLÜDŽ$éhINz”ŽôĨ0u‘KPR†ķ”GšibbĘĶžĻˆžĒ>}JÔĸŽH¨ŧü RĘÔĻîfŠTĒS§JÕō@U™^šjUˇĘÕŦhÕ"_ŨIXģJÖ˛eŦA+NÔjÖļē–?akIäúÖēÚŦq•ę]÷ĘWžĐÕ!I`ûJØÂ^3¯Y5Ŧb‹Õž Ö#eŦdÉŲ„T6Š“ÍŦfr؃t6Ē› mh?;OŊŠö´’%-'M‹ÚÖVĩūmEdëÚUąļĘčZĩRČ+ĒTiˇÅíjAâ‚ÅEîq“ËÜå:WšĐmntŸ+ŨęR÷ēĶÍŽuĩ‹ŨízˇģāåŽxŋ;Ūđ’÷ŧÄEėVH2ĐōēŊī5¯|ãK_øŽˇąÅ¯~ ڀŌļ¨ Õ/pøĢ‘˙&1š5°€‹B`ŧŽw{ îi„lU¯4XiŽi†)ėQtÎdÚđÚ@,RyrØZ$fˆˆO–âļøÄēyņũdLQÃ26î^Žēã3ĻĮÚō?…ėã°šxGvg’‹Ü•%¯ÎÉŨ„2“ŊęP)GĶĘSļ –ˇåbv9Ë}Ŧ˛€ŋ f`ŠYŋd.sūPŌĖ66ĢŌÍjvė™ņ į8‹uθ­ŗ‰įÚęyĪîŗk˙ č‚ ēĩ„.´`ÚD+˛č9 \a&Æ&“NČĨ˛b-ųŅr´Ĩ’LR*ĻNHĒ+ŒfPSÉŅ“Î´ŦsD.ANĄuŽukSķÚÖˇöõ­y#jFÛՍNŦ"ë\;ģÖiö°§Míg ›Úˎņ§‘ĨDg{ÚŌ6ŗkÍkk{×áÆĩŗWãmsûI°ˇšĄíy§ÛŪį6åˇ'sė\žJũ–7¸uŊktĪ[Üž&ø¯ŲũTw˙›EwŠ5 ōçœQ%•ņNųmÉ@ ČūGōVšü—('šČKî[–Ģüä/OšËgžōšÃ<Ÿ]ŸÅi~s›ËÜį1:Ë)t ķüį=Oú/{+ŒÜčPWzŅĨƨ#ũęSĮē"IĻĒ@%&֍ĮqîT‚ėK§]E’{Üė„‚ģbŠŊv‡:]î[ų˛LęnĮƐ2•xĪ;y&>U§÷&í]áûUnĸøH6'§Rä›9`Suė–LۛžņČ0ŨČ'ŋĘį˙øŽÔ2†Īyč#szÅLžÁĨ*WR˙/ž…-¸÷‹îŅ’{Ūī^ƒŋKđÛ—Ūß÷Č?žō…Ÿ|æ/ßøÎūpŸIöĻ.˙ųÃĪ~ķĄūĪ}í.Ũßž÷Ĩ?ūđŸĨ,O%ŋø×}öĢûĘ/ŋüŨoūÐĖ:”Įö¯˙ūĢė˙s$e#€ü€x€°ą/¯×M÷$X€čČ#ԃ€hxÜÂO„Įė%8ˆ8‚"h!$%č-ü42Éķ4fÃ!›Á!H&cō9@:t"':89ˆtC2H×A9šņÂ÷Ō-zR˛€ß>gŖ!ŖŌ™CaDh7r"x‚†ķ7œq)=H…4’„Ĩą&`87ŋŖ„hŖ0qjWt'e¨75¨…>ø-č#=ib'I˜†<‚a$8(ˆs˜'ƒūL34įÃÉa„ĐR…€Øˇ!#_ r@ŽŽxüᅕø‰WxhĄ‚x†;ˆƒé-Kâ?áņ7”˛9́>ßa/(=†"~ŗ˜‚8W˛d6ŅD-h„­˜)2h6hčCˆ€¤Ķ4ŗÃ2b‹‡c9ŗŒ˜ˆ@Ą?ų‚*W؍Ÿ8#ÉH#Ō80ļ8„ŽF’Œ´ã‰ĨŽˆXVÉŖŠŒøĄR´ą?߸‹øČ7$#VH‰é‚)@šŽlx*iւ}€Ÿáˆēxy8Ĩ(‹”¸9ņH‰‰ŒŌ‰!h‘Ą?ąˆrs‹7r@s'•(&ũŖŽûū*™¨%Ŗ¨<ąhģ(‘é’ų" ´g}Q肴h9y5)ɏĸ)iŒėx#S;5éĨb'u2$~s’Ļą‚b!J†R”I;`rŒŽ¨c2‘é;Ą•iB7É&B’°ÂgŖ1Ŧ5X„3ƒ5 Ų,zËeY‹PŖ0<9@iv™:PxČ5Zb'–,Ų2Ŋĸ–ŗČ(ņō‹â€~鑴X„0c6M“¨xĸԂ“x5Yâ&sšũ(„a/Б•ŸÁ5Ōc•Ëą&ļy…q|X™ؘ:roؘˇ­Ŗæa`4S5÷=eĄ(΁&ŗŽ›z+¸ÚĄ˜ÚŦEšŠˇęĸLjŽÁZšĀ9ŽĢ ’ČąĢ9œ×ZŠ 6į‚>͊1‚*1z§ŋé3Ķ*5p*ū­ēâąv ¯'J”Ņ1Bõ5_ö…ŗ:{ŗ<›ŗ=k^äŗBKǚ94œ!30˛Äŗ)+Ģ [§ę%Ō)‹ÎZ°zĸ[™ũÉ#Ot¨×äĩh[dFf[`;ļcļ’ãĩjAļÔŌļc~d… ‹§GëĒFXĩH‹ĒoĘŽæĸ9ĸ3VĢŽ.Ŗa)ĸą8ŅĢJČ!’ɤV#Ŧ ›Žm*ŽZķŽS.š¤–Ģ_Ɵ8z#š1B\UƒŽĘIĸŽižĢĸ`2¤áŽąĘĒĢ{Š`3ŦˇëĄ' ™Zk÷xc›¨>ø¸šBģ^z,>ÚŽîą${+˛KŦšÛ%°i1 ūëēI6ލ¸3ÁąCy‰A("Y‰3+> ¸M:ž˜(#IH›D˜˜ØžZŠ~”š]ä„ a(?Hŗ<2Ĩí™ J‘@› Ų0į[„ŲŲ›•8+ ēĩzÁxû g”q_[Ņq‰žáŠ“i$ÍŠāģÁq*¯$ŸH"žĒ;’Š—kZ'ĸxžŸ(ģĨĶ‘ Yĸé;ŨúŋJŠ;ÔáŋžjíA}[UŒqŗ!4bŸY9p";Ú>-J“MŲ7ĘI+K<"[Û-˜aŋ‘cHœ†x§R*—¸ŗ<“R‘Ã"&ŸŲˆų,eŖ–Ö(G˛7jėŋm82ŪÛ­ˇI5L;đk‚ūĩˆ– ‘OŲĀrŠ …<Ž šÃ¯‘6å Pėĩ)Yœ)|—”øŒļq ģHĀAčĮÚ9ƒĨĶ‹ĄĸÆĄIŗ"lDŒrĻ´w­”zĄ4j÷ēzˇõĘ"7 y Ķšž„Ã‡Ķ“Q €æHņ8ž…ã4SŲ'-|ž/ÜÃ˙ķ1ÔX‘‡Üž,S&ƒI…Dōųx™5"‹žK\ėEūzœ´šÃ7,Įŋ؛ÉČĀŦH'Á\ĘĩB‘$&͌ĊōIė iūôřGi–‡Fŧ9Ëh9šl˜ßRĖ›)ÅÔĮéŒËŲ1†÷1Īüø?9xŦĻ/¨ƒ\ÍĸˆÂ/ÄėËüøŠ\Ęj‰ŊėūNÚ„ÕˇHû&VŠz(T™í;Íl!'}Ė9ŠË‘ûãŠŌ3ÚČ,rüŧ¯;§i-ũKŦlŦ‰‹’‚—fŧËĶÉÍj2‹’øĮžœ$‹ōŅė”t‰Ėķ=U]@—q†>ļ@ĶcÖŦኞéÖd”˜”+#lâfpzmYjúĀæƒ€y Ŧđs'{Õzˆ„<žcŠÂķkƊ#Ör­™,)1œ-×­Ą‘œã‹ ĀŊsE|?Û;+´Ĩ ´Âĸ-´^ÛqëFq8ˇjŌ6ÛĪÆYŸę×ö¸™ļ‚#sē’Žč<ė‹lrÆĐ2–ÍƒÛŖ{’ ŠļwÚ7Ģ{ÎmÚ=ūļ#ķČ aœ­7JaŨ7d× !Ûø&pļԋĶĸhÜ\šŽ¯;1ØKŊ]#šTišAœÜ¨Šø‹ßlÜ(ą\`‡e)ÅR ­-(ņŌ–ŪGÛ|ÍČåŨąĶÁēZ‹3ĄĢŦnJ/H™ÛGėØėûYŪÔᇕß_7H ĩ˜×HUą­x­pá=ŪŪ͉ķ‡ėęŖ°û2FĒģvģĀ ŪØM#â5Á ÆØ/AyúßčņCĨ+ ŽD ƛVÔķT“;ŽájÚĄ¨õb­™*5ĄQ1֊áNÎÎáãDÔĪ@qß?ĄæOŌučTCųäæíį%Nsūæx~įz.įū|į~į€žį}č{žĘĢ ”û2č‚ūį[ˇÔŽ$" KųĀ“œ“+*˜f:Ŧ8žˇMü5bž~Ûō<ÁĄč…NčĻžęövŒ~ꋎ꭮ę°NįM%|4 å4āƒÁCŽÔh>OĘ ã+,ÅG(ĮđĖ’ī Ŧ ęËŲĄNæHbæ?îsDOEÁ¤Ęŧáæ$Á äZ'ņ•OI@l}îĸņŒæŪؚ==9˜*Ųâtŧ~2‰4ĩÎD5 ĐĩĨÄAĐîŗ;áđlˆË<đš<åcđû3l^ ünŖ+ÁģĄŊÄíŖ%Íížîĸ“ņ¯ņÖlŅØōäL•=wūÎdņ™Õ€čųī\7Pü>>(Ä-Ī;åSķ0_7 `"÷ūpŨrĐÔÁÁM¨Õv$ŨņF¯ÖkėņJ=—Á•ØÎLÅL,ÍjĨåg$ÔBt‘B.”õ\_B„ĄõÁ§Bbß`ö0ÔõXīõtB?ī/Ų=R"“FÁQKž%` ?Et÷8ąķ âqÔūN€qAwaōŅÕÚ§|īT4`Į/ŠÜëEÎH‰˙`‹•FĪķ%“÷’ˆáŦ÷ EGļäųPĸ¯šåčįQ¯ę!úđÄor“ŋ=Ēú-g —i‹UIŠ¤äą ģOųØ= oXō”Ɲûķ~4ßn˜?_ËÄū”ü˙TōĨŋ_ĻīVŊDˍTqG …AŪßũā˙ũâfaē2ūčūęŸūėŸĘŊīMÎôūīũŠuüēBIōqSf˙Ä @H0p ‚dØĐáCˆ%N¤XŅâEŒ5nä8€ãG!EŽ´(äI”)UŽdŲŌ%I/eΤYĶæM†2|```Á…8…%Jr§ÎĸI•:ŒšÔéS¨Qm6•ZÕęÕĸ hĀUĢIŦaÅŽ¤:Ö,H°gÕŽe+ŗl[¸qå2Ü9×îŲēwįžÕÛ×/[žf™°i^‰…UÜ6mcȑo–\ŲōCž_挑qį°ū”A&QtiÔ}ÁæũœÚ5Ķ×NĮĻŨųtmÜboįN]p7o˛Ā…Cū=Ü8ŅâĮ-/LŽ­sčv›G§Žrzuśą‹ŧžŨûäīá_v_>ölķéq’Wß~ {÷jĩĮ¯ŸūũúøõO´ŋ˙jųüËI@š+°Āū|*ÁōT>.B ‡BĪŽ úŦ.éōĐ Aüđ§9L+DET1E ŅÅalEk ņh 2 _¤ņGƒŒČ!…l‚ĀˆœŅH™T˛É"3hĮÆŌŅĄ'ŗtrË" Ë%ģ sL(Yėņž%,蠇Ōėĩ˛Ō$ŒĘ6CūJ(6ã’ŗNŗŦTČ, áōsJ>ŗríJ΀úŗÆģ Gé,oΏ5kÍŪ ’4;FQsT­ 9ŗT°< ÅęĶĨ6uęLTņZôHSkŠéÍËT…lGJĪjĩ&H Eķ=_ íPa—ƒ•´Rƒ}5×ŋzũëËŋ˜õ.Ų¸žâj̰ĩ[mŗŊļ[pŋ—Ûq¯5—\tˇU×ÛtŲ]7Üvá}ˇ\wëEWĶDĸW^{÷õ7ŪįxāŽļ:—_„î—ā…v8[ îĒŗ´Š˜…fXã‡ų•¸ÛŽ3y〯Å//iĮꊖ`šå—pųå™aĻ9æšeÆyį›{n™ūsšg›‹ÖŲįŖéĨ•&:館õŦœfúéĻĄÎzkŦģž:曚ūÚj˛ĩöēląmf!Q  ŗÍ[n´ãN;mēķÆ{o°]ö ŅXÕ o¤~ų€¨8 g–G<æĮsFŧfĘož<éĮÁÎüčÍgžr+ŋÅŸ6ütŅŠ•lpĶQÛõÃašįĖk.}t—s˙šrr‡ģņ×§}ø×/ŸŊgŌŗ†ēđåa›åîFÉŲņgŧöØwūüp—áö\xšđtáŋīysoŋåŪ^öōmžxŨe¯?xÆOŸ:SÅXg<­rØĢ_÷ā4ŗEîgū2c@íÆ§ģÚQN|”_ņx´õīu˙Û ū ÷šĒ.€}ë uæžŪ/fãSÛķ`†ŊÆŲŽ}/ _øˆB—Ą|ëÃ7ˇåĐkR˙XžßIp‡´ž ¨ģēpf@Ķ čâĮ26€tĄģbM˜¸ÖQnŽãzĀČöēĮ=Ömoš¨ÉŲ‡„?<‹{pã#ūhRÎv~wŦđÆÃ7Ķ<×ĩôKønķŊhvŋ•0‡ÉōŊŸQĄ‘ŋŸ#ĢiBēąsŗ¤čE‡Ībvf“× !Ã˙å)R§Š}å ŧ´ôķ™õKĻöĢĻ÷Û0Öë¤ŲyŊÜËŊŪ{ē´:Ü{ĀØ‹ē „@ØĢYš§Ķ-SŌ›Hš¨ėA*ŧĘ"sō*|Ú&šz™MĒ™vē*4úŽ! Ŋ‹Ō?LâBE|-/ĸģ7Ē"’D* ūÛŖ;ĄNĖŖ¨AŨ¸A'ü@œĄĪņÁëÉB.’ÅåY?œ9ÅŖjÂOäŖB$ &DBPdĒ&bÆô‰ÅJ+ąŌÃtԜ“ūbGxrGD-ŦŌŽĨŸąŨڔw[Hč.?4ĮtĸŦ(´%ė"!dŦFŽ‚")ž@lŸāB˛QD+ŠG˙:DđÃÁ×ęjt€?dATôŋ­ŠĒ=ōĀĖČē1ȝÉFš°?—,Č:ât(] ElŋeÔφâIôI` qŗ‰ē`Hž†8žjFĻ´B§é™ėše´GĨAG¨?ėB%”25Ŗl! ÔFˆKĨ`ƒ)‰ņ ވtņK‹—sņŠnÉˏņ–Lŧ Lo1~qĖkQLlŅË¯Ø ÃtČ\LÄÔÉČĖÄ´ŋäLméŠŧ$*šĘū‘’¸0ÂŊŦ—Ž0—ĖTĖŊtĖģüŋ͏ ÍÚü—ÎÜMÆ|M͜یMĄĖĖÜ °ĖąĖpáMčôéäKoÁJŊ°Ë‚1Ė׌ÍĐdįŦĀTŽhΞÜKvņÎāüŠÎœN͌Nö\—īLLŊ„L‹ŠĪoN÷TĐÜˉĄrŒpĸ,É™œ›ũÃĮ]šCņ;HkĖħtPÍ)¤đ=4„ēŠģēßĶ#$ĻĻĖ)ŠJ-ôĄuÆ|āLZK^ZŅFeĐ•”‰•Ã:ĻõŽs§ęŠŅ R|äĨįJŅ!­¤—ĄËÚāF•1ZŌSdūA´šäHœŲG*mžcûĸíÄ IŠŖ­ĻhC^ĖP u ĩĖĨĖÉ/âI?ējŅ*Ŗ=ėĀ‘RËĸS?Ĩ­)Ä*[Ą„uD,.Ũ ‘$”Ē-ŗDMÔŲųR@ÅĶĖjQ„t39DÂD;TĘzÉi‚Ķ#ü3íĶrŠ56—ņˆ…@SŪÛP Œ@ĩ­rtÆ%Õ~ōĻ}T_ ™Š›{LÕ\}"­Ō'€"jš4ȲLPQíIŸüŗ-4PAŨŠĘaRܸQ‘¨š‹dŅ â?öUoÄÂ["ĮqMWHšŦŠ*ĘĻČU×YĸŠ1Ô=5ŊW˛Ö}ū%W ’ÅDWXyí#ã)ØLBŅŧ"X†•׆…ĸ ĩŒđĸSĸ"‹tØkJ‚zXŒ}ØęšĄIí׎…nÍNÃHŒ >…{É*H@\!äQųbŋ¤Š*ŠM×éģ^Œí[ƒâØšb&íÛ?Ô_û%_đ)Y–¨˜Ú]^ë˛^Ž}ŪÂŦõYY÷‘>žā×âßúå_d܆™ˆŨ.}5FĨRŲÍ3ë˛ÂųŅ´įIZJŌĢ\ÖXža×Ņå´ UL¤!ūĄĖų´?õYBŧE`ü^¸5Ē•‚<´ž€ģ"Íū"õž•ÄøŠSÅmĻHÍZ¸ŨŌķ“Ö،ÍĐʆ •†c cFãšÜĮ b„3¨ŽĶŽáŲU)ˆŌÛj + bt,Đ!T­ĮIÚč…cüŸ–Ŧ9Šm]ÔpR]yQŧ=,ä‚),zĒŋ‹ãL{¯ēę7ķ_5˛^įSā÷´7eųĘ%>Ļ+.ļųƒ“iŒägÔ㠃>ŗ[ĢykŠ K`öš­Qö7˜Ķã§2ލ4]ií]lũ˛‘ÆĐ4ãÔ|\‰æeiˆ‰mAX~`J.ģŊēdÖÚeMnbY ¸m†1›eÆŊžö4Z&1ī=éúš2‚i:¸Å)8öäį-ģ¸ķgYį8~ę˛3ŧnĮžņ ã &Gļ Žd­,›1&iavgļž7‡æ"Ž&/—V§y‹šch¸ÆëØIe›-äŠü טGäáōRĒĢϝšĻc‰žęiúëoϝŊfëŧŽëNéĢŪ¯īũR”Ęūø šdIĘ-–ŦÄĒ0`ŋĨį{ë8ŽëÍVéč38^†,—ž0úrm-ĄÁįúcI҉DÅ =ų%äæ^čßVčžiŋŽíJæė”Ökhįfh¤šČ!ēVĘNŗ#Ę^čīÅjĖîj˙=Ŧ~†hĮoļ&dî†oÍÆŨēl'¤Åc%Ä Ž…$ęe&jNˇĸ-pĀųĪšäŌÉA*ĄšëÎ}nĻ~oûFa7íč°ŅãÜŪlÆ^\ųŽî„žīΞj".i›ÉhŌjä-ÖŗĩãRfˇŪˇ{ŗ.93*‡ĻīgąŊ€ĶšRÖņųî:f 1]Tqą@ūėĸ‰ā†˛ŪLënöžåģũ´+gJ>r;4^Îá€VģÕãė_ío›î¸1 Ä8^ē`͝žDIs7pĻ’­@Ÿ$_vl7>÷ķBÖ^\ž/hŌrČúĒ-7ģNĻ3ģbôCWčŋŨ&%odän(ŪɚÃ}ÄËĄÔ9~FPmáúqġ<Ĩ7ÄŽŦ~¤ŋŊ?ãÆQ*e#.t(„DO–Đ b+:Rø#Ņã™d×Q\ËķÂ2Gš:l1j­0ębc'vhá d‹‚yvÃv$Iv$Yöj‡vjŋCvĸ’l*ĪuP+%uČņiT-áÂĢnšV2# ĶŊÆp,ØūMšI ‰k÷˙yĶrlÆá˛¤Wŧœ%ÖŖ?Fš?F‚ĸ#>ŊČm"ĩ+øžē÷̍é”6HĨ~îˆ!Y>.D\‡–ĸ‘$ÎUdNhŠļâTÜŊ¨ Œ4bĨså¸%žöAVĀ…y:ĻĄV”-ĩĐptņtœĄąiX‚4JY%œ‘Nš UwúIa—iŪ~lqĮ”ĄH5”čC Eôæ’qÎHåŖsZy%„uRĨåĨJ• 'Z Ј’§ĐĸA5 Šqļë‚ŅZ+ŗ¯-Û,XˇúP^ ęАwgĸčbN¸wŦÎø(ąŽēZlĨĐęø˜ĩPuĢ+hƉ׈ĮÕ īˇûž+§ĒČž:éūõŦēŽu9žŠJd­ŊØ.™oSķhZ¸ÆŽģq˛oegÂ!ƒ“Ĩ"Į莿Au€@ŠÎĩ$§-ώ˛¨Ūv€ŋ[øEũļ%.ĨĢF9+ ĀįGîļ–€Ōdš+áŅ8}ôGL=5ÔîNŊtĶI RÔ[WŨuģ_'mĀpĩ3A`⯊ÉÎŊÅ[ÛŧÂuągĮžúЋ)s%tÁÂ&3æ%ß…§ˇËŲ@\ä dāĖAá|q>īÍ^Ū—Oå7Ŧ•Ŧ8ę"õ™:~–HŸ'Š­˜ÛûPŨôuVęfí\šÁsløA@Ā.ë¯Á4€hŽ•ˇBū‚g;Šڎ^yãv“CĀ—.Ÿ÷GwÃåūKēëE%žüL€–ĘŲÄ aVŊļáQü%“›UĻûëįņ%šx ’ˇīŒ5ė; ęh›øčg<>áđ$Ō\Ž-‚ëËį¸'ŧ q0`Ž“Îę€<Ų/$}áHú$B–Ā…',Kkœ‡ģŗ¨,}ŧķ]ījŊ‡9Ę\Cƒˆfž#)îcDS`X§ÁāÜ$0ƒQE@Њē/ÚR—ŌR/؛z%ŠÜWúėŲˇ—fËüëRÁŗ´œrŗĻā,¤aMâMÂjķ1Ō¤)M āÔ3Áu’^-VxVņ\˛qaM'úäęÜÁMXššÆčHŸ€ĒՐŧ{Ģž"WxOžŨ›'Üįid;VÔČICú8}ēSĸW\‹â€ē‰ Şk‘ŅXAĀ]ĄŖō“6,´´ęx Z霏¯Ø8üņ°É0ŽČ]ŋl‘βeÁÕÕËx–7G ˜FÄí2uÄØZi!dšÚá+ũhg/ēÆ+ļ’sđ]ĒĸŲ•5s–ĶN1zãāâĪ+yWO€D¤$ÉĪ8&ĶõļÕ-PÍ’ņ#ĩwō…$ iv‚ÖĒ˙ËĢÁq$t .¤ū li‘$-I)ҧM1ĻPnzöôąYļ-P*_6ÔąĶäjɗ@’ÆņAîŧë y˜ĪĘ­k‘ˆMė†É („žëîD$E`ŅkWĮ4ŗ;‰ëJjÛŌīęÎrĨČ!Oß b-rJˆ4hāŌoHŸņ÷üŒã˛tĶĢÂ< blũãU~b{4\Ūļk{œīŨ•ģÉ"ēaÂ91B{ümĶ—oÕmíΊnÆü]UŊ1ްxEĪš´(S]ĻRWīP…ž.ėŽŒ/Ų(ĶE–ŠoË'īīÂčâ2 ĪC&vGŒÕÛJøĒSMô"å.ÕKšúÖSí”D-ēį'::snÃ}ŋ¸Ĩ˙k÷ūŒķRĒÜŲBīŽãą”Sl^fÖ;ÁwãōIÖëŦn/HܟîŦnk°Øŋb’ą4Qá…¯ĢĖ2ŦíÕųđŪ­´âk’¸Íã _¸Ūã–ŋĢÛ܇ČÃąžš^qĨÍ4äëCĢå†$žĒJ´Y2˙ëīéņ°ę S}ŋīļpûÜøMvãøTãĀ"+æĄ¯Žy;ęí=Ú÷ķ:š­ri—‰Pĸ>ž236°Đž#Ö×qÔ\ÃûųÖYXŅ“ kĸƒ6Üĸö¸ĄŪÖÍÚä‰Îņ–ZdNŧŨZĶ‘ĖmŨĪūaKŪ%‰ļ¤JÍ´ž´AÛĄtļ`pa E<ŅæQ|ūŧßõ‰…Í}’ˇ%Ķ"ĩÅÎ8U†ŅZC)”„­ØnüŲjĐ‘­ßŌ1A  ã)ˆÛ¨”’8N•ŲnHЏ-áoíāH_”é֓Ą__‰T+uŒ˜AôžöíĐea׊…ũ0á}Ö &Fč8ˆ=õ˚ĖîQœz•Ļ šÄGŽ”ŨƒĩÅË •}ČvE…ú ØËÍAĄaÚí‰`ž ‚‡ZÜÅ8Āč•\ØÖWĐeÕÁ‘˜Ü„OäĖÄ]› :ŨļíĄˇĮąmHßČWSí: •嘒 f•aeü 9bÆDÜ!ë@ râ"3ŽËč0UūûIÕį5â0ļ ‘MĀ9Y)ŊN'_АVn™8Ū f­ 3>#Cąˆ4Új}†1ŽŅ0p‰=ÖcĨâQŠ#:ZTÎvX5ÂÆŊ#ęX•Ĩ#¤ĸ31bí^VäXŪ æhRŠ"áą! ’ŌD-Ą1€&.ī°Mg)¤įĄ*B@bœ—äã9ļ¤Kž¤EŒ"LÎ$MÖ¤Mj„0äM•ÅFš"ŽcCFã¤å2fÔ0ĘĐÁŗa–†`ŠL–å0ÉIÉSaņiRļ$d?2äVâŊ‹=™•áãXūS(–%BŠ%YŽ%?zÆb°—N~E ĩ×âWū$^ūĨIęeå¤ZŨ[æ%:åØ^›¸šwČõ˜gĐY]¸Ü"náEÕ-)%UđdĻ3>E֑fRĘg>$!M\–&J c;æĨCîåjĒæđø%UE]ŠøXHų8‚•žČ‘ãæĩcR;Ū%é ÎW Ú ŌDÍrē‹r2'ķ@gsFÍs.guR'tĸMÔÍt^įt:§tFgw†įx–gv’įy~'sšĻkDĶ#fYjōĨ|ļæ|VRļUãJ>ĖÆ ›nKĀÍá˙õRĄõ爺Y`á=aœí%0Ō'аâļ!% l˛§…¤â &˛ĻPŌ§‡âDâaÔūÍŲrĄ]ë_§šĖša đšŪĩ| NĐ͊X"ƒŲedŌád’†Zčâ¤×Ķ-Ę%HT(ˆÁį†ē&q~h’FÕ}#Ļq^\T˜ßõ] 9ŧM]¨Ė‹Ũ՝%H˛’gįՎ"\BË”é'ÅcēFÍŠģ@"fÎŠÖéQä 'žŪПö) ūŠ *üˆGœéļ@ęé\č\É!DŠÛnę&Ä0 ‹Í“ëô hˆ‡Ūh^–cJļŠq™*ǞD6é‚Ķ VH~h#M˛¤>•ÖP­‚ĻŽ>äŽ*hÖÍ[Šh„šR…ØéũŊÚëū‘ß™4EVBCü."И†*„Ļ*† ĒļÆåĢ2!§¸nįĶ”+wž+šĸĢšĻ+ģ>ÍŅLįvĒĢŧļëŧŽĢŊÖ+žŌĢžŪëžrįa]ßŊu–0 hĩF‘^ųęĐ 6Ğßf v‡I,“vaˇâɡ^l@Ž`8+ëpĢŽŠÆ"Pü•áXĪHzbXŊŲxé—IáĘĩÅ~Œ?Ĩ¤ŲQļŽ,l¨ŠÎ>iÎ\­dl…XÍb­ĨŠŅ˜ķTåPĶķ`•9Õo]R0͐EJkEžBNŦÍęsgĪN4…-J¨– mÚ~„ÚĻ퇀ÄÛ˛íÚZ(ōxū„ČX<‚,žå'ĩŅÚi"­ĨTDÄ %õ ÷pföb&u¨áņW•čŲÆÆŨF.žIÚļ­ÚfŽHhŽÜļ-ŗ°)ŗŧ)ĪĒÕl$mqşėlÜsA큜ÁʋœYÜėPAåcō *†jŽéjQŽīū. %Đå­ܲ-æŽņz.žx“ŪŪĮō Šæá5¯Žϊôô8š™šláîšôg­)İîN8æ…mqČA2nŪŦ+.đžoĒ"ĪđέōrnōŌmģDÆK@aÁīĄ.^ŒØéPŒ‘Û˜Šqŧ‰nžhÛČߜMÆ!9­.)q^Îú/a°NN(J ¯ÛūzŽwëŗP¯Ģ `.…Ÿá„Ē} Šĩš‰¤hŅíÛ§úĘI™d΁zĮé5Ĩ“بîr|@n ĪDŽ˜î#×J —Æēīo‰œ°§ ÜXËo ÜžX –Ü!Úē•›JąŦ8æ[ké\pŸæ§āžĐĨKp5q7‹ljÅÔ=˛`Š] ķ9_VŽ(¨lZ¸íŠāEÚ% ‹“qג*˙î`ÅqčÅčfŸÆÂą#ī˙F˙]%=jā™[šČ؝čĨŪĸwÜ×qüYO4Ōd†)Ŗä"W2,ˇÖ\’¯ŽĮ2…œđ3öŨ˛°‘XŒ˛Ö˜ŗ~āëíßĒņÛū ŽërI"˛Vē#.GŗīŽĒļ>/dIŗĢãMđĒQ͖g’\AÚ?nÄ^`šqÜĩ:ŗpš16÷ī;×-ûîĪnĶ<Įslč2pbōÂZâUņ%”$-’ h^ÎDĸō™āë%Øâ3ÍQ2DŗN1˛Đ=ã…ŧōD‹…ĸĸd6’–ėfa9CĄøŽYD)!wuN:O„.Ž´iČÕ:×'h>ôD3Môn´-Õm_4Nį2G&!m9ÅÃN!wĨh‰U"n. ãŲã3Ë´B…FGn#÷ôšjĶäb5WŸR~ö~Õ"Áũ"Ëĩ$“YÅ /f„{-Qvū—cĩDwõĨtl×ĩ];Æ#ˆ`ŖÜͯŧîÃqÅĻQŨ´8ΊHb2SĐ)ŗī:¨î5eŗOûnUWļJôĩvpm".*Ë­™}õŦ™™B‹€ČoLXv%ÅR°ådļf×6ĐÆ2mÛvI eöîgSiĶßÕ 7Öā÷YūŲŨon­ūÉdƒÆįîšs4×ŗn§Î@ÂōVWwJČ)æ”hĮŊöv^)&Ųĩ™ĪE*˛^Įi††Ys?w\Ÿlnëė|kwc8M,ëĩ}ŗÄˆBŠ ˇŲ™Ę\ŪÕ‰ßąE+K^ŲIz´Qļ\Ņr'UãژCJ7._õ~¯ū×r†SHG˙4ÃōJÂEęēĘWbB,ŲÛ@Ŧ¤Ļ›Ŋ6Œ=_S^ÎėR8| Mo´~w8÷øŽ(Q-ōžōv\Ŧ“¨m Šö]Ų šŠ‚a/eCĮôÛÍĩgylėxØÖ÷~c€T~ļR`ãÆčaœ˜0åĪŽÚ=Ĩ`K9ûŠ*ĀXø;sš–Ģ #C†—ÛwÉ"uÄÎĐŖY–”'•Ā"ā´ÉXéšŦŊ¤ŲîŌš}ZlO÷yžģu7qvįšõ‚ĄčĮÎÜĒÔ&đõ`tų3ŠŅhhDâ žtФ•sÃōØ^矘­­w8oŗM‘VuĒ1utŲāū‹AöüÅHĩ2FzŦO5Xēļnzރ…´OûËiš¨n!Jøâ ß*HCæw”ēĸsb6;×,\Oļĩˇ;1J˛ģÛĩõvŠP[DėĄ4U‘üąp€ŠLŊx:eßâŽ:4t %0æxŧ/ŧJ\v—3UT7séĪöã§ū†s¸ęķwQáĒ(y{ ’ßqr+vėīܐC9iÎØŠ¯Wyīļ>ņ§qĩûx䃸‚RĢëU>Õ>åeÔÖ>ûēú=’Tˇ2ƒĸž]Į}ņ;<}ŋIĖŊ˜o†āx"Q‡´FČäXņ^—´˛9yX+§ģ+cuĻ‹˙};žĖe´b > x0Á@ƒ&\˜`Ą@† BH8cF9vôøūdH‘0hpō¤I“'Ŧ<Đ`%ʗ0Q68°2æË˜&gŌ<ŲŗAK›5]Mi”ÁLĄ0—ÖėŗæQ PQRõi4ĒU­Q¯Våē3們cɖ5{-ÆĻuûn\šsį.Ko^Ŋ ÕBāKąŖD‚3> <ņ¯^ŋåđ:”Ÿ[iļT9”éäĒ`i^fpsg4Ÿ~îĒų¨éŖ¤Ŋ™õklØŗąÖn};õÉģŒy÷VĖÖĸoáÉīøpã˙(:ÂԟS( uԟgŽ}ģāîÍÉû.Đ9Ĩt’5'åZŲ)Ė×Ģé_ʲ~kö­M ÅzĨūĻöƒĘ¤ũęŖĖļüN[ÁÛpÚ­ŧ%ŧH -ŧ°0‚(ÄÃ˛6ÜÄëD ņ°ÃHQ<† ËnDMėFC €õĐ j5FƒmĢGŖĒ?É>ëĪ=”¨ĢiĀ“øīǘ’LHĸ–¤MÁĢ”-AWƒ0Æ.ŊüĖ0ũ“LŽ īÄÃcŅģĶTS;ņ´sąĖ:“Ëj´m„‰É˙tÍ&°fš/%Ķ.“ė>Ÿ„l€=όjĮ™ZTQ–\”@*¯ÔTKN3]‰K;E•ÔRGúĐT/šĪÍ[lE6amQÄSÅĐ1&aĒ‘RîĒ:’&ęL;22%• R:%öūöVŌWF%vW4Sĸ2Anŗ´˛SŦŧ5ÕP%]0ų 5Ũ ƒhĸYį\3ŧYהSÎëĀkˇËķ~ZW>åķIhŖ2p⁋=ĘQc^˜RˆŸŨÕØ ÖR#ÃĨø4+ŊÅmãMŊ•_QŲ-å /R.å +ŒBä02č\†øđ¯š jššŽ´ĐũόėČ<•ÖČ-.pŲô|-6Ā)5˜haNī_Ŧ›äĒa@Eܰą—į0ß-m ŲŌ9íÅØnnü}Ī*öš jĘŽ2°ŲĪ„@¨Š_jT˛ą<¨bOp)įÛīqēeZZĶŋžū<äOŽģ¡9˙ôĐE/Ûį̐;ϧN–ōkU˙ûõ_¯UÖuģŖ­ZY€uIJâ-Ī\l*ɝøâĶõÜøš6OžsŸEŽØ+ÃwZŠČ” o­Š§Ŧ?ô0•ɨÁĸTÜEĩ¯ÜSŪ1§Œdæ;w~˙T‚–§ŋėš-_8´øtŨŅk¨ĄO÷Ä0?ÍŽ€šĄĪŨô(Üė/}üRtƒŋâÜĪ‚LÎü4č–umÎķŨfôlí„ĸŠLļϞŊęáH`ģûSffã'ÚĖP€`CŸuXð€°7ģá ?÷ ‰ÆĶ_åŽ'%*5‘Ō•O,3@ô0ĀŲūŠT˙–Ļ((%÷ Ūyx9Đ1‰gų`ņˇF6ž‘x"DPŸÄ5˛-{?ŗT€î•›€Æ3vœ‰Jp˛Å­Ųą[ęž"įøC8>’ųĐ#YIr•ŽS¨ņ ‰֑YÂLļ˛(+Få5œ!ã*{ČJĸŅ’ą|ãËdiŋZÖ)f )ĀvÉËø˜Ŋæ/‡Lb͘ÉÜå2‘YĖa:ķ—žÜĨ”ŲĖcBŗšŲÄf/¯9jōō›ĪDĻ4ÉÍpŽsšģŧĨYjö2œ­ĶT”„$…` O{f¤žÆÉį=Õ6y†ŸdÚ'!2ЀŽs-ꄑƒÃ‘œíŦĄ•ūËZXd¯9í MU•D˙ŠQãtLĨ…î÷Đ ¤÷|Ā]Đd¯XÕĘŖéL9DË[íÆ ËqCP%3 ‰#¨J)B[ú*|ĨČV4U*q†ēÔGâ´Kđ2‹MįgS§VôĨ˛R‘šŽÚUã0ÔĢå×sJ“ÚŒ§õ ĢCëĨ¯éėk­åšˆU×YÖ¸ŌĨО+o ”V5_0•DÃzŊ͟w•Đ^-ø!Æ*6~+Ëk^r&8e5Ģ…lGÖ2ŲÍ2§˛ö¤ëg+ŠK„eE…ĶQąJZĻÕĩ]úËcc[[~ÅLe¨ú+Wß$XÛzÄŗŋU _‚ÛXáFr´_Šū\įu\ĐĖšŅe mĨûšâŌ…¸s‘jušËĄšJ”ēŨMX‹–žŠ×\âUAŌ{PōĒ~BärÚҊ$ģâ /|ãŅëōˇ]¨íq ۍ$˛gp?úßŅŅąįõ§; ÛP UCų噃ßÂaøzxÁė qÜ6„`ûG#%NņËLl'ãuÄSqs^ŒŋũOŀIĖNûĸaëX­ä:ëŒQVc"÷ĨÁļ ¨Oī[–›‘ĸ í‘Érc*¤Ŋ}o-“¯cøUIjüÕ2›ÅĘŨ]éO¯Ė#ļšmšũ.FēŒÖ:ĶŠÍš đ–Éŗ68ËíĪÅás ūŔãŨrĮ9ØAt[Ũú–‚gŅķŌs‘ =Ē3zģ'Žô­T›"ŪžČMo2Q¨=í[ĨyĶŠ~$bu:[æ=šÉ™ßĄŲD/ŽFZĢ€%õĸét[/AWÕ˛6e[,Ë4—ĘÄ&îЎzŲˆŲŲĨn-ŋė#]^Úļ,Ãv›m™Æ´uCbÕ 1›Ņúj4´īÕĻĀō:„6>įîähzTŪdæžÉÉo÷ā˙æ79^páWxžđ,38-ŽĒg–Ø ŗŽ9FYˇßÂqé*¸ŪũEWø“Ÿå)WųĘYŪr—ŋæ'gņËŲã[’-đHŅūÚļm—;äz‡Û5Ŗ:Č6ĨėŠŌe>Ļ'ęH—zŠžô¨SŊ}7ĮyHä ė ×\ĶúgÁ=ö´å Œ1W{mŦ˛vˇŋî)g@xaŨdÛ×Į_ķşûķå”Š€§˛ßÍî%5ņéSˇēâŊĻĘÅW=ņŋúã)ų̈eˆw戭 t$o^ķĻ’/Ž īņ`'ĀôÃA{ĄĶĄč€ŦŲė˜Öt=Ž|YÍ Ĩę%΄Ŧ?d əJ/÷YcaBķ΋äCIķŪqûĸģķ–Í_'“dĨ Ô ˇŗ…OËEžī›áätIr<ĶP‰7"M[FB h~$ū=ž8õŊŋíģČš× Mųîƒ˙üƒŽšd)h.ôÃ9Äė,4Ν6Ė/hŽ8ĀĪ‚î ÃoÄ ĸü‚č4XG:bĸ‰XCö ÆP‚FjD0˙$‡aâÃ+\gųx$qd/ŖY „JP˛î8J„šāĘŨÚ¤Ö$íĸ mšF- §­T4¸Ä/ĸœ0ÄōŽTÎOv”%v˛p˙ˆÅZtŠEĨå šđiN‡`ŽÄZÆZR'wXĖĐZĐ=’… YGŠ-!l%ÔŧėŲDŨrÍŲڄT }ÃąeVOūØo Ꮟižpįp Ũ0wBh Q2(‘˙<ūņQŋ'ī1 /‘>Í €Ŗ@MVp­^ ­ãÄŨF­ņĖŌbÍģxNQīöŽ ī¨ Oą-Ņ…—$ ېũ6q31O0+ņCđ(Ļ1ID1ŗX˜b%ÆísQËq-âŖ ãģJ-I…ž0„ÍnÍ|Ÿ‹Ŋ¤Py>|ĸQōZIJĢe˙`Ž&!CĢ%wTĸƒ‰Æ"å/ }00Td ͊×dq‡pŨÔ-$›Í­j-U:Ĩâ1äTÎV&]Ŧ°&Zä0"ĩqY,ņ……vąĻ'×pvâĐ&91"q$ū͐vä‹°ŅijˆæÆņ QpLęËâxqûî-F\2ļ@îCĸ‘ÍûO‘\wÆ(?ÔR”,īLîcĻbpr(€-ĀëĀ%yj´æ Č|ąšŌ ÁÎŤ†Œ*…Cƒqė3,#d-LéŠ"3&S2+“2/Ķ2337S3;“3)ķ*l÷f.û6bįÎâ0#NčLėúޝ4å‘1m c“ģR3FH%ŠoåÚN”āōåx3“ŌNæv“8}3˙ŖŠLbsęÎ#ŧ.㐠„+ƒĘ6aŗ1¯ĶÅP†Ĩč-[ic”Nō„'‘ÄSņ(/<Ŋ3'ŧč]Qúø°9ˇnfŪÆū5Šs/c„ĸh“§$ÎŧōĪø3/.ÕĮc2‰-g‘ÚR@Ξ‘nąˆĸũ*0)âelE*ë“#CyhIÚ0ĸŦ’<üSFčqô°ķ¤ŧ/&Žßömšx‰™ @EĨiEQ´¨i™–‰FYԛp4¤éFeTG{ÔFa4GeHÁIHi4HktH÷­H{ôœøÍE—ôÜ,”3ëų°o¤˜L+;”â SKįKŪS?ąDņâ<Š$î֔MÛÔMeNWčh%`gÜ1í”ĩ‹Jđī4ŅŦeĩō”J{>˃9IYÍT Q,ĪQ'īQÍRRĪŗō Õ6ć„ I,øūÂĶ:׹a1TAõÖHUÚNC{LŅ>T|îã„.#…ÂčŽ^ņh(kü‡°*FŗĨņ°â5úę#eÅ!V$mEĒÕ:*T!<õZQD!"E¤ŨБÍvlgÎåî&‰úĐ ]ŠĐ1]ĀđķÃāĩB8đ+ )í8C•>厴%¸ˆ*Šíž¨{TƒZOūg_¯ũđãJHŗĄ\M•\_j"K)ÂSķp?•V¸ÕˇUīĖ :íQč€ŦÚē˛đ´UI"]Õi(1‘tՆ¤íūđ/TCŒɆúՀނ`!ĶūÁ(gųŖ‚ĘņO—V×F2Pß jÉOņEŨ¨ö)T-lŠĒđk:}qʤŦL¯ėLcŒBÆRô mĨ#aĻ=„âj˛"2B ųfƒzt'~P%7 äh‰ŠōOW3ÃPĨQkĸž.B‚ę/Ŧf4.ĸÄÎq¯2LŸSBÛ"šČLû”ŦP—cl ,[v"Bˇ1ܐ;ÜV8S07æP„Ä3ōDcH)7T‡+†O_–„žĨvÂįmeƒfeƒ%?ˇrUÕ4uŽ­^3+…m#ęL]ũy"w0Ûâ×f“t—^›ƒEmÕļm×z —@$ņ„tđW6c4x¯_ųG×Īū'n‚;AƒPf—qš¤oĻW×2zXĻ/+ŽzķÕō2>Ũb>3rũwy­Šr3åõz5{#7Ŋpm@uĢd)rQ\ˇZ°1Ĩ 5˜w‡Ō{8FaÄ0H&ƒaČoōonc§į‹R‚]Ū†K⟐Ŗė 8èˇsũ×/gÉėN“t.–ˆŨVMģZˆcV˜&†Qx"ƒ—fZđFJ´˜bævI6ą~o„|4˜`ä¯b„Æ„Ą‡JÄâĸŊOĄāø]Ūx™Væ—ė'ŽŖ‰Ŋx qęá‚×ö¸Ŋy ‰f蘏 9]Tí'‘á؏qę‘ ’ûؑ•ūƒ’)Y¯€xØ˛ėK—\tÉÕļŠÂ*ˆpšĻo†Qt‚;GqĐø„]7RVXaˆQÂøøxÂkP™Š%Æar9I~ÕA?š~Lw­ĸĖd!øko%M‡â‹u!Ą$ŠƒcXŲ`Îøš§&X~Y–ĄuEW%šÅ•-æbnš9bč—|Âöį‰ięĄ×˜7™áB&זA—Œ;øŠW§vxr1RkXšjūÃWZâiú1|%‘˜Ĩ /cg–ģš*āųzįŲŠ8ē6•yĪ)Ščūtĩ‰~O>)Az‚PŒĪz(&J? :NÅswčGvB}ĢXn5 %ō9Øū"ؘÕ,e āzNP"‰˛ũXoĨļcÂÅ)ÁS?€ļpļŸ™îo+4ú“3­Ū<ēēÄē,Vī~Ķįg˙•¤•ĪŸÃ÷^eZpSã”Gf™DY3åncZ ¨˙ŦĮn7„zĶʖŦEÂ_æR5cø`„ä:ęšn'ŧeX}ĩ&ü#ViAQ:÷tZÂ‡*šb‡:$úēĢHĀLû,J"=ē—m/¸XtЁ–.;ųz'Ė7Ž)gl>›|ÔúF Ļ€Šâ$ŧštYļŪFטģUËRƒŠÃĩohJãĨwīŠiؔüh÷Z ­nwėFhE#=YY÷*ģ>tū_w‚šUo&ce5MRžL¨‚˜yƌd…1âPu™™Ã]KÅTcmŊ7ēų5aXwar7V9›Aæ”`:ÁÕ/}üÛ Ķú•†Œ4R´?B°‰—į8ÄīĖyÛÆBŧ]Ķ=7rÅô;FTtŊQm-a–Ž ŋģ(wĸU8„+ÆhކZvü`zvŠf2Ä;ŠmpČß°}‘“fÛÛŊA:.HŧUü4ŌŦŅŪmš˜m†˜“‹įаŧËO2$%BGŖÂtBŠî`:‘‰õ÷›ŧ(ĐšpÂX  dƒéQ*šĪyûšMPc•ĩf?žē5¤œD•YÄP{ ûäūe/Ņ ŠFĮ\ ›8: ŗ&ũĨ6ÔŌŊ\ŽĩŅ `HyŒx›ŖĨW¸p›å&¤FQž†)Ļszg" Mø}tJî†}ĶÉ7œ(JĘ</Ŧ<×ëÖh1dMP' ĮÄØ›ƒĶW %­u\­ĩ${­C]m,; ×Ō‹/ÆIf÷Ö뗁|qücĪŲwbĐjÚųU*ü\"[‡ĸãũ„}ܯķ¯{ƒÖ>­cĶ„[ĮÕÔ@§Ú­Ũāņ,ÔūĶ˙ĐÛ7] `3ø9dhŊQwZ\=īoƒw’Yh=Ą }`ôfn]HÚI¤ãõ€Ĩk¸YÂ3úÃs.ĖŖ?=Í|×ūÕ;ĖœÜ€JÃdŧКíĘߊįĘįI2B×K/Ī–Āf§hXķo>(v‘b_=ģ7?9ƒÛY>C7‚W{O€¨VoäßÓA‹–¸hH¨…ā5>é…Júzōˇ˙l[%`ī}įPæöõ(… ēŧÂĒŽĢQ܇ÁkLĖļĘÄˆžyĘ\LĶ“Ũ"Pŋôc&,;Â^Ĩ{¸šõEwąúXm…ŋū4ōzŗwŋRķˆaWƒ;Įs5ÖŪ>á> 4y¸ā'1`Ÿ“!ŽqŦč Âú?Búí„/`ÖČŌ÷XūhG0¸ųÃ˛m"‹.\WŋV6qčĻĶ˙öė<7éī˙SŠY°"„ ,ˆ0ĄÂ… :|1ĸĉ¤ˆq"Aƒ0°bƑ$KšDxņ¤J• Ļ\i’āaÚ¸ …/f¨a‚>&č ƒ&Æ8¤‹- I“†F8ĄG66Éd‘Rî8å‘T^ÉāG?˛&$ŽQzYĄ‘DbųaƒA:å“Næ(f›UŽiå5UTTBUTzi9ÕVzI)uT|^ŠŸčš÷Ôvåå'~ķŠˇ”Ŗū āg×VõĨĩžOV :āSá*]ĸmI*DljŠ~ú…ˇĒĒėÉ÷)ŦŽÖE+X­úę­ļŌë­ŊōÖ§ŗēęk§ĸåTj˛&í |ģĘÚ,´ĪÂÚ,ąĩâúŦŽš^ËëŦĐūJmĮž¤,IuNĘ­ĩŌnë,ģŨ 8,ļŨFĢíŧāx`R!0TPÚ‹ŋØJôũ4 Kõ—ŨŖ(ĖĶQ #ŧ^ό&<}ßĨ1U=I<đW ˇ%0U¯žl¤VޞĖĸ\_Ė2ĪLsÍ6ߌsÎ:ī,s§<ã|`ËBO4Āž?]_|'˙‡tĶN?ŗ_äŅN{AôžcÍ5ūÎ äËUÚؚ–UéşXũɡ^īũ¤ÕĮI­íéŲs? •SG|ˇVãņ iŨ ‚'Äpŋ‹øĢASŊĨÜ%5VĨ’ŗJųä–WŽųåšgÎųæžw^mä > SĸMÍxęuļEúčŽKÅ´ĩ­Īūzí´OîÔâŠSôōíļ×.¯īÂ˙>š¸.A īuA>é^„žŨĄęawĀķhKOąĮĀÕvķvķ'WÚxī=Ÿß?ú¨ø•š…ißÁōy2ŖîūcīĄŪsúoŊWõ÷ÛĘ'ķāg,đģĪā–Æ•Į]*fWģÚ˜¸Äņi~ šHK^ō’ 2Ä5ĮĢ`u2ȑ…p% ū!ČÔ4蒗mOXüGĻĄ%vU ĩ6O>˙™–Ņōãæpf ôŽOæ7ĩv!&ÜāKB…ÔF„ĄÁaņˇŋÂÕ~ļRš¯ĘŌÂT‚:Ä"˙ȰųDo~rĄRôą‡]EŽ€‹›Ûē7O‡|gÔ ä¸Į…áMrŧãŨ×ŊąĮ|ũ‰ķG?R­eÎÃ_%¯H ŊėX=s—Ŗ*•*öåĨ@—üßKIILBEwR„âAã$Îu¤buœhKX’đį_ūW6˛e†‹üĶ(ũƒ2l^JËJ3“BLoYŠR¸Ę[ĘTųF ve¸lūå-méM™\ä%“Ė*3YLQʰ€N!fSL&Š]‰ė™œ–ūPšĢ1 PËķ벡0úđëbđĖŽ#éĶžė­ŅdCׯ(67?Žod‚‹ØÃė’ŠšmŦbÍÕĘ"Y?w™“šÄĻ*3ÖFt}K>ėCÕuÚϧWšôž„YIGjÉû ƒ |ČqPĮÍ%¤§āŦ`PŸČ–jU&ŨJôĖYĀEU@Îķ Æ :•@ąÎlm\Ÿ™0‹r2X˙l@ĐĻ(ÂŖ˛,‰jõfQ˛ĪšŌ”¤ØTišÕŒ!ĘŽ`5VEŌϞ'_øš*T(,˛([6SģŌÅĮ<å!åūZtčŗcn˛Ņúå*AúŖrÚsŽ9Åâ9É#°GũķYĸkäč×Ĩ^‚ÅŠik °#’Đ­ģlM-wÔßö6"¯Œ"G‚ģĢŨqËDXËęO—jņ-la¨ô<ļC´\ĩˆ]œĒķZÖå"…•ąŽģiÜķ–qmŦx)i°Œ;>ûŠu— žEr5e^”ëMã—/—Æ6+Ņ[Īģn%(x™gŒÛōg~¤{ŲXUSSŖ­lb‡)aĒ^ķqļŌ&hUc?Åž×˛#~Âō3ą§rŦĄ ËĒØ ŒRôLėŋ¤ĩ­{KĢVĸ"$…EäîvˇBrĨå.XÄÔČūNœâ‰ĖÉPfq”íÔ°(wĖē[–J‹ŸZ2ėÚøĩŖJ P}[Ëļ9%`Ķls AëÆxz/ëPÂüdī|Ų č:'œoĢĪvYʒ?¤fE 9ō€å™aĨíģfjEpUĨZŨ‚ŦĄ5Eéb*ÅÃŒr[Ú1ĶøĪbž|Š,įûÂSž;q•å{ã1“:Ö¤üĘGƒŒŪār“\Å%îpˆŠ^ā:¤&ĩ9כ̕jŋÚšŲS—íW„ž¸PTvu[Úd‹ĩÕ`%-\æÜ W×F6Ž2'’8Ô ^qĩëŦŅSÃTĪræXVŋČä7ŗŽÍl”3­dØZ_Ž1‚Ŗéū‹áPUvWâ°0īÃđLĸLJn<)ŦČÛi›ģņ¨¯&0LÍ[Õ2Îŧ*o‹ļÚÕ˛öŗËåŦ9ãlj’g]×ÛäOæöS¯Zā•‹Yčwäŗ“ŗ\ō*#Ö~Í,Š}‚qĐĸuAčÄ-˙6oGčÖd{^|åT˛;ߟ…+yî4”<͡*^U.žŠ3|Ëŗ(~×™Ō…ŗLEík¨]I+°īœĻ9L>=Zœŧã€×^×ęŒšŦšYīyĶßr˜ŋ\\sb¯–:ōyöv~Ap =é;2zĶĢŪ9rÕé=Īzͧ>öą_jÕķ7=ŒžÍmÛŠ´Íūƀa,aųõˇņ“î够œé0Ĩî5Í8^äyä *=íá:{ëkõŽW}÷1aĢŋ|ø‹­Č!/ã…ęõígįŊØi}S¨‹$Ž6ĘĖ ˆ—0nOĶũ b# œīĶ?h@čS>˛õX ‡UįŠũÕgŅRx†§EƒNÁ•?Ōļg•Z]GSVt•û5mă‚Âķm¸%læ nˇķÔÕt?×b&Įlũvt5y#‚ģįlw6Áį\xöx“ŌPÁŖ}qn†''ČĶ.Xh<ˆgaöN%mcevQ|!…Ã$? á8ü$j—J/î×Yę—G|#JūˆBMŅBCÎ]ņE 1û’Y…ã6ëĶIeĮ‚Q'X< dˆQ8a‰E[”ˆxĮ9ŋ¤Kö'o(/”Ŗˆ—ˆ9—H[vęˆzėĨŗ•ˆõ…OČ4`›h/‰ƒináhhŅp‹…hē‚hvˆ˛cVCˆąŊ„*ęRˆšøX,¯¨háFüÅ\•x‹Ė˜FÍĄũ’v)Å:7x0ZĻ^V>Ã<ā!ct4c]¸€<'1uĨQƒ7.P†„RÂŌwIqkŸxxĩBhD3„{tŒkhMņbDœMˆĸwøHD^s3‰{ĐDōč#Ô‡öč_'å1=aiZĶ*ˆĻūLábwΈcua ‘īuŠCKꖏyJÂYeUÅä…ĩčt6ƒ‹„dĸøR?aŨÆHƒÔ6ôä7Hzä7VÅ{Vœƒ´*×s‡´âc7CŲ‡žR|Žh`kQ‰ÆÃķHO)ȕ›Ķ`Š´d>ô|€Į]]i–¤“;Y™,&Ų:–XCÚRJë$jΤ_ëæ’ ØYŦH(¤č9iɐh%Zgi‰îD–.´BŒeb°((\$˜9v˛Ē=ПĖSHژ‡ų1ĮĖâN‹k˙uŠˆXŒí!–ׂpëɞīw{#JĸŗFaÆCKŠ.ƒjZŒöpüˇZšö|…]%qęyaÖ1^Ŗ¨[)Ę8ÉI}Vb?z˜´2‹ÅD ņĀŅÂÃ/ĖcŠ!n)lÃ7ŒÃøiŽ•ÉXĄ*5ŒŽŦA¤w-tĸ1ÄVÁ˜ƒö`Eq‚zqčN<–â•ŧ9ŦąĀĖÅC‘ØÃ`Æ!ÆŲÃūáÅaėŐÆg,ÃX Įq,ĮģĶ^b4C†ÄÁøB°(ļ2ÅĮ“æ-0DMv!2ēĘ)÷aŽˆsWáŦq,[ŒÆZ,ÉgüÅ ÁœÜÂ/ĖÆ“LəLÉ÷:ĮĄ,ĘŖėiÍb_ģ™X­ČTĨŠXpÆôHZF[iÂ^xy™į‰y›FĘ ɘĖÉmüÂe ĖÁœÆ™,ÆnœÜËÍėĖĪl“Š6 ā~šô‹Ŗ¸0Ļώ 8!\‘Š€ÖŦ‹Õ`p‘Œ{GČx˜§I1ŊpLŋ|ɟ\Ė\ĖžLΟü ÉŅÎĐėĪ˙œÃ;ŧ0ÔáŽátŧĄô›I\´ņ7ėųŠ@œs{ų-ø¤w”¨ōÔmŠ,*Ū‚ ã3NãΒ—âOJ -IUfąÄÉ,Ț›„@>Ŋy1÷}J^ã%QÚMåQ^}üBŠ&‰Ž"(×ŧĮ4Ē“€§˙Á—Aí]ūĸę~ąjL.åhļæmîæÅ!ĐîĶm@üO|ōĘb)–>žNđŌĶîx¸‹‹< ;!Z+š jjūæāTš‰Î荮 ´2Í1ĩŠŽ97mY‡Ė7/§@ŠléæSĐe•Gž•PŒ˜‘ƈîč)ęĢÎęčÅĶBlâ}‚ÎG=ŖR6‡ÕƒcÁß+$™gDžŗI¸'ƒęĮŲkff^ËndĘŪėĖ.TÎíО^t Ōž^ԎíÛŽíËūä­îŠÍ+Ķ–n‘ĪÕ͚Ä(sc€~'Î{ėjXV’>×ڒ&ü,ĮūšQÚ[\‹,ßî_ˇq>\ÍU`§]Ø5ūŪę7掚,×ĘæeÅۆõ>v?Ģˇß^ˇĪĩ Ođ#ŨŨBî§  jØ=(ØšÎØŽŊŸãō 1NˇyF{ŧ<ÁÜø*ōœëņĮīOōC/ĩöÍv(1: P]¨s  vÔô3=Ķ•]ĸ’~ķsy§LHôĄZk×[ö[Ũũ˜épsØ˙É >ŗÛâŊ ›‰†X'Ë1oŧGšķˇöģŧ;Ī‚ ö}ĩq¨¸ÎŽKO K˙1ú=ÖDyÖDXāæôéÃģČWŸIú~œ š$—¯žî‹ųšŸų$Ûųôúų›īųî úĸúœúŖ¯ú§ŋú‚~û*ZĮšFGū\uļß.’xM°Ô§4Ũaěõt•ũÂĮ_ÂČ?Â"L§üÍũĖ/ũ<á´Ėûן•Z­Ŧ1ķÃIį†ųå _,Î`;CéA˜Ô褧jĄÄ?§™kl§ēã<ŦÄ;ŽûlĢ˜ ÍôÇÁ€Aƒ Hp`ƒ$D¨â‚&\ČŁFLX1$ő!+€RåJ–-]ž„SæLš5mŪęSįNž=}ūTčPĸEeQ"G‘#rԈ‘āÃĻ1’Ä:U`S…C"´Ę0iՑTM’äšmZļkE0WŽJ¤cíļ-iĐ$ØŗŊVū {U*، 7ŠĖø÷ĸWŊO—"V¨W$ČχRî82đ]´k9ĸœZôhŌĨMŸFZõjH™n™jᾎ?’k°TąšÍr•|›"H·+bî[RųrŪĖÂeeäĖÕ6ø‹;qRˇÜE>4ōˇu‰|ÅWߊŨân’yģî]yįęwOJĮŸ_˙~ūũũ˙ŠŽÂ@ØžRčƒ8#+ĸ,L2ķPđŊ‚ÚkjB§(tîĀ ›cĐ:ĪLÂK!č4­ŽëDŒŠÃ2Œ)<ƒ˛!S¯ģĀ˛Ë­ ÷vĢh6wã!ëŗ+ĐPd˛I'Ÿ„2Ęč\+ŠĀØôūŌ €ŦÖ ŠB]ėˆĀ+ō°"-‘ÔČÃô8\‘ÍđJd‘ŧ•;QJŖ¨“M Å<Đą=ģz Ë´ÄdëBĨ”62$°M.ų,3*īh1ŗjN—´ŗSO?5Ô'\Ē@-ô/ĢēōąŪ>´ę@<”HUo#(6ĖÔ$‘"^éË3Î`MU(’¤J Ė ¸ŧ”û‹Y6%ōY$k4*‹–Wųš’ÖŊđÂC6Ķ9-6]u×eˇ]¨äÎJp -ˆŪ\å“Ã+ÅÄļŪ\}$ŗ^z+ŨŗLHŗ5ˇŗŧ Ņ\=‘|ËŨTLMJi _Bŗ]–Đ‹˙DXāŽū=†ôÂ|Õ¸ä‚÷͗!ijųbfKn9eF[ļšĐ•¸gŸÚIRG˛$Yeõ_‘0öˇiFũõUi f“CJ1ōpļ3ËĩšK‡sv´Įę :&<Ã.ˇŌÎøæ?AÎWíYoūnßÖ8)ŽĩÜī›=6ŗíyī]tåŊģ)žËfŧqĮ/ ^†ĸ‹RƒÎ,š!‚¸čĖĒ÷uzĸ§]vēæŪtĩˆj…(KŊˊÖžˆ!w‰bMĶŌühÁīŊˇŅ~{ҧ¤Õ¸đŊ§šÕ4YŪĄŧ˙üØĄä‰žŲäßvŪŪ¯Y\œvīŋüĄ'ŦUFU­ô€ÉËüūVŋ<"Īc›ĩŪK§­Ÿ+ΎŧĮ×co˜]Ō=ȝkĀ*œß×;ĖņęeHÛŊį=/péØžŒį6č%°x]éÛÚ*t˛^•°> `øT¸B˛KrÛZāō57œáĢKƒĖBÖ˛ĪŲëpRi•ôį#Îi{ cŲžg;#&IeuĢÛÛD63œŅP‡´ÛÜύ%*He'ÃbŖŧR2™]Ɋ`t ÎøēļЍo„c“†&‰ˆēQFîÄ9H€MKŨĶŋ¤g} yÚ`—,:ąĐ€‹t"%ų!­ˆ’ßb$Ŧœ%DKŠË-[’ĪZ„,CbaktūVã¸JVļ25’#Ÿˇ7!0ŅįWc1¤]Ô’Øæ!ŧŠų@šÆŽxĀ ™hÂLÚHÖĸ–…&5›ÍĐL<Ę ëd7ģøiRŊ‚â0IUēԜįDgPƧîÜČúŅ5ɕRB;Úz§o BGI5qœÍD"9 Đ‘K–ÔbL Ãr­€rŸ ÛíbPMōÅ IL4cœDņåLgHE:R˜Ā2AÍÎĄz„Æä/Bâ$Ž„(Ņņ`hŖ¨,fM¨Dī-’@JĪ'%åͅV˛:ŽAyųž=&—8ĸČo`øŽ85qŸ!iVĩēՖĖqO§ZūĸôļÔ¤Ŋ'Ēb­åūŧ6ąUåw˛;åín—SŒđ”vÔŠ_*NÍ(ĖOÁ™ÎFÕķ( ¨C",Dmã?ⴄ åjd%ËBÉĩīT¯ dFg‘ˇÄz0›ČX7 a‡sĘšHû€ķÖĀūKœ\›+šdו$ l@pĢÛÜ ˇē.ns;\øöˇ(€†‹ÜÜ*¸Î-ŽswĢ\ˇēÍ]Žt¯›\ė7¸ËÕ­sŋû]å.wŅ}ŽyKÜđŽ7ŧīííyÕ\úž—ž÷•/sĮ;Yūö7Ž^Ĩ. ØīDy@\ _Ô/‚6”JaʁUWĸ¸ŌõH|mūUb[$3%fWˆŖ°@ V°ae§3{(ŋSĨm-Ļ^ėĒgžŽšbĩ\āa˙öØĮ3)™.›+ÕŅëjW›â(˛“~HWhT2Ģ€‡5fRųĩô§Ž@3\.סŧ=Ó¤"Ŗ×mÁ6SōÜ&y UĮ5Ķķ,ø4a<Û ¨äč†GiöŒ~ŧg>ß6”ō*ëûęEĩ'7Y"Ŗ›UFhovŗS+K…—váRÚEv‰ŽŨuļ™g˜ģ ›lžTåre%¨ËŠ[՜OqĒXĨE§xÜgZ×úS/aФF¨yQĘËJé=h×ū ØžŠįtVVšfb¤,'!ūk'ęIĸŌtgĸĒ%HĀjÛÛÛ>Ŧ3ĩ‘ŒüÜ)ķšejuģ ĶļuŧåŊŸņIHoæk2Ō mĩųĨi+Ęū÷=į—0~/åČūō“˛“ĨÆfW9Ô.šv0 *xĄģj5VuwÎ,3wŌ’¯3ȉˆc9KÅĒ"oÎaXWr”į˜ņŧe>ķū˜TĒžĒ!ÉI˜Pą×hņ2Œ1īĐWž¸…- ąˇpxÖ%3og —ę†ZäÆIÜęO#hÔĐÛ0Kųu¸ĸUjY‡BāMsļˇ].ãKėKõRĪĖ~įÄĸö§‚{$ęžŨ íŗ:6Äü(=S„äūCéLčûö¯ųvWˌŠĻežÖūAžōSŽLyĘ>™Ow{ęU—fÄ\ęĨ%=í5¯ī…$qŒīŧ3âzÁb™•ĒkLéĀëlâ,Y;”đš+×ĐÁ XšĸŠĢÁøš’ÃÉĖG\¤MŌaeå u-"Š?ė Ņ^üR÷–6‘ĖM˛É_}üåO“u.6F-ē_ĩeíĖfÆåq€É8ĩ÷@䰏Žr,Ás‚8ž•€?'á´É4Ø 2})8$“™ūɘܐ““0ųĀĀy<ÃÁ—Ëɖ.šœ+˜ã`›Ūņ‘ Ô7Ā`˜°Š”œĄˆœŋÔÁ”Ā5 $ū ÚĨÛ ö@;ãŊ1“=…b7n7j8Tƒ7d’åc>įK õ3:Yņ•@#¤Ŗ ŋ§šB68ĢA2>qŠ$“Ė:2ÜÍ!‘[ Œ¸Š-)ÜÁ;TŊ9ē˜”ØÛĢu[´ë§æ`¨˛Ę> qˆ?"¸žŖCz¤h@ēˆēåČd;2|ģĀ/zA˛ĀDZŲ5Z´}Ü|­õģ"14­įÃKŒös= L@‰°C<¤Ešƒ%!c8Ã8ļ‡š–žb2C;)‹[š_\Ŧ#ŸTĀ̉HäÁIl ƒp‚ûœš°_ę’FÛăs4@‚žĒÁ@TT2ÔF34Zū™°‹^´€#(ÅŠÅx”GœS Ŋëk§Ję=Č8ŒąS´XĘÆ0d,`LvĖÚĐŦeô(8qÆÖ€Æo1 ę÷94c<ÔŊĄķDĶ’Ą B™FĨ)“ėA’ųBúĮ°¸Ĩ@q´ģŽYœĮ˜Ü3\̰b Ã02+rArė!–VŅ c#œ$:#ķģęhIGTʝ ˜ô*”ēĒøFĒ07y"°ņ°?aĸŗUŲ>"ĘõķrK)lÁ  sI ģ'‡Ã*™tËų[§šäéĢĒųˆ}‰p!ŽQ-nLX<À;CRd6éI° !2‚ZJô`ĀĻ|H)Ëū¯Ü Ņã o* ĒǐžÚ î+’ ;ƒ#‹”ÚK[â@L ËPCēw„-#bO÷$ŅsĸÉg*Ŗõ@#Ôņ!"ĸ“Ņĸ•š!5áš`{“Œ•ÉTū–Í+TSP‰Ą[<ģ?ÄŦlŌĢ7Ë:m B 9ÃŌAœ]ēŅžŅÕŌU°ŋĢģāđEËx Í šĘ¤äß  œĄĨ‹+>åŨ´į4ļhSŗ:¤×#Iģ‘9‰ lšČļ¨^áOŦāĪ7­´XDĄ-eT>ģÅĩRš{r3‰;ãDĖGEĖ–5;?R‚ QՌEŊ‰,͏äŖæCB‘ĻĻŲøqÕ4EŦHDĘ Â˜Ú .d&DN,Ւ0ÕFVņŠP{ēŽC9Čä H¤ėŦwrÃĮŨ˜= !žä„DĮRÆĒS&ÛĀtŠÃŲ›6ūŧ7/ō!ŖÜĀ`LQ“ËÅŗžŸRēPuŽ`Ö{˛ļ`GĢ (ãŒË瓺?ƒ$ėėî›W‡{ÐĶv9›„ĢCĒ›C õ GŠY­ĐQLLŠ­! œČCrGĀŽOÅÖDuļÕÄוÕ*¯"›49ø?$Õ?íL*l”ʲxN¨ĒKUAŦŖWfLŽ(„ÆT“ߤOHųĩØp€ĸM‘üKä5dëÆ@Å ļB$^ŊV…U:˛°W–[ÄCLJšŦī„Z˜‰ÍÛ`<ÚŗJaÔyŒ†(Ė€T(pLO'LÎįĐÖ9ũ¸ĩP60ĖK‘ ¨¨DÎŅÂâØūKœ]Y8,63q֖ːC˛ŌŽuÂûÛÎ5Qų°ĮgųNoĄÔ¨ėšĘüÍjä¸Ū¨N¸%Tôt”UL…›[րĘĒܘ,124äũ7‚WQüDĸķ@ˇ1WtÄØAAžD]X@ŧ]ĪĨŪP ˛S_ŪäØĸs™ėŨ\]˛ÛD˜2JWcü“ũU8ũē† 15ŌŽ”%ŊriĶB,СUąīk!YĐĶ_D=ŲšŪę5`;0ŗÅ<‚ÜRŊL\RÄčûĪëO7ÅÜļRF°IXôpßuĘÎā¤kƒ*nÂmzŊļ‚3ģNąõÜžR͊>ūāí¨ÄSÄØNÜ5đ}ÁĒ “0$4a ŋlœUŋ`Ų ‘VTMO° ĖĀLíŒŗt+Xķē5yâW.ūÁ>ôZyãå°aFã˙€ĪņķĩƒÃÚ⏋ŨŽ6ôaX$2ˇ­ØíQ_øebāpât áËŋ€1°"åWúeŋWņÎäĮfēÖÜļA•MãKv›C5ú@-būŪ$[ĮM•ŅŌädŸ3‰BUŽØåã2Τ?.(fēÃSķ7{¨Ė\@ĐĐd­–Õ_#ēTĄĨäí9cLFæ)yĒĸ A -4cŨBz^OãŖĪ-€=Ũų˜Ō%vå/eQū äųėKĪdŠjŠõ˜1<’dĩWqa؈P2æ[Õ<ædÆgĶ€š0Û\›3”%†z™m*’<&D7…^nÚŗŨtačƒ€ņÚ­‰î˛ŠŽhŪÂhŠÎh‹Ū莞hæč鏖¯‹Öč“iVi”^é”Ū-ÃËį˜.–Škššļé›>Īņš=9,ņgœęĀ%Úžg™6jŽJ˜îŽ>ę¯žB[Hš"ëĨĖâY~5Q#æÄi6č@Ŋi¯v#‰{šëģŽ9ė’Žú˛.ķj/ž6¯Ŋ&.ŋÎ/Âîë’ėūŋ&lÃlé"éžNėÁö2Âl/.ģî*4N&ĖV—ˇÆëĪæ{hČņlw)ęļ‹9Î.˜íÖĻĩŌ† Ûō0Øî°• mĶpēš8íŅPmēíPém×îĶømy€Íæ ÖŽí™(nŪf ÕŪmˇ[’ā•ĶîëÆîwÁWŲn ۂãîėīņîŠÎm‡|nˆ&īõfoŸ‰îö†īø–o4ī—˜5ŖîųÖīũV÷Ļ9å.<ūđg˙ŽĩķŽ‰æ&đgđČņ܋æ-ođ ßo ¯ĩđę:Éo įđöä1ģF=Žžī”đ0Hy í™°đƒi g‰Đŗ—ūņęM€Į § ˇ Gq÷ÜXœŸņ"į3— 1Q Yr&O %ō–pō'gr>Ąō%ŋņ,×rú~đÚzF#ķ•ĩq‡ 2×rGķ(?s(Įō-Wķ3ŋr8GžęE—† ķ;—G$/s–Hs9īs3ŋq'7s˙ķ6t"§5tAt_‰Q'u4't>¯^OõX˙ąß0•¸íܖ‰˜+q¸ŽŪN—õ_/҃é˜K&@˙ō ¸€õ īđögŸ7¯^öäv%”øîŸQph×öČūąˇžvØđĮIv‡Ėv)ŅņmGw‰ wĸ¸íoī‰Ų^nëŽmx§w÷{¯÷yˇ÷|—÷~Į÷}x}xi{ņxƒ÷w~Gø…Wø|/øt‡øNÁõ(q÷H/î‚/Œˇ¯üúëŽįø/_¯'ų‘7yæ*y”?yīę2ŋŽ”÷x˜y•§ų˜_ų™WlY‹ø÷/˜ŽøwX‹ĻuÆ6#úSdiÅ$ĐÄeŖ0‰ŌÅŖ‡dÉøyžˇúį.wÖ¨úšā0Û ę¯û°{.1įą7ûŗ7Ûžúĩ÷ÃCîũwI”˜ ŊĪŗûēĮûģ×{čĖûžßûŋ/=;gûÁ¯öūĮ”÷ŖŨOŌčŗ§Ų›ĘËŊfĶĨV×k ŊĪúiďdõ4cÂ÷|ÉÚú›Č]l ÚE^Âfą:ÜYļBØŖžBbgyŽ$P[ØŌ—ÅĪĮũ–}L…žá}ô_×)DōÔŦJAŽZ1X—*ԇú’qãččÛĪũčŠĐˇ‰p^ȝ“oÍf.Žzœ̃Ŧ动A 59ĐRŖxļũ„ļdég˙VĸūšåzöUAËũI^ūĩIÃĪ‘ņɄ!#€ °Ahp° $(ŅĄÄˆ^Äx‘âč € r$ɒ&OĸLŠr%˖._Œ)s&͚6oâĖŠs'Īž>ū *thАDž,ĐņŖGĻM.ˆĀĄÃr„čÁCƒpLxÕ!دĮ‚e€āęW˛lŲĒ-ˆļbŲĩ­BÔu¯E¨|õ.5Št0á†#NŦx1ãÆŽ# Y§Rŋ}/Ɯ9ëŌĢc"üēđĄ]ĐŖŊļmVôh¸eYŋåxp Y¯œogäœyˇîŦ%O.|8ņâÆ#OŽŧ&đå,+o~ŠšwîĻšDšmW…Ÿš?‹1ļjĒfÉÄÛpnÕĪq=kô]]ēfęOA:Ν?˙ūū˙xÔ$5` ›eŅ-HQBK=ØQ{1´ÖB X—…$ūVzW‰UÖlĒĨÛxeH[F|Ų×ā|. Œ3ŌXŖ7â(ԁ1CjáFƒPqdž‚™A\!ŲĀT™§W\—%_AØ-Å$•ôĩøW—Tō˜Ŗ˜c’YĻ™gærB ˜RZ)ä—ō]IU•U6P”YĐV ʼnŸQŅé× –Éâ‹^Χ&šBФ“RŠR°ā—pœ_ō&ŨĄ× ꧔WÆ7՝J:éԓz69ĨŦyN‡‘–Ąr)įĸ[:ZНŋŦ°Ãą™ĀĨ6ĐiЈę*äQ–ĘŲ§[˛Šį˛FŽh–„.eíõåÚ,TŊ[Žšįĸū›îM›&ģéîÂÛŽŧīÎ/Ŋ÷ڛoŊûâ[¯ģÉ0Ā sŠ+áE†Å$ž{Ėm‘  hDĶžĢĸˆËhŽäĒÛąĮƒr~l+ĩŖÜđlÛbØđ¨§†…ĸhÔ9Ûj'…ĩbœōˇāÄąČC]´Ņû8 ĻFUÖ–‰ō|q”~†p“ĩb7Ģwī5¨Š[)yh†‚> õĪf›ĒĐGŗŨļÛoÃícļGM+E2ß-Ѓŗ9ĸ@rįg#ū-¸\šv—āeųŊøā n=øÖ ĸ]0~pcžšæ›‹ ]ĄuŸ-v*:9Փ›.9mēuxäoIîøÔ°ū;éVëo¨úgģâÚs`œŧđÃ?*wåžĻ3wˇŖ{ęŽ{gë¯D{á;Ã{âS=?yäŅōNųĸŋ_žųįŖīœįt‡N¤…3˙ũ<ÕÕĪėú‰T­ŽûÖûãīüî;ĮOrīŲÅ\T°ž\.} \ ˆãíęx]S؈ÜbŊ öjßéžáčwēšf4‚ŗ`ũę-ĸQks [čÂŽyD f ô4ĀTåGKJœĸs(SŨe`ŠûŅĶĀĻÃ:(|JÜØ ›čÄ'ē‚ė›!Ų’T¨ŦĐbW‹Č“&++õ†;œÛŗ§­ … „"ÛčÆÍÅĐgTŧūŽãŗ0Ļ܆+:á zxFŅeˇøŗŪiŒ)+|##éH_IqˇšãŠ*yĀŋX2>ĢaŸ*ų9*"’†—J@ĻiĘSĸRRqŦb(gøÉKžRŽ\âÉvĶJX6JiŠÜ%/{yŖd ˜› ˜0 Lb˛ë_KfŲĖ9Ķ™Å\fŠMhb͘Ę$3IfÍmS˜'9Ũ5NpvķœĮÜĻ6ÙÍd@ã‰.}iĪ{âķ8rÃc&ûéĪ4 (A jPŽ1Ÿ ](Cã#iUŦ–ą”¨Ą*Ú5‹RôĸÍ(GšQ@2`” )IK)ÎTĄÔdū"ŅČŌ—Ž4Ļ*éĸiŌ›â4§JÁVĢÂSđũ4¨@ĒP‹JÔŖ5ŠH]ĒR›zT›æ4ĒRUč>ĪĨ[Í  Ä¤'˙šÕeÕĢbÕęXŊjLÕsĒj]ëH `5ĩDËŖ]sˆ‘驋y’Õ‚ØĒģ†%l!dĢúšž*•q5{yM > ĩĪyŖV‚*[+kŲ6bã‘ëw“؏hé3Ø íÎ~Ø­8ā‡-{]@Ģ‘IЇAęų¨- Vņ}„˛—Ũ-oØ4-Dœ­ak*Ûü0<zΜdXēŽå†4ŧ \jX]YâŌĨ]Ōmoģë]âA¯_áŦlūL×Ö]hD¨ƒVëHȍĐƂ„;ŅY(ôEԈ*p=$n[ .î~7ĀŽ[œÖC^ôä­<×%DācˇŌ‡=o z‚%åŠh5sĩ‹i-r]Zú÷–â"߀KlbôUFŗĒaŌ\aך…ŧÆfČũū4ŒāĮ™ŽOsđyĪũBĨ4ĒeßJm{ÛøÄJ^ōšb¨'—Č6yŠđ\|\žGXÃfąJĢ ž,g+Ųu[äėĸąK$f2›Û|´đrŌp^†ņhŪW= J €ŠaĪâŪûŊÄmš.˛ŲaĄĒ Y#‡Ņ}I˛›íhk$;Ŋø†ĘTJ Q¨–vęOŖíå!âĖ=—æô¨KM•gĨ”^5Ģ+5éL[ [ĻļŦfëJkúÖ¯íʓô*jLĮظ6Ŧ‡}¨cĩ:ŲĘ>SĻ”uĐgC;Úd=­-Ĩmí2āŦPõ˛ģím9{ĸ‘ˇ¸Ë-Yss-؎=7ģ×ŊnŽ&iũ6ŊëŊœŊzÖ¤ŪˇžûũĮ0JÅßįw§mīƒ#ü(lröĩŋŠík×p|:aÃ!^m‰@Ū˜wÂ;îqÆü+äÅ9ÉGnō’Ŗüä*O9ËW>/arŗå2wųĖkNķd„Ûß9Ī›¨KŽĪč=:Ņ‹nôz;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/PoolingConnection.gif000066400000000000000000001104651447311732500312550ustar00rootroot00000000000000GIF89a™÷÷˙˙{{{{„{{„„„{{„{„„„{„„„ŒŒŒ”)”1œ)œ1œ9œœœĨĨĨ­­­ĩĩĩŊŊŊŊÆÆÆŊÆÆÆÆÎÎÎÖÖÖŪŪŪįįįīīī÷÷÷÷˙Æ÷˙Î÷˙˙˙˙˙˙Æ˙˙Î˙˙Ö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙,™÷ūIH° Áƒ*\ȰĄÃ‡#JœHąĸŋ?`Ü8ÃEAr‰Q$ɓ(SĒ\ɲĨ˗0cƜŠqfÚqVÔis%Īž@ƒ J´¨ŅŖH?4h°€ŠĶĻPŸJJuĒÕĒMĨ^Ũē ëSXš:ļ,ŲŗfĶ2]€´­Ûˇpãʝ;ŗˆwķâŨ̎/ßŋ~Æ+ĸđ`Á~ F|¸p^ƐKŽLy2Ū8ŌŨĖšŗįĪ W.pLúqéŤQ;Vm¸të׊]›–šõėͰoį^MģˇkÛĀ}fē¸ņãȓ‡nĐĄĩåĘĐķ^¸šbęǟkĮÎŨ2q‚š•ū‹Ožŧy‰vmķ–›ũoŲÖûÆvˇšsú°CtØÂūų˙éæžzšÖ@Aá§ā‚ 6ÚhšąVÛ{ëívXĄnæ§Ą…"`8á†~8ۈĸXâ%čā‹0Æ(ŖMé}˜]{$ÂÖ†âÕaiûŠfßtˆ¸ZsųaC†˜!›āŦäŠ‘šˆ„™Ÿá’5ÃÉÎ’3ŒČyg;įY?y^2žôūĖ'íI~öğú (ä‚ĘÄ MhØę†žÄĄ hĮ ēОÄĸͨļ0ŠŽPŖ ũŸG 2Ō“”4¤1\įØX¨ŌœTLãi)JE¨Øt-8íJNoĒĶžōô§; ĒO… ÔĄĩ¨H%ĒR{ē–ĘÔ"/åHTUōԙÎčˆôœ*F–šÔŖrõĢ^ +TŧiÕ~ “tU…g˘ֲ:H̉ō%*i˜Aē•cpéũ"×oŪÕcvũ_[!’WE1ō¯ú*,ĸÛĐ*ątyėķ$ &ĘB.–í]fģ´ŲË"Ĩŗ¤mŒDëYĸ6r§}ki÷•ÚĮĩ–A¯]ūíLb›7Ú QļÛ˛­Øt[Ūâöĸųôíx„ûۏfÕąÅÅq{ļÜä47šR .rĄ;ĢįNtēÔe”uņŠŨėŌTē ÜŽw'"^~•ׯãMÔyÛŨôVŧ\¯{"ߍļwžœ…/ë‹ßŽęםũ}īqÃā/ņWš÷-đ‹\+ĪÅÁ †°Ŧ$ŒYįiäĻŌĶJT4<ž7E:KVFü”Ē\Ã#V€ˆCŧa¨€¸{ ČiNÜb/ĨÆ$îŠMŨ‡ãÛÅ>&1uü"ôČ(ną@ėáø1@ČGŪņø–\bįTÄK‰ąS2œã {ÉRŽ1˜Üc‹2šËPŽŠūiye27Y~]ÖpŒ›‚e7į+ nąQĨBeį™—UÄÖpæĄB­ĐM3ô hĘ­Gk‹ŽP¤-éJSúŌ8ģ 7at+LG:Ņ€Éš–<Ŋ¤Ô¸Ži×Á€&MhBKŠÔ¤Ļ´E;Ŋę×ôG‰Žĩ|\5éA“WyąRN .™u‰ĢÔ|ƒ—؁hĐÂÖЙ§ėg7ÛÖ¨Pĩt—b’APĪļå#j2õgÛ*JZĀ$¸%;ۊQuŽ´] ‹NNŨ“¯Ÿ­:¤Í›P×Î]Ķčt4ĢĄ(Ũw‰–oiˇ'Ũ‚rˇÚžhSü[în7Æ)l31X)¯îøÁūOtnlÃ+K„6ō.fp_œáŒ>šÃ‹ö{W-uø>8Äžk†ÃæŧŠMœŪ#ōÔĐÉ ĀKŨŒ‡ĻmŽrĐ9ŅĶ™ŪrāY}8]˛Kō27jX3‰;w4Üf$ąī1öŲēđf=›ŠŖn¯æĒ^™ É-IžžÕֆ˜ŲpŠ\ āÄgGlŪ­ŗ]i6į'~qˇ|î˙ūV€bLúâ>Ôî iķŽKü\y_wõÃūŪųšÕĘßUž xŊ@+Ũ^‡øÛÄ26\gč÷ËųˇvŧX4Üh—öĒf?=5_Ú-ŗzáGô’}$Ō.Yƒ*Ÿ-šFącl&ĮtsFō4h#,wį)žwu€Ą&nGu”Qgu“<ų‘,9gŗuB0Ĩj‹€ ȸŗ‚ÆcsŠ&(.ƒŖR|H0j'87x€Š"1¡$ķ'yÜ†’Wj‚!;3Ã#r%úĄ)•Ō+¨˛)Fƒ_H/•˛ĸ’4û‡2ŋ˛†?’{P(xÍqyįąp›7f¨zG†ĖR…F’&cø‡ė*dč0Åâ…5Ã'ū\h3†˜…_X‡Očz?$Ę"}5#3'3ˆâ‡Pĸ‰–Â‰Ņ†€‚)Fhˆ)“5ņ’4ô‚lšfCƇ~˙§‚̧.S*ؗ‡čRŠōR‹Ę"‹ c0ķG1ŗ¸,õ'2Wbl/Ō-ÛG-8* c3ŗH1Ęb‹Ā(‹Ãō,]H‹ƒo¤¸ƒ™8ȡqö!c|U˜‡Ķ‹īr„ ãŒŧ˜ƒˆ3Š„¸zĢb‰ wkfÂū#4ʏc3ÁrÛh*ˇˆ*§žčŽę˛ō"¸¨ˆŗsCƒ+ÄąœVmE—‡)Š&c.WØ~،Øh‰V1é.)Œ™^s/¤ū‰ûĻs26Ɏ‡zš(‘öč2 ’™r¤ĸ4I]'5ûh|ūø’́}.hP3 y0ģ’k2,i1ōØŋ’Ü’wlŪ0N!#üHs=WĩX’4™ī˛•锖2/ļ‹%ŒÕ1 ˇ”÷8¨”ę&"j9—Øøp)—ˇ˜˜UŠ,đÂ4͈*"…É.øĢčGÖĮ”|Y€+€€ØĒ‚2BɆąX2;X0:Š…g†Wh„ŌŌihÖU´ Vĩ)V`…S‚–ē'…šr3žŲ!”ø™sˆŸ˜ˆ”š?9…)y„™Š}9–2™™âŌlÆš’+™|+ūyšīؤ¸šYš­‰’ĖX™Šæ„3Ų5ÖG%vgta‰‡ĻFĒmYhn)Rrī;LÂwCˇ5ŒV4YA#¸W6›†ƒ'¨ÖyFrJČ'ØÆ~v’h=hx‘×ÎøuŠĻjZŖ40Ųpii}2z¯–RC'ūW!å—ŋĮ*8“ĸøš”(Ht/:rčŲĄ™Ivē4.ץŖQ3lzH<đ{ę&tĢÁ5ø!wB!278b‰r0?Mą`|Ų—|<LJžf%#:¤7bí9{ņFƒOēliY‘Ķ2]Į5ķ)%ú˜8qK:!šˆ5ɓi€Ž3ēlę¤Ģ‘”ëĨū"Ã{ķ!oÔĮwųGnįž-¤/XnGĸ(5ŧæFšŖ„:|0˛pé92ču¸Ķ˜„i䖧ũöž†Ú'kãl¤j&Ič#‚ŸĢúrŪōĄû‰ŒJ<.Gw ĘĢæ#wP3mÁö Hà GNŠX<Âs9!ƒ3X­gĶyå*õIqoļšz„pöņ4bĒ:bŠ:RqŌÖQz“Į}cI(ŗ6Ģ}w<`w\G­L87‘ūąÂ…ˆŽĄw8ÔvzŲ†°K°īš°ŧ[}E_Wz|ô7– }tš~GjiĖGŒŪ˛Š9Âv čˆ+pČļy´ãˆ)Ûū˛“dC3Fg¸9ŗˇYŗļITUqŗ4Ģŗ6ģŗ>K›NE@C;›Aģ‰Ĩ!ĢžYÚ)Jgƒ\ †qmĄö뉆đI‘š)˛D3k1ûĩ=ļ<;ļ?KļbëS<åm!ÅXQ) á<2"ˇs+qËŠŽ¨Ļ°™3(-¨ÆĸđņzŠ:ĩÂxĨ\{¸ŋAa‰ōlëXÕ¸äq´01´EĢ•kˇ˜K´™[´•{lŧÉ´"˘áœ)’‹¤Éš ēŦĢ;=šV5 ˇP˛—Ģš¸Ëš›[E†‹Ŗšš3ʎ¯Ņ.訕nI€ësŊģˇąĄ¸_"š°KŊd”ū›5qģē›ģģ‹™[ëģËûo8ˆ4‘Øč‘Š™1ž™éQ8!šĪŋΕIû"ŋ-1AqˇD[šÛģŊôģĖĀÛžŠų|* Œ{Aŧs‰¸­ûŊÎ+KøģAÔK?ö{ãDŦĪ:w¨Ø†Á›Š ”U™€))”õhvŒę¤`ļddcÄE:Ņ…Ņ7úęhģVÃüŠnķzÎJnW#Ÿ…§Ŗ'2zJŦrÃc7ÃrX*|PbôĀ RÁ$u˛,;ÅMsĩ}ԁ…§¨:Å^ėN Áo4Æ.œPl,dz¸Æ¯8ŒKwkŖrTbkj'S÷žnœĮlŧ}r¸ÄūčÄN5n'üŦ=ŦŸqφú¨cgĒ’jÂÖĒ:?W&ŗŗ ļMåËļ<Ė´L=›FÉ/ąDņ˛Čœ°Œ´ÍL6$õŦœLŽÍ{sÍQ́ŒÍbscaÎÄDŋä,6Ô|Î2ŅCÜŦÎ&…ÍtĖîÜ3:Ájûmõ S~´ĪŽåĪ÷;?˛ ĐĩÂXeņLÉ ÔÎŨO ŊÚDĖŦD5‘ĐŨ[ ŅQ´ŅÍ\ 21?ũŅøDŌŅHšÄūI&Í^+ms4Đ-­^1íĐ߯Đ3ŊÍ7ÍfqĻg8…ā žāūāîāŽāVQYžáná^fģÜá^á.âdÖ=%Ãɘâ߸Į+ŪÆ:ėâ0Žâzã–é'!°ßäą8ã2Îâ |ú°’úǍ–ëDėČÄ>æ5WYEŦ!›'Ū-uŲŖ˛*qGĘūÖ$ŪxęĮúhŠĻqJūÚŗ$öūYĄūš^ƒ/¨¤ŗČđ#ú…#÷Éí~œZiT‹:\ģĢ8NĪH´ÅœĢMã5HËRÅĐ}#šđŊgŠB0—(€OĻZŪÒŪv'ē)øŪķúN€Yk‡WĮV›œ>bãÉúČ효…;t#?ë |ķ"xU~A‰éŠ&ę Mé yiĄ*àc7ĮOjĮ Z*Ōˇ|Ŧą‚:G§ôūöMQÂ>÷Õ~œ§xŠYųĒ‹•¨{ˆŦ™Ā4ŋœĪIœÄķĨ œî„ąßw_i lšÍ’ųī(*YX’†¨ēCZˆXûĻ‹)žˆ)Ãé…äŠûÕš]o_oųĘ+•ÆūŒŊ˛'{ųüqyŧĮB—¨Yũ{˙­ę‰jtģ'ū(AkÖ!•ƒųöҝ÷˛˜•ÖX;pÛč•ŲXÂÉ$įĸ÷ŗÂ.Âʒ<É$$XĐāA„ .BÄC‡!JœH1ĸċ)NėĀĮCŠ9˛$HĒėpR¤Ę”;šT2Ļ͏)AĸüØĄáK-kĒ\šŌáȟ“jܘą"͈ ü ° ‡„XXÅ*p+UžŦjĩ`ƒ†>!î$JŗhQœ;ßēdÛVnĖ™l…ÕéŌg]ŖrRŒ”mÇã=)wąQ¨ ĖNĻ\ŲōeĖ™5oæŦáŌ§ūĄAv:1Ę |]Âå9ôtҘ]ŗúŅmÂD#.Ļ3v‡Q›'nŅøRɕˇ~eū‘ H;ŊŽ…:õæÎ­\^ųsp  Cļ ›nyŪŽÁĮ^ “ŧEˇņ‰žŨÚ$đÄøíÃ|,ŅíÍųÂë<’ëė@TpA'cč"§",N´Ō„Cę§ģVJo.ģ@ōĪĻžT/.5D­¯ũÜzK)ĻZÍ4ᒚ ŦįĸãÎ+mŦą ær¤ŽĮuüq,ĢВéCĻä:m1M,ĪIžŽ<š\ŌĨúĒ„ō¨ =<ėĨĄŧ|’Ļ*ûP7ˆ lpM6ÛtĶÍī&$MN YūO­ĨÔrȃŒÆ›(Æú’¯4<—*­!>S;ŽĪ/â3ĸÛ ¤SÎ9UĶĒî| R;§ëQČ=Ũ´:‰ôLЇ]o¸Ōn REHô'X%r•Ҥ4¸HŸrÕE=%*”Ö?EÕEŗhÖWĶ|ķYhŖ•ÖŦ]ŦÔÚ:‘-ļY YÜHÉ['ĕØk#Â3Xņ0Â3YYÃ–RIe4ĢŦR5íÔ^PķũQßPo4U!#÷„1Õ +ŠņČ´ĸuš„ˆY[IK´ŖƒûŒ×`;ŨÕč`DĮ%ˇĀiCyä5ãÔøÚnOöø)IMwã#-ÖV-=ÅčNŒĖuWU¨’í^Ĩū˛…JĸK-û4ģįÎw;ė°• Ž¨ÅøĐb!ô‰ę›ûuĪX9ūXĻŽ]Õëc ĐĢūiÖĢ3ĸ˜ŠBv¨h’ëļûî„ĒMų]•‹.ŪCꨊ^ßöÕÛâæ;Ē­ũŲpŗszrĨû ¨9ËjÎŗR°Ze Ž*mĩUr…9ŠuÅV]āŸ†­¸ôf5t¸ŗĩ]vlYŲęrŧƒ^d“ų6~īŒ đÎ5Žåv/6eâļQŨ­¸úŠ€§lķéĩ üƒĐēHOu"ˆm•~ŅEĨnvėĮčį˜+â{ęûTõĐ0ÎRÃ#`ĨU•4`ū t€¨Ā.0‚ˆ`Ø ^PT ,XÁjp ŦāM &pƒ*ä  G¨B^1„āSøAŪP‚2Ä` M耹‚7$"ØBņ<ôž$ž.0…œā ŠXB!Q†Q !g˜ÂƐŠœ É(BļˆôaKxÆ ē0r”c7ˆÆ7æ‚3tbũČ œĪ[eSŪá$…ŋ…š zÛbÆT†+æKRÃB•p,ÉHėÉ fjâô Ž-’zaŖšõļwÉBޞjt¤*]y;T6r\ë¤'my˂|ævÛ¤ˇ¨V(JŠYëūķe1Ģ÷¸“-Ĩ}‰|Q3“GŠ ą(Rj™.D/@ę•ë`1{Õ¸Œá kÍ'Ex†ŋA:szę¤H°lÖ.t5@|Ö¤g=õĻ=ƒŗr´ZŸĖVÖĪhŠkŸÉŦ„.F6L  ŨH-ëéFŽ­•ķã& 9Kū!•’ķE˙Єí3–ˆ{ˆzRzRQ†ķx÷ŌhōnmĢ‚Lmú1—eí’cCfhZ'I ŪT¨A%—˛ŠŌ"ĨĻVEÕÚMû÷Nnt¨CUĘã GÔŠb¨íœháĻ2O¤†ux x'~Ļ–Ît† mXcfôÖ Ro‘N4”\Ö˙v”÷ĄŸiū¤6K*ÖĖ”eōH&ßzˆÅm˜u=l_õJƝé՘’åž9[ 2ĀfvŦjũĶG@€&Ômô)DŠ)AåŋŠf/OîC-āŖ-4ŠöŖĒŨ(ÄĒŠYĢ@ņXžĀb(?’T2¸ üt&[¸R 5ÆĘhj…–ĐĐŧ–@Īmq{]â9Ÿ]J††ÚϞ+RZ VV…Ę’L‰—Ģ’äkņęS˜˜WĢō•%fąK™N-۝Z•9ŪÅvŧ´Œí¸¤Ģų&˜ŊˆÁĐHŦ`Ã4]î•Tlz_ #Čd>i ¸{ĩųaö›ˆˆáÆē\­4tmVû@ƒ_/hĖ‚ ūēÄ Ęō5Į• <1G „|`%‘‡äĢ ™ŸiØv?ôĸ)Q‘rUKšō—ŠāXpē!­_WšLĨFlŋGÁHF\šĻÅ­SŨ°ĐĢbæÂynĻķŗŠˇîúiš¤-ŅxJÜáîŽvËTq=›#ũ}ēËíni‡ΚĘ5Ú¯-ō…‡xīįxÛß§øĻ÷æ×æywŲ7'šĮ›é“wd˙-#ēsũĻæ÷Íų°œ%9*õĶķŽūۆÛđZg8ÄĨ›žû7Ë\ŋ9Ģ3nvÂC\đ ˙;ÆW?iO7*ÖŊ{ņŊƒÚ¤¸÷QK*ąƒG>Üá ;@Zúĩĩ­lekG:Ų7Éœąŋlč rŌ Õų˟râD|e!_įųzĘŦßķņĮģ{yđnŌ°Á8Ŗ˙ k“h—…c>akžlk4–0ļCÛ˛‘’°ŗ9æ“8L:Ķûž3> ”ļū ~Ō}Z˜ŸJ:?ņëŲŠĄ)/9 —°IœZ›Č;?ʛ7øyɈ PĄ€ ĸL ´ ŦĻB,8 ,¸"\2DB!<Â%K Á ™šĶãĨ)dū›TŠ3­˛ \wâBŗá•ØúQÂÂŋûŠp™4•kˆēË@—ƒ9Ōķš´ąą¯Ą>l*Žz0V!@dĒډᐎČ).¨’Aœ<@Š&QsŋxDЋÄʸ<ĢđAŊņ+eŅ't‚¤Į{ŧ>YĢËB5Øû˛R‚ĒŌē˛wé(°!ŋu)År“ NƒCZĖ›ŗj§x!1sa”u™˜ĮB˜Ŋ‚Ļé1ŋĨ Æ,FE$§§H?:ķ FÛwb)H3ŊC§`ąELŽÉÂ4aDFĨ;%ŦErÄģŗ21C Ä~‚$× ŠļáFĘQ:ĄQDbĮz4ŋDbÆ XčĢ<†ū ČՁǟ"0bÂGyģG†ĸ-bœĮÚĮrŒČ% ŪĒĢž[ŗė“Y.ŠŒG{œÉKF‡THŦ¨93>Ú­„KCDąē3#ü“v[ ĮyɄÉã‘Į€ú‰ŒČ;ķˆąĩdĖK˛”LžDKEr–ĩŦÅ;㓕lIÛĀļÁ°5įs0<)ĘԐ2ЌĖūŊÔ¨†,ÉÔH°ĘûŌ-q"‰j;4> ‰ũ2 ĢK”!ēD,KˌÁÕäÉž‰ÁĖLÍjËT[.t Žīģ¸“;°|1LkM,ÎąÜIá\ĖÄĀL$ŒĄ´ŖØ8Ö[‹Ô,Č4NŋœLėŦLųôIå„Ãŧ‹¸dŊr (‘¨å Ļ…;ČŋtM¨tOųÜFŒŲÜG(ĖŪ4@œžėĀ3´üŖ(ėļŲâÎøTÍÕδLÎúĢ ŗŦØA‰üÛ3Ō!<\ô=<Ä2€/3Ч°FŲ (<˜ÛĨ¨¨¨JRøā@tŠ­ŧb+3ĢÉŦ7eĶĀYF””ēĄ!ÁĶbGŊAÜŠÉdÁKƒzÉôt)Ĩ)ÕQĀŅC=Š ¤ázČú’ąXĸ Dîé)˜VåˆxC¨JõĐŧĀ Ô›4ķĶĩ“‚I›øbÔCHĘ)Ķ—CV|UÖ ŅYEÔŗb–[ÁB–Tqe&Î*DŽēĢŦ‘KMõĮkÜĢ×ėNzėž7Eĩtŧ*C땂ū”Š—ÄšũųMŅRF~ §5ƒUnUTYũVzJÔr›Kœ DÂ։E5‘Œ, ÕËŦ? Öy]ŌĨđQė* #‰I—ŦB5ĻåkÆQĶu2ÖBD؉ŦĨŅ3TK†…6æŦČw‹3^Š=–ĢšTDžŊD×Ē{ŸjÍÔ÷LօEŠđL‰Û,Z+d--Z}ēUÄ ĨœÔŗ”ÃĪļēØáܧÍY[ÂŌ„ëĢŅš*‹.Æ0Œ I<„ąĨuÎRí@ĨרZšNmP_ŒĄĖŠųpë3ÃŠÆ˛9M™Đ2zC;k\ĩeÚnENŗmší°ĶģTĶ{IdÁļ“ëČ3ŽūÖ -lĸŌ,Û;Vž-IY {­9LвK`ė/š;­<˜ÄČæ1UÅĄ+,SÜķIĘĻTŋųÎËũŅūI[0ŨT6.uĩÖãĪq‹ÛÄpģ ‘?͐\Ķ’ áĶäŅ3ĸĨ\ą Ė{%[S5WÉņõ–Q@bۓ/=0ʋš_÷‹ōKxcHôåIËmŪ:Ëģ•´ŊŪÂ Ņ…ž"•Ž,:YĶ;ˆsā“ÛŨŨÃ`ŒąM}ÁíôXRĐŋ5J/E4"­9=õģmģH>Kálā=SáXŠÎŒH<…ĪcU>āŠ-Ã=B“ܲãŌũk;âōŋ 9ōL‘nūáÆÉ^kÁžmáL­Ō+m[Áą:ˆÃĪ›Ņ`Ãkģ!ƐÆcčģH–!DßK؏õÖΰŧK3ÁëUŒScÕÛ¸qS‰[‰N`ÃĪÜ-93ģÁŠc6`ĄŗâäõJŋ->’D*Ņ}ØÖÍāU“áÛS—;Ö`=–ÜŒķG íYBmZ,ŽãëĘ;Ž‚ße‹_›āLĩC´˙ƒ´ŊP4‡ ;žaWÖMXƒå°lŌ?ÎØ7îIˆŨûŌ%@Ą˛ĩÍX;´āũüJ]ķē[Ķ(“ÜPn”ņ fũË6eėēOÛÁÛib·­U&=H9MCēLKM|đoppJpŖz?đ†Ú56a-mŒUÆā$ŪŊ´āŪĄ>q0ÎŦŦŊËaųvŨ…v͜­ī ‡Ä§ÕVâ/âĘ?ō ŧˆnboãhéT=†ƒĀŦģaMČāÛÛŌNrG‚ūņ“’Ä€ģ Gœq)gË ´ēdiF“/9\v;đzßŨjA Ūåfî×íËĨE'ĪÁ|ciŪ5Ÿr*҈á=‘د.gáų(M0G;[kOf;ņ Đ9ÎĸŽaũ>ĒknE?ķ…’ r$ŸĖyē8?ˆ7—sK—ė‰:ÕOîŌ‹ÃōÁđ¯ŪüRžšŪ8=x5̃Ø&UrĀeœČyĸ›LšŒö ’KŋuL/—:O–DJęãԈ”ÔHæĀü@BaCJƒo3GëXarÜĩ°.­Žŗ"á”í°u\ßöŠUŪŨĻɒØdĒŪ4JČR8KÂqŠZĻē]ņ+Žg¯3Ŧˆ:ƒū˜õ„8{ųnßwiyëÜ)¨ž¤ĨúDģr‘ޘ˛ĘHˆxĮ‡¤Úŋ^vįąxŋŽXŋwjŋ÷|Īx~ßx;Ŗ0ũÃy&ö‰h‘÷YĒUl6­ŅÁje_tōsēõą¸„Āw~ĄyŽĪųŲŲž™Öm/Ãî[b$øĞ"ŦšI"īøŪæVoĨ‰Ŧyâ}ŦõČRÉöéčīú—ĶŽņ,zI:öÂVZ{ôú ŗ’Āŗë?ŽÃ93ŪDĀÚwųˆ_rÍ_Ūŋ~\Ō_V~+a+§9÷Ēā1nŊčÍ6ɇØxūĘxUîčgô4—HĩzėŸ ëŸģFcGÁ:=@dmˆDˆX ÁE(4ˆĄA…%&\8ņ!CŒ/jĘą#ȇ+†”h˛‰”*W˛léō%˘2gŌ|š &N•rōėéķ'Đ B‡-jô(RŸ H~ôB €¨ ŖJ-(UbT=PUču ūEĒŠ‚]ĩĒU°WąJėō I‘o›2å(w.ŨēzIRD™ô/ā•7‡~lø0âĊ3n siS“q=xĨüq2ŧ ēEXV„‡„™Agl(˛C[‚nã €ĩ\‡°íę92/îÛēŪ59Ø1đ˜ŋī nü8ōäĘ—Ģ„ŧҞÔ"C^}zE¯ C,ûûFŦ,īf‚úÔģžĄÛæ­žļû÷{Ë÷&é—9đáA Įä˙?€ 8`JÎeRgœ…]iuÆwÕ1č҃č=X‘uŌ•ājÜi¸Ņ…Í|xŅG[‰}˜”‚­ø"Œ1Ę8# 6X–t|]FūxŖi÷#„>j'š¤Q” GCZáEŌ&߉yE™‰æŲG#Q-Ū§R‹Xzų%˜aūdcw€āŽIÂ5QgŪíEžGBdœ ĸ×V nQ•RVŲž‰}–į›˜Aq€R—…*ē(Ŗb’ų”™nŌeeZ™šĨÛåÉZei}ôYw›iXĐdsúi•ĒŠbĒōEÆÔ–Ōkĸ˛Úz+ŽČ؈gūųéVMš֎YÚÁkĄš”ĄmqĩUž¯NäÚˆĢ˛:%ļîąkŽ\SqŨŠ;.šF=JY¤ ĄšŦ§ĄšEÖTWÁ›V´Dē‰õYUYÆgąSW­ĢŲZūK°š qKŽ~$ÔZ.ÄK,ĶŽžiŌŊ×eŧžQûnz™6t^Dju÷•ģę0’ } čĩ‚Ę|đ¤WFüÁÂ,…;1Ī=CühȞĨ ¯Vl*˛bŊ;/XĄ!k*Įe*-›lB‹æā5CIŗÁķ6ZÎŨ—čÎ>›}ļ­6^ȝuYE×1Šp „ÚÆO¯ °ŠZ}Ėą[hžũĐÜHÎ}ۅhÂ\"Š]Į<א"„-f—…qĐ0ڕ[ŽkÅWkÖPY\íģqZÉzîļURŗ›4ÕûÂu–AŖC„ĻŨų¯Ÿ[Ûž¸×Ēn‹k­”_ū;đŽ"^ä‚×)yā"bךˑĄ;Z—ūąjƒ zxí‰s=sÂ!ø.kaˆ?>ų_>JiIęÚui_׿"ņ õWä!Xš‰ÄîÁØûĪ=îvĮ;•¯€„QÅ\ļ Re¤eÛÍsv"ÖFNZ ˆîw;ÜioƒĢEž×(ß=ė€&u¨ ũéLƒšŌĢ6u¨Ų,kŠ™]EnfŧūĐ¤ÕŠ™Ē,ɤĒ2ÅČąĪéK˜Ŗk*=ŗˆ,#ļA…ŽŖÍėNÛÁ.ĸöOLfĄxyÖŪļÉ #…ĘŒ’Ŧ;ÖY&D3—xŽđĄEŗ”:ámgÍāuG˛S˛ aéS˙β%Ī]ɍŗģíû›āõL\ÂëÍ÷ÖÁĖp„ųÛk>é2ķœëbnęŨœúF0–Û"9•čA­v‘Ē]&4čĘwŗ÷­b…I›liîqÁŒķŗ„r øÎmŽĄ8įļ8ŌU˜0_SË4PƚM“2y˙-НųØĶŧ(ĪØōI”Ĩ'3€æÄl†ę˜kb8C:ܗūŠ5ÖŠKĒÃlhLŅ:—[™íÂuÜčΚ{ņ‰+sL“áPķ_Í<jwL A:@¸{[é DĶc "ēÜiŠnÅČb'iPj8!NēéŊĄŽČBV´Õ\ņŒŠēsĘĶžaž´KūJ$'ØÄy‹ÂÕĄ‘2šĮõ=p6U[7ũ-ØŗëņĘŅĐÅĨíڇĶōPÔeĸ÷V$y†¯oGä^+厖aīŗOl--ȖĻF›äПTšÃĩ>“*˙¨ē[žl>2>”Ö ũŲ qßęE‰ĖkÄßq]ÃIŒĘIY…¨ xœFũUJ‘Įá}ˆ^™ØĀ|˜zI÷”ī)^Ųūĩ^Ј€´ČÛÁ˛ũeŊ{iͯČPé]iPf<ō  !–ĄÍŧˆĪĄMôŊ 8…Ī8€Ą9ĄĒEáĄIáPá^!f!janĄVĄĒ%bá~av!rĄš!ĻaŽĄÆáFq´ČNžæáŒ8€„ķu öĄ Žā™Í1`åâ .ĸaœ#žđŒÍ#NâbÜRu饎ĪRâM߀đG¸lĸŦé‡'rĸ)BŪ­J:ĸ´ĸ+Ž ø@Ú*Ļ„ŧĸ-ŲŅm@\Āų›đâKü" hDđXL@ųhÉ2*â->ãūŦ¤„LĀ@€ĄX0^Āü"dĀ0ZlĀ€c5j@2’(c2^# ´ã;*ã‰â¸Đ#4Ū#Kø1f@¸ŖKd@d\€XĀ.bĀ7¤<@d€@5f@:¤@fĀčâ7^d:=ŠËo”">†$€ dAÆD:&#$Āč";*c9’@Äã;&€ãKb€tŖ:¤<–O…$P ”_pŖ5FœJ¤#NĻDJNŖLv#ÄäIöä`Dr#U^Ā0eųt$š€dPâ#€]9ʄCN@LVŖŦd4¤K‚cLnMn$ ĀĨYÎĨJBeOjūâ ų‡W~Ĩ-> cf^ÚX8!b_æJŦ$Ą_Šäėą„D Ļ.cūÎ}$ĻG6ĻfFŖÅ%Š3ōL nĻhēÄg&•pĨÄ`æhNbiĒUhĸjŽ&%ļĻ@ą"$ÅĻlę!m–j:`næænŠ“ŊQoūĻ g@Ib§qęf܅Se6'kĸKÔâ#E§tē"rēQĸ0gĪnf'õmįmŠZxēyŠ'Ļg…™Á)‘rĒį=˛'wūäŲ§|B#}&‘{:\~ū§Ųė'|î€¨Ī¨ Ra§Ž'b%~^'‚6čšMčåôŽ@Å'…rĸ…ūN&VœIA܆ūšb‡V_"ÜyލŠĘH‰ĪŽ(Œ.’jŲĻiÆčtÎ(Å}—.-Ļ.b‹ZŽwFbrhmvWzč)I%ŠĪ„fŠĪ“*éa1išt "J)–Ū •ŽK nŠŲDi–.éaŊhr†é ziŽXéĀE ™§ZéVļiĸ) ^⚮ƒĘ)s€ipŒļâø°ĪŅŠ¸„‹䊞žŸ6†–ĸ ”g.ę娚!œ&jbHęÚĄD§%Qj¨˜žĄbLJ~K§iĒ?Մ_,כēÄĨ’ĒI•Úc.#ĪЃڊ­Âǎá ĻĄĒ˜ŨĒâisĻޞ™gЍ§ū„áĖū‡+–Xá&Z´NĢ´V+ĩ^Ģĩf+ļ6aĩ&š´nĢļ†+¸ŽĢ¸–+šžkĩ"kŽÖ*RÅĘ` ĒŗæĮpÍ+ŊÖëõõ–ˆĀמeŌū‰Ū†äĢFŒ@ ڏŊŦÁ,å„˨†™™Ŗ>æÃF[ÄĒuŨÂLŦÃf,˛bėÆj,ÄzėŦĘæRčm™Éž‡‰u&=Ėđņ –öᆠÖėɖ,ĘĸQäu ŧ:ĸųjŧAŨĢĢüTĒĐ]I\„G{ʇUíˆ1Íím\i*˜jŒ¨"$>Ú-õlXĄ`,ÍW]Ŧz ÔĖTŠ’ß]YÎū!7ŲĢ2ĒQƧiíŲôŦ+J ŲeŲũˆ`Sdˆėtlu_éuŠx4Žü`ßv”mú…ÕG‰ĒēŽWQ-Ŧrî-’mŽ•Ė4ØųMö4ŽXt†IĘŌÖĶ åfŲ­ëĄØ•RœØ*†į&F(šį‹•js îę™mn˜FĮP†áģt–ī1SšP‡ŗčÔĨ,Ÿ‚VÃä­Žtkb¯ˇf/÷n¯÷.Z÷‚¯j¯øž¯§}oúĸ¯ųޝûļ/ü†īû>á'č:›ôá@đOąé‹Ę žvøÚ¯]ęŧ1ĨE0Ą˙2ŨęÛ[đ!ĸŊ§ĸ„ÔŪ,ËÚlŨ˛JÜÎvđū[0{p'ŸD8Āí&]čĘ.,šÅŗÄ'ŠO߸ Ū ÄËA^iE ̌Ô=Ų¸å”ģdĩŒĮ^,^˙ˆ@§~€õ&G°žÕ’ˆņëĀÔ ÆÕl…ápĘø1ÄšŠ† 1ņ”čIíĨđā†Ōš˜\ę~\UųīßÜÍAĩČ-D4uE¨\’ū@-ë5p§†ąŽqčíë6ÎøũŲîMîáĒIÛß žŌđ1í/ūǟˆí/ķúZCąTܘœēÔ ËŠ'›Ei…ß(ŽōQōEp*ŽĻŠŠÕŦŲúfåEdm Fĩ"ƒ–{m ’(îÚî`#JB@2åŨī ūrŸ<„ūë,”ą°&Ë ¯ŌŪČņ–ĮdØ$[n•`§ÉĒØôÔ!ŊŦˆMî‚hāĖÖ +U`k(w$GŨE•qëąũ’ą=—•Tؑ„Uf|‡hÜÛųÍNēŗô$OåŪķG\!įÆû1îdņë ō ŪõQO˙åŪ`ąœėr6_Ąü&1 Ą6ãÅÔvßÍN–UIx ÂÁŌlB4ApkæbŽ+ ¯œp('ĖŦn^ņtËu !ũ™dč…%›WŠDsÜŨs1ëNe”āŌ2 ûR‚×´ Wû3*MÃLí’Ë *gVRģ5ÃŪuR˙*0á•ū ëÄõ QÅkHRįČĶ4’95 ãqTŸ˛ũųWË ŗ,ndž,ßQCņūvI'Ο†lŽÜ¯ĩWęzÛŨß{JŌđ‹Œˇ5Ŋ,y’‹Č;đÃK[rë šq6Ā÷}đ‘coĩģÃ9īĄßžŽ__°Î#ÆũVJSÕē­ķųĀ3ú•Ŗ:ø Ķá/z­ƒ?y3yĢĢvûūe‘?˙ĒúĒ#:Ëu=pb3,O/`„ˆ"ča Á‚ 2\Hp`D…"N´ņaCŒ3>ÜČūäE‘;. qeJ•+YļtųfL™$@lØ9æôŲS§Î>„ā9čO¤<™ =J4¨SFŖūä9°)Ђ9ŠZJđ¨VŒP‘Šč@bV´`ƒblhrf\šséÖĩ{o^˜ 4āûˇĀ~ \˜īaž„/8lxpâÁŒ!#öë€ō寚+Ļ,ņcЛ‹Ųô辎IcŽlŲseŌziמģ€ãÕ§Bˇ† ëA-W’@ŅfŨ=kTļlG~tíÕå$}ķî°´hŲéŋ ŅucÂpm—7}zē5CTôø~|ųķßIŋžGņņ÷÷˙ĀūųČS@ŧØĢ(9ĸS :ļ„#j9†úę§ĩ皊¨ˆ¤ËpB +ĢÃäĻĪģŪ ķ)!Kp8‰D°Āeœ‘Æ–¸ŽŖ‹4Ú1$u Iŋ…ėČE ‘?“rɝlJkœr%ÜęCŌ>‚F N'R˛=’< IB‘ŗEŽx< JäĖ"SĄ1 ÂōMˇĐ$ķĖ9÷ĶH8ŠÂ“’Ę@ôļá ŊéĐ:bĶĐ<įdčˉŽ+2΁E4MøÍņž2Ë4´Ķ E’ŋR%”FöîËQ:R?ĩTP=OÂW[.,ųf…ĪVNßku?NE•Øbĩ˛Ą0á\Ôū-/“U(Xč„HΆÆÜsŖk roTäŒĩÖnÁí6\WŅÔaUY_}l/Xs}w^Yį}—\ Ë-UI&§-RŨu=ܞEč+6mUÖ­0]LhŌ‰$ĸŗ_lĶ,rIaŨUŪŽų­—ã‘ ˜`ÛjĸWR&E>7d”?Öĩ͕īÍ/Ôđęä’uŪšĐ4sˇ„7Ķ}íŧXĸ¯ŠŽˆ[‡Vz"ĄZn]ĒŪ˜eqsæų.ƒg&R$ĢŗY\Ŗ'NÔc—Ģ&Û^œš~îByhCķÕK;yTö;ŠŖļo5Į’ĢĢyÚí´×Ö7q™ˇŽ[Ž“Å&H[Å'ˇūŧėzŊũķ´ŽöqČE/š]2éŽ{8Ąœ“GmļŽˇ )¨Zˇ”F’ˇĻS‡ļqĩī\fRC}/{W°öぞųĩ§æŧųį1ū“øęE÷:<ē•Fą7ÛjKģ뤒Č(ģąÃߔH¨ŸUžųßãŋú÷á­gIōĖ-ēš˙ą—šEY‚â÷ČîNĘÔū¤DŋȐ}/ėLg>ãŠQŽvōŖår[?IZ0(1ôN ;āû8’ÃͅÜō‘ļŪ/…R§õLÛEGgĨœŽ3¤Õä<ƒ*¤P–ŠvŦÚWč(ōYĘx{Ôpdz+ũp“h¯JHō’ŠĶ‰Ö“§ĸ3ã=˙GQĸ–õyE%ëËFšTˇ–ōuÚI#Ō´^Ū•‘™ĒÜĐ â(Ųa j2ė(Zŋ°BŽ’ũĒūÖúĶ6öŦK:ę[)[".ugÂŽvé"lô:~ mŖĘšŠ B•r;šV˛HČØzUą=ėÎ>’ŋ,€5 P€`ĶÛ՜Æ/¨!ÍjūĸŌ8FILūr=Ŗšā.€€q@r?ķ[ĮdF¸ÖulŦģĶÄ&ģÜÅmc*[^š”.E @]ŖŒdÁeIaOÛ!ŖĨŌÚé¤Z8€ëč QĩÆÖą–›-Ü ÖËVSœh3pÅ’Cē¯ÔĶ)ėCŪÉP dÚŌČĖÛá˜Ā“:ë…"­2ÁģUÅŊLJoRÄ>¨Ģ~ę/H!+TŅŧØĒ,l~ėa~J°`/2-Rya4Ķƒ×€ÚzĘU’°\šäJņmeŸ~ŠĄAō•™Úo–\'.˛1˛7.,FüļšaLÂ#Kļ—^˛ŊsgAû%?ú…ĖĢĘR@”ū m[ßmwé3ĸĪÂA).ƒž Tp éŨŅîh)†mW×LŅ6s­&čÔŨŪā4áŖT‡g쨞úÜHW—Ö¯–uŦi=kōŅ´$xrĄĄ|ĮáL —PKâ—yeĘ]šƒdj“Í^Â';–'=;=šO—ėÉo&RQž5ŊQ9ęÂŲüĻM„<ÎE.™öO¯”Üvķx8׿5ba…MY&Ĩ–æ[´wÉ=đí•*Ēå˛ü+„ŠŲưŊŧu†Ŋ×ÍlûcvĪôÁ_ƒíâ"QڎÜį1Ģ ĐųBwŽįåVÎZ8dˆB]ʨŊĻöšāŦuDĶb1ņ”SáhŽļ˙ū^˛e\{֚ĩŦ–MNĨRoēõ_4Ŧ}æļŽúÔĨūęôŧä<3eŧ†î÷8Ø,eÚ”ÃÆŌ%Ŧy3ė†ĀÚ´ÃÉČđb׈õ KFQoiŋ>;°y´Ôá˛Ę?Ræh?$°JĮ2€ŪŸÆ™w.Ėē‡+™7L-=—ShŠÂÉFŌËŠĘĢ÷yî‰Ũ‡8d*›īCG˙#R:¸øØã-zqöŧg? øžČ—ÅúÉĖ”iļ‚ÄcoŒ_“ÔˇäWŠ Õd95Ķ6—°ÄP¨zēËËøÆ:Ųj͞^IŸVųW^åŗSķG[|Š­äS¸ŅYūβōđS:'Iøo,ôREÄL/XŽãžČ-éfÜŦrxéú0›>Oų -"d ôŧĪÈ˙ˆ…ˆÜŅ*âĘŽCÄâBڂ„”íØFũ˛ˆœūĖŋhėû,Š­ú˛ā + ŽZĖŽđā āNį¤fZü†é|š.-ĩädŲ:â÷^đ-QErė*lØ´lƒ|ū’nã‚æpƂŽĸíi°”ÕšPĨšNįŲöŖrĐÎHÚOcüĢũ2ÂÅ(đd $p+ĀäZĻĸĒËÆŒ‰ Íđ”§ØĀÉob'´.‰úũ‘'pBvjOâ*í¤íE*ːJ’¯' eūūxâšD|vC7ūH–”b-´#}ŽĸZZPí ĪrŽĶ21PžpŨnG†Îų Õ*Z:/Ŗ(Z’P i1GbP‘*ąôní°ĖŲī#8(ūÄ$‹čĢ- 襹ÁéL˜Ēķ âĖ Đ‘vÎŖlqõĒÁŽTúĨjåR%,ņM‡ccQ A‰ Đqeä˛Z‹M$(„Ę'v¸‰æ„–Öî K ‡´ĖËĒhpŌ¤ ŅhļâĻ\p ƒÉkīZ*SēŽŊî#ŌmĒėĖiĐĩ¤Å"âÎiŒĖcR˙ąŸ|ÍķĒąoF„ ˇqΝũÂlđ8¨'Ŋl‰ÄiÛëæūÄĀ42õ$Ē#iÄáŦPÆIúd &QĒĨĻ4Oņ %K/ 7’l&‹&KŠÅÉØÖ/š"'d–Ōĸ–NŅ-qÅÅLd.A$E$Ä$åĻíÕé)g$ôKŽîĐâ 0ČēÍ O<žZ’§âēÉvåaâ°HôŲė,™q  $Î#ĘL‹JĨåķoXĘŪĒ*yMęąöQkĖĢ’œ1ņ ‰ )9DÅĻ*w¨‰Šä+˙œˆÚ“mf˛3I‰O’Ŋ°ÅEū%2õÆŨ‘YXD›āîPŦĨãŧ‡ųöjĶĖüĖ̘žqī..sI[ļ"Ûą•øH—HmņŪĶū-ÂĢ)ųˆ’ŗ&OŠûzĖ[ nķzÉKFSĻ/Ž,Ķx,ĢâĪÆrÁŗ  ąŗo€†Oǃ•Ē"(”­ũô¯ņDņK^ėųėÜkÁ\‹,[DBõŗ6@Ė•VMč^ę5ųEúØ)ƒdA“äĮ0-A[拺3?+̘šæõ¤(pMjŽE˜hĒm—zģlņė#đ’1ėxi2?ę>ãÍEų Ŋ†ÂƒDe[âđėˆ­1 C ‹ōėŊÂÃ%÷ ņBˆ6ŗĶ[~’Č"¯´ĐŊ<4RsŠ2H"ŊLĖbÃ~r,-qy3Lƒč˛:‘}ž+m´.ū$ĩp°TjKíl/Oō&`Ņô čĩîR-ŠE ä#S&O+h C(đR!Į¯đMp‚„ŗ"īŅ&ž1…îÔąĖrRëhLwĸ<Š@;ˆËî2ŌēŌY“ZZĶNļķGũLUģ50[•@ Ė+ Ž:šÂÅ6”Åéædī7‘.§C„į 20íS…\\“Õ˛°†Ę•<| 1D[,uvo?ԓ?˛Ã$SÕ[kėŋÔ&_Ķc<ŗF÷ä/3æĨ(҇j§|ŒŠL °RļJMQÍaíul$U_īgYms7#M˂UIũ¨Ëm|ŗ„Æâ†°dwV#ĶĖÚötÎ2O ׯ´ūXĢ ĢRĻĒIá“úÎ j)}6áĀ4eéˆÃŦ`™âoVé+æ Û.Q)įʇ1ĢÕŌ¤ļa–gŠ&bŅCr|ą:'ō$ĻlÛąÕØP¤ÄÉ ;Â$Ą06™’cPļj‰Įׂ–I|ÎJ;”‘,å.}tų€ÃŌVm+ˇg§mĪç˛ĩôļĒŅĨh#pĩē4ãH2Y°ęh3—ĸļ^-Wn‹tp)ŠŪrƒ{āŌAäR• ŖöqāT[›o Wp)mE&sÍ̖(IoĨ‘BëiaîÜîNpŽErčÎ:ĩV„†t‡ĘXßåxc×%NŽÂ和ôĻ:SŽOđS”ūr/÷a3é{mçøÄBũŽÎ¤°94bJ?Å.­¨E.õWX éš*¯ØTxáWf|߉OŲĢ$û.‚k…šōĨå<ķaõ¤ŨŠu™Ö–xa÷­äŠĐpYĀŽËâ%Š"í+-‰;siđPĢ/rc„/l~X%*Īf,/bœķ@ĢWˇÉ‚…îtÔųĻöƒ-ˇxEØ­ÚÅ~—– Ņ{Ū5Ëb„¤CD÷ČB€īÖ ŽHsXpyØÍÅI7›tGņš/ŽāÔ!˛ŌIŪܖ6ËØ‰CØ!v˜6HxĄú•ũ´KôHŌvĐũĀ‘ƒ­cLuâ5ĩ ęŧT˙~„Ņūøz`ęg *d›%:û“ÜŧMléåPK[-mHqX÷8B÷”$Gų?I0‹Ōe/ĩŲBĐũĒPT˛D=+™{ŸIō0™píå0SׄŽ$vP­âF:˜î÷žaįĪdõx•ŗ™Ãʋ=ČN:WņpŖŲm ˇGšĨ0^ąŒ›&2ķX•ņT‡šzÆTīĖĪ ­7¯QȒĖZąĐs—yČĐôAąY˜WŲõĸ~m†[į=HDDWgųö)'M^鐚â4ø;YTžšĻ’yÅ´âB hWĢX™AT`öS´•ĶZEįé ķBUúû°zÍ)3Ĩo?HŽūsÖĻRŽ[K€"å„ŌėKãųŖ3yc´‚vb´ēˆkßīeÕĖ y'•Ni*1™žßš åוŗEelbKč8ÎX‡čσO8 ¯AÅzÎ¸Š‘¯Q’‘%2ZĨzũČš(/(đēCuĨrUņ\Šô8:OĩŠ“Š=ēÔōVŌ3,Õ´nŊ9”cX¸ 8Վ† 1x-lEu›ˇ]™Ms tO8Y’šQ`é€{“*É8˜Ŗp[ķ{“8“ŋšf9or‡úSBsƌ˜ÚbUĀá¸ÁkOÍÛ.ŽÔl0\ž%ŧÛôhŲ3ŅbĖŦ÷ [P?~ÜÁc¯KUjsIûôĖmûÖŅU25Ē0"}[3 Į÷õlj—šš%’Ēø)iFœĪ•ŌÆÉū¨ųˇcZ•ņÕÉĩnŠN8cŦލáÎϞ…ŗ*Ãxeo?ŗZē\ĝR<Š,ĖĪöž‰˜œū';ö,ú÷Ė÷ˆĄņũHO渨šüÎeL7yrŅ3c-ÂŽ¨ī@ũˆ=7ÕPÉ—ÜÆ9æËébëúTíJLQ]ֈ QkgI–­ŒéNl—éx›´†šŧ1gŋGŊX*•e?Û"īæŦ5Ė­ŧ,4˜Ģ‰˜Y@<ŗåģÖAdn}.^5¸%¯›ENZđ&ūrļVopNđgėŽ-ŗ)BEÚ§dYM¸ŗ×Zū~\§}†øĻĶ'pŽáÄŌOj>{ŧYhUwƒTQEd6L4Üw}/o×MgdãhD¤ķz%žsžũß ÄÄŧŊØßÕĒo÷čF w=Ķá5ūõŦPĮ}âĮÅÜ#į‚­qnS˛ €í4š‰ąšūųĢT7FŠí´[Ū˙ĻLĨPVąŒģ‘Îœ:h'ėvŠŽ}Up‰Îi=õ†>.°Į$Ũ:e|4AŊš_8+€ÅxĀc f§÷ÂčĩŲŖš°~]Ž–fõ9Q§´;4~ŪeuĨãĶį˛D°v_Â뉁žsÜ~&Ū–ƒǍũŧÎ ]Ž,îuöŸĢ&#”p>đ‹•å ?<Ē…˛ēä5ŨOæ}Ø žhĪŪ‰.ÄaŅšũ‘4_&^>Æ>÷ôSę3â/Ã1ķnĐׄ§ëLË[˙wüö ĖØvC°8Ŧ•AdĢcIūkŋšSÕûėq[…—øĘøcĸ˜ÆÔņ%Õi§Ã)ÃtĐčEöļÂC $(P„B….X°ĄÃ‰V´HņĸŃ+\@"¤Č‘$Kš<‰2Ĩʕ,[ē| 3ĻL“ ô0ņ`Ĝ<âäČņbœ6ū4¸(Äĸ":,íP4„Ä tŠ1ŖVĒAšfõŠ믝_AÎ<‹6-ɚ!ą)YĻGĮ"œšĩ¨UŸnø÷ęԂDâ5:0.ş„Úqë\ģ”;ļ5Ģ6ŗæÍœ;{.ÉöaۅPũƅŒõAČąRt=‘ĩE¨KĘvˆēiCØ6=ėĖū4˛Øā‘ĩNœ8æĪĖ57°-ú-܍!r?&ޚtĪ܎årĀz/^ĸ´+– x2äՓî~´ˆåÍëÛŋ?f͌˛k¯v8šÁÖÁÄu%BBڅ…‘Rĩ%HŲ@ !'Y{ZHa†dŅ—_‡)…Ô[ŋ™ļ‰! E"A&JÄ"C‰`‹,Öf•iũ•˜b1’(zŅĻXr2Hdeĩqča’J.™YhE 4•RÉ)8€¸…u"]]7 •QõdWy^j„`{eš ß{E’L&ų„YĒ8M5RÔbUCíŖTVúé'C':ļ×  AiCŠĒhpāY¨ĸMūgƗ搗Ŋ‰iϚǴ_[R‰()Smõ—ŨP Î9G…ĩ¨S‚¨ÂHŅhėyTšļ˛š&ĨšĒi—››Úį¤ĢFuiŖ1&JÚi-NŖT{؝°FēcŸvÆÚh™|•ë¤ēĸųҝâŽËd°†M'Öwɖ(ŸQc‰cĸŒ¸TbΊX€Øîę­ˇâĘošž’ëYœ{Fhm(ĘĒ͌.Ūe,˛à ¨c8u䈄-õ›{…VÚ-ČE^JpÉ&ÖiTŌáu°¨§—˜°.c;oąŨŊ*á´2g„^Ģ"crĐ@\äĀ'7Iŗ¨0úuãŠLģØoז˜â§ ģô‹ŸÆ,ū‰žáøâCÄjÛ1¯Â t¸G¯ÍļLÁļj_7ƒmcC„.*#Ą/žlį‹sŒlģ0{t+ĀCū­álŨöLS鯖ņ%ꃂ÷gåQTYû§VT–ĻØ„+.$ږŲÄxãĒŗōF"žgŗnÂj7Ū‘ (ō :mžøöTF‡Y—ŗŋC"^ē鉧žēKNFæXRb%øäą)UvvҤĪHuŲ}Uc&OēņsŠŨ|úĢ ›DN‰—õ_ģ)j÷îS #Š‚ŪįŽĢá~ Û¸īJÆ1[âhĀãáŠyę+ÉF§5mŽ€yáVš$¸ #åeW$Ũŋȗ88⁠ū,áŅZw=ŊKB1[Å0Ļ"Á+w0ŦÂ|$ ˛yīƒTā}¨š&Ü ˆÄ$'gJlĸŸÅ(~i>CŦ"ÁŪ6ēŌÄĢYK›ŖRä°Ūmņ/ö‹Ÿ—XĢ—UOƒ…C ÍG4!ZQ$ °xē<â„ÚÛcF,čG@ūņŽƒÔã$Į9*eØÛī’B8SĨ^\ĖY:kå!-Ũ˜úĨŧūĖYIäÍåžĒ’B[)ŒĐ‡ĀU^•Ū ‰ËrŌ:)ęÜår̃m˛Šä#!RĢļ9p„ĨgJ+6` ˜Ļ5ā€jjsšŲŧūĻ7ĩŲÍmbSœÜ$§9ÃyMt‚ĶœßTg9ÛÉNqēsœđüf=åyÎun“$ĖĨ?īƒÂ}mƒãģ‰Īwę|%!ˇaŠl´÷ žq”?ŦT4˙‰ŅŒŠ¤ŸíhgPyģrkBcŌ'Ŋt“ëyę'súåCH &S}Ī™e(‡sŅ!r 9õ¨OĒ–Öå]Ņœ¤*Y¯]­’OkŒ*S üf4R[ãDoZShĩŠĶėiG9ēÕ°Ž„}t Lm"¸MÍJbĒä‹69?üd“ĀLO^\$›ŌĢ|ŨˆWÅꡝ†ä ˜æ`‹ØÄžE¨ AØ•lkĒĄēMūĖn&ĨŊ°†[´Ŗˆ™¯W’˛¯Î_{*€°$8-j_ĢQT&]Ί Ũäį'Vå-kĸãڎj—°gm/|Žäh÷ŠÜŌēļáhHđÜå2wēŠdlYE(Ũ–ˆvąë˛jh-}WgžÛnqŽQ^5šĮUˆtŠËŗČžôE-!&/ÚAkrvËív+&YŦKgŲ}!‘9Ģ4–íƒÍ,-iuõŪúĸ…Ŗ–°…‡ÂÚ &OV™lSœ0)Ė‹å…_Žđ{ fÅGną‹ÛëŪ g Ŧ­•ąŠJWʍjt#1m×]ü9MČ*ĢZ‰ú¨2?Ē÷Ázmq…ūoė6(KŖ(Ŧ‹Ī(ëT9AJ™Ņ\JQŠVۈ|QjpŗŠf~=yĘ(ëšŲ į$Ŋ­]ZÛä¸ôĨČ•>o7˜›2hÁ \2{›ŧŧ8ŋé͊nt}Ššž õ’ÄaŠ@{Ŗ8ARŌ¸ĀLī3áŗŪ;„ŅŽMŠO­:," @Ëä‰ĻŖĸTI†ĒŽ,d0E‹č\‡:9¤FuHzíë`ģ­r~ŠSõS˜ōo+škĘÔĒk"qZLģŽ6“q*l€f{Ûâ2×l?öĢD_§b*ÚPūi8-uĩßŊ!n7ØōŽ7hôŧ2cĘ@)­WĢŊčjˇ—Ķ„÷ĩĶūŒ!zŸZáönø}ĨBTɏj† [íÔS>ą×¸¯>´Á=^ʆTä$ĮO@Ëž¤H+cŗRžÆ+gKD˛ĩA~đ—ŧI;ī9#˙g^Đš%~ģ9–ŗ|ōČ™Ų ”<Û™în„ģ›áŽĻēĪ}ač¨P^vÖîíŒtzRP?soõ5Y]ŅkŋzŠī Yۊ‡DFīYļR%âOˇq˜RG;ŒEŲv8Ūílo$šY=3:;*sa‘9ŒËū÷§Ŋ=ƒŸrå Īfok’OŋŗÕJÉĀáÜé“/}äEvy(§ķĒßcčqs•AŽŽĨËũÎāžã^ō:gũKVīū{ƒ´ŲN]æŋeũ%.q‹™9'Ŋéwpā ?øÔg c‹­CŽeo‰ÁáAŨüBC?ün”ū…Í_}ø’âfMÍÍ´s/ķxß] 6ûÆÉ?ūäĸ_ÂûO?s­›odQFBU„nŗĻ3×wf–Ī7ũG_čö% ĸ×r[ŗy•nĸâxfļk Č{~'ÔU‚ˆXÖÅ~zBĶBv~ŌV%Į|&‚ēgp'ø(胭ĩ/â51úe#f+Ôƒ˜€6ˆkzį€:(0?x<(…8Ö%×a/Yb1ãu5`]RČÄ8ˆ#xTøZhX…•c”Awū'?`f”Å õį„âw‡ xzaĄ†ŠÕ‡kHeI<&exįöeŸ%G8zcˇ€e… ņ‡)ˆÕ7gÁá Bm›W›ÔI­"h‘ö„‹hhĸx“(‘hŠ‹i”ÆTî<9A˙•ƒŽ(ZfHQ¨(V瘊V¤j´lY& •4Œ›—%?ņo—6ŠĄ¸w¸Wŧ¸UĐØ‹&$TŸōXOĸqQU!äæ}B'Rˇh‹bŽ$86˜§yq“*1ŗ'^á)_1‰øU‹ĸX“WŽ>•įØ<ŒqD•% ĮoâĈ]]zĩ˛‡¤˜‡¸Č‡Ŋ¸ü˜jAhĩE^{ņū5ļ%sh4&v—{㸐xčŒT”Š)‘msrėˇa0Ŗ[Å+uņ…ŗĮŽFՌ 9’Ëxz&™Q:y’'ôC'Ņâcüŗ5d´.:p5i U$vtvY“ĸȓ˙4•=Y2YG{Cáu?[ƒN‚PãSˆ éw÷ai•;wO5$æ>&%&A1ƒŠĄÄn7Ї8ŲAU™K€š–ŨV––C9ąFŗ8;Ã@„čyį3Pf •.&˜Ē8˜$§y´FBmˇ×l9({–4 Hm5™!‰šQ™Õu™"PM%P•ˆ“P¨ÂD×%åVp|yšēļš§Ôšūwtˆ…OB$I92ŽčPA(Éx…ÎחŊ‰m%œöv}ęU‰LšŠGļyndų Äuw7ȌåIJŋé‹ÕYoëW‘šÉ‰ŽQ[ņ2cω6‘‰°¸„v!žåÛũ™+čYEĒž€ŽÕŽzē?Z—^jUŊŅ._ˆ= –‡ŅéŸJĘm˛#•#s'qØ7žU-VsY0Â7čÆ+G•ĐiĄø‡Ą%ŖúhØŗ‚ė">ŊŸŽswļe,E(0ɝĸck/&Î8Ŗę“¤4úsÍyR5Lƒņ¸_æÅĸyÂ]ŗÖZúĸ6éˆKڏL*lY§|ö=đC.¨•ūĻ2#,ÚE›6+RU¤]jžˆĻë#ĻÁֆŅKF8qS5`$#’5C!Ō-Pú‘^Ǎv§Š–§X'ˆĒLLĨ| U{rą`@nøŠO韋ꍩaŠjpgHM)†š¸Ÿa™JG§Š)ĸŠ’¤ēp"‰8Į}‘‰nI$b‰Ģ ĢĮAĢŦcĢo§Œäy^zGvdeŸZ§ĄVŦk3­Įú{ŒØ„ē÷I›ds“¨Ņ ­”R­'3ŽÖj}ÉĒ<’zá™ĸy{Ãz¤˙Š–æg)™­¤čg¤¯á ¯iVŽWI¯õŠŽžēˆä›ÉŲHÁ Žfų¯W°‚‡­.Š–’ūTīúIā(ŦņJ’Ļذ;„E›æK#+˛%K˛'+˛Ē…0e˛-‹˛/ë˛1 ŗ3 ;.6ëątĔRÄŗ=ÛyŠäŗA+´CĢD˜Ac(ˆŗ9 ]ĨBŗM+ŗO;˛1=NKĩPkĩUKĩIģ)ZëąÖäĩՄNÖļ`ģMb[ļdûĩ 0ļj{ļl›ļî”ļÔNh‹MŪ´ļwÛļxûļyˡ{ëˇÕdļ[XĪEJ{cGk¸ˆë\k¸$ XUä\Š+a’›~ŒÛ¸‹´SŦuš¸dš9û¸–I¸üe”K}ģšVÄZĻ[…Ē{ēC]$Aē­k2Ŧ+ģéŖš5öąĩĻēk̘ūąąËģŧbzģ!ŅĀ;ŧŨ–ŧbēŋļQËkŦĐĢĄËQŧŌ{BÖĢžF{ŠØK­Ü;˜$DŊÆ+ēŪë°ä;˜ĮûŧĐežÂģž'‰$ÔŧíĢ)´+ŋ‹fOÜTŋŋBŋų[2ČËŋžąŋ˙›$$„žŧĩ,‘ņ‹Āå˛ĀŠž&ņš ,LÁËĀŒÁūtÁĖÁĀŲÁ(øĀœ,›A”XÂ(Č œÂÜÂÕįŋ/ŧX2LÃyzÂÕ͓Èõš;|7\Ã.ąS6Á“ÄęÃ%SÄ,ÄiqÄÁYˇņdORLÅSlÅUOX|Å[ŦÅ]ĖÅ_ėÅTŦMOŒ2Mŧ6ū ^DĢÆkĖÆmėÆN\¸f<욨qDHw\¤gĸĮ}œĮlH~Č_âLŧētLŽ™ôÆ‹Ü Œėȏ,mdėˆ\2q’L€ŒĮƒŦɯJP™ėÉ{ŒÉ ŧɃĮį(Ƀ™™ģ2ƒÁ#Žąl˛‰gUō%}DË˙ŅgŌE "!LĶ2ÆčI EkNT3ø0īĘwaČRxĘki¯äYņ͊4č˜”#vi5Kãi[q‚ÁEa3,īg ĸ…I—Ö#ėą—J“Ė?¸ĖViĒfĶ0>úĖĻŲgsįœËæ&å!S#sgĸJĄR+\gО¤aƒ›ŗÎ>ØÎ=ŲūˆƒOL†5fd5u'¨ ­ŅÍEDwĐmŅyĶaÍR-~ķĪ'¨Ú\TŅĐHKÉWÉŌ˙âÍo‡'†ŌD‡ŅAŅšŧĶ"ũ09}Í@}Í;ŨEZƒ"]cĐOķĶFmˉi/=íž›|W7'ũĪEiÔG5ZŌÕâ§ZŨrcäĶ[ũ[oÚ7#ęZÔ2’Ī =RŊ¸1}E3Ŋ|÷Öƒ1v3UũĶzŌR%¨ÜcĐCmÔ9ŨĶØ\‰'}}ÖjŦ:Aוk×äŅ")ÖZ}b ũ4&ĒŅ'ÆÕÂÕ4N¨]„‘ŌL}Ú~Ũx­ ŲĘøČlʗ}ŗĻ7Aū–Ûų ´I ´PÔV5}ǜ†D|‡6PAÕAeÛŋ˛Âõ|ĩĪĩĐŨ4¤\ĩ߁FŌŨ4û •ÂËŊ)¤™?[Üã-Ū´Ûļö*œ ™ËÆÛJdÜFtŪä“ÜNėŨß͉„¤dsĒßr­&ÕSm˛ˆßsĒĢ{Ŋ7Įõũ&hü­ >†Đ9Ё–RBÜĘĘCöWˇ4ķmʅENk ¸ô¸ūĩŨâ>â"îáNâtkâ÷Ëâī”NŪTâ/Nã+îļ"ūá6^ã(Ūļ^Mĩā˜ōŊ ÉEŽ%í EiläA[Ü]ēA.ät%ȟ<åĸœßU>mVŽåXŽÉčsāPî!„õ“ūƙüL>Ŗlgž™ųũ6{ÄĖĩ *[ĪîâĘĸ1ĖSÄ´LĢąŦ—“1>Ã`ž$ĖžŠ%ŪÉPx!f<”&eA$uŪÄÔ9ķÉčSDæBŲ@Nčp˛/sy+ôlkiÎŪW áeiÅ*žĖWRą]"ΈɝĻ¯NéāQ ęĄŪ!u4ĄûYDTՊ|V`ļé}^:ÖŌÆšŽÂrxī’9žJiv,āŌV‚>ܞŠ P6ėgķĖ2Ųad-”Wé ëū‚’Ō*ĩbtQĨ>*1Éĸ\$&*ũJ@áä?ėër+ Â.Ą—jŖØ’r†Úū'8aYؘaé–cųEVē ‰Â,r'¨˛;YÆØqM4MŪëPEaã.Ђ#ūL,ōœ€1âEH,Ö×ddtlę?gŠ#†ņWŖˆS:;v•būEėčũīžįíĻ8äMq Ąōãîœ>f/L?#˛V[ibH÷…ęn^áCvķ“]--Ū55x9CuČ]ķ¸é"ĐôŦ÷ôkø@ `đ>pTQFĖÂc\Ŗuļ5Ņû#Öb˛čk˙_ļ'ŋ……:âB˛SŅŨŒwrģÁfAșđsŽ&˙ëí^ĸ ÚöūBæÕ?Ūņõ]H/Vę†Â;Jú\úHBūŠ™ @[ŲRĄTüSChŠ;Låų„W÷€ˆ÷/ŸÉąú;Š;ģ•īDyŅšîŦ—5\^3(rxīb¤Ō^pˆ'3 øĩ$÷%úÍîãė ŦšÎčȇta:ĘV<”ø—V›“ö Đž!B`ˆEĶLđG‚Ŧ™%ÁŽ8áŅrØø,Žo‘Ęš'kDUÚŲDã]īFŌĢGØÂ7ŲÉpū"”Įņ{JyĐø™ø-†uwBj&˜Å-̃°ŦÕë¸Éő'f"čg{2’ “&žpi"Mŋõž!„n íÃ8āÉ÷"ÜkÖy ¤ĀŪųQ,giMi'Ä,ĢhIÉöķ “­â ë>ŪK…ŧf™8֐‰áúŽģEĻ1O[ŽJ+âCÕ l@ ŪíĻÃ˜ĪŒqË֊62^5›ų$gÆIŖŲÃe7ŗŲ÷i†'E-ë€Q™'|‹eĕö-Äą ,Ęļ‰Ų’îjõxŪšv7ŧßmī‘įÛänN§ŦЁ“Ē“Ļb]nj›Īp¯åĄÜä1…ÅBqyįÃí¤Ccq+u—œ EdqíWâ2¯Ö!9Éu=u‘ģ;×'Įz› ”-l Öluã5ņrMÜ]N;ܰ…8´U˛€ÚvO? 9ĻĨ…íA’ŌŠĪ}nŽëėã×uŊŠ>øŦ~%Ōë:°"ļūä‰ū4¸S:Í …Ēĸ°–ÉŦÎųØĶžy¸w8æ ˛Ú,™ę˛hģPj‰1øŸsŦŗ§—„Ø6IČ ?{“ė¤A7ąfæË‡bU¤Cß}ÆÔ>,ÚZM_Įü͜›÷XžÍpvįl>Ë(ŠkĮúĢ0pxœ’uĶŪûp‹ęÜ u´™÷‹›Î nՔ{%؍Mfn)ÕŌ˛ Ü žĘ}™H-@_R%ŖÅį'§s=˜xŊī3Ā’  Ķ´e)Ŗ` íĄÓmsˆĶI5búŗf3ˇIÉØY Ú"[r"Y=ˇiŊŽ(Āa;Āđ€ęqŸéĒ yIŸĀa–LūđžKĩŒã9˛ tĖxŸãĨĢz ŠØ$l¤ÂŦ Âč‘V!%“2¸1UÃAe"0Žá(&3ÂMą ęA Ō Lĸ˛éģ*¤ÃRR!ķë°-B Ŋ;ž,c$ūX#ōŖ'ÅÁ›Ī›ŠŖŦ8ú˛Ļcɨl&™ĸŠoē) ų ”ēɑ<Ę­"ŒĖË,ßĸĒAá=¤¨{9?ĄƒĒšŒČkŽŗ¨É́ļ|ҜTCŠÄËfr3Ė Ō'’Ą­ß;žøúËōs¤ē˜w)ģ0–vĒ;ˆëĘūōƒŖt4ĘdR‹:'ÍÃ/•ĖËΝŪâJ“Ž`Jŋ‘|šTĄ´˜|KSĄE›RaL咧—ĶŊĒ8Ŋ˜Ã˜šô$zžâKÎôĖát›ö*e1„›!;°ĻČ mƒR„Fã á™F>i‹ņXÎ!šE‘˛'ŦĪĢú"üŌ/eŊi‘KC¤DąÎÛ!ˆđĄ× @)7t˛ŧ ,ÃJT“ ¨Š‹.¤+åŌ4,GņÁRĸXRX+ˆĶCõÛCŠ~ôŌIĨKĒLG™,Â!īx5Į(´įøˇHėL5 šTųéÉŌžNã CEÔUŌ”ķPašņûļ kßüE§œ_Ļ‰?ŗ 'tŖ[E'ĄQO’ė›ą9bĐúy-3­“ūz eÕikŅmY6°ĢžÄ4ĘŲl.Ę)ŊĩLXū)L}<&¤ûŠÕôÎú `­Ā;)ŦNgĄÖz]‹xXŧY¤  œdåŊÕĖĄ$Éū“Lš 7*MxŠH\ŋķƒ8žĘHŧŗczĪ1’V{ÕXŧ°=[Ÿ€…ĨÁŦČKęJE-AŠ%ŊY¤+’bŒE)ģļģ(ˇ&Ü?g<š†ÅYŠPՍõŲj•Á—ŋįÂȉ<Ž‹Ķ?nrM’u‘—û•N-ĶĄŠÕrÉČĮŗM“ÜĻøÁĘĢڝ ËíČØŸۚH@,.ŖŌP- ‚Š~,°1AYrŅhܝ}âĒÚi8čâŒ2‚T$;ŠžÛĀåX¤Á2K¨ęŧåĸÄBūÆEĐ%˯úøSm @m˛ĸĸŽĄ}BlĶ/M,TÁŨõ¸Â÷ĘÂې1eĮĨ#1Í.]$kķŋ`G8bRÉ]ŅËÁO ÛŅ^“¸Cž7=DWbFǐE?‹TsĶZŽú\NS-ëËWēĀÅĸÜŨ$ß Ūī ‰Kœ*LÄj i¤ŊCÂ|ėGB=ŲIČ&%ŽöÍ&ŦO8mļÔHŅ~\đõßÃÛE@rÔŪ=׿x͞țÅŲ ķ%#ĒøÅíüĨ=ŽC<´tĘŪ6ņŪ˙ũßnô€o\Ĩp”,m2ąY-ė UŅAĄƒˆ }N]1킋ëX™$äūA9JQ:Z¸,EÕã⯠‚4HXEHÔĻp’MĐVÉtMŽũËÁų´éķM|ĸÕrķHĄęÍv‰•Ž âāuɃŠI›ēĸ4§°cJĻySŪĶŊä:͚ĄG’ĩɑ=V1––/ķ=†˛_ččß1&dŽ Jƒ¨)¸Ę ˛ Ę+ÕcņŽ[‘Xą*ą„Ųį{ÁLŸ™eš÷Ûša"7#^Í´P \ ­ˆ;Ã-äV2äâK:"IšĄĒn–ÖéĘĀŧÉæúŠū–Q žÆ\­wšžĸ#Ž+BZĖnĨ­ŋuåg† Đä?Ņœ,2õ<.Č<8GF‰>ŨūŖ’°p’ĮÁ=œËâžë$ôc5?<*Č X „Jh–g¸ņ!ŗ…S:s^+ĩN%ĢNæ |F´āIŊnĩ ū 1Mt[ΓęäyæāķŠô¤Úߚ]¨Ø -[ Õå¨üĒ[…Ž [PãOLžCé‚FŨ´č—‰ĩįĄÅ[÷M' Æ™Ūž=#íĖ\W$UüÕv1›_kСÔÛĢxh˜ūŪ•Ú͌īā3ķ$ëÛA[C9‚;§ėŗ>vK9‚ŒŒŪ3œŌđ4/["§fk Ōû ߆îQûPÉ2îíĖúJãÚĄŗ]S?öŦš™íč}lOô ū1nkDE6ÕUĨ2u<ķ•Ŋö%ĄÜ9wĄ' ŧA*9=?ÕŪ_.Ēņ: ĸҊøTžJŪŨĀĻ^lÁUÔ`TNŒGi%6‹Q$…õ)q&´[ÅOÜã9dfˆœ–\˛  Á Ũ×fëM)•#â}*ZSŽbØ|ÚĖéUœå&[QPē;V[˛X|cÛ´H{X]Áä™á˜TLÃT…îčŪ:lũ:ēyŲŌŖžmÚn†­’iË­Ü=“ĸ¸‡kcQΘČL8§ģcÖúę֞o§Fŧ|Ũמ>^diÔĘūkģĢg-™“ąŽŌŦw;ūKoÎSŋĄmČ~ĪūpˆîX˙ØhĶ6Šfœ=;ĄävIYŔ^ã2–š.>ŽÔN*"?0tä™!8ëÂמņ›ĨZؤMõž‘hËmÄŦâ\•*ÖôâuqwžXtæfŗ­×­hÖ,¯rh.[Ķ=ÛãN[BIų\Ũ]G¤ö˛˛Ņį=Ki…Žwl PUVžsyF<ĸ(\¤8Üąd^t´ kŽēÜ6ú0¤\Ē~*3u5\GåūlčŧXHô*tj-]#;Ũ’æ! ‚Å>Î/yy˛ž3 ]ĩMãŅ@oá,čĸ›Šq$AXuVŪÛ;āŽĘQf&éņë ūcP„‹ĩ˛ĸÎGŠŖË° $šE´­gweņõKōĩ]ÎuŒ jÖ-œ^87Dëųš`Ņ_He'­#'åŒãÉä#gvc]D ^l pŽ“Žh”ÎŋšöŽŽâ2¯—f´ŒN[qœ#KĻėl…^k…/da6aĘ|1ŖYYŠ%‘ÎÜé=ŸÜėKC ląûœcVĸŨIî9 ĖpOx”čŠ☄Âĸđæķޜ=Ö$ænqûH,ūbūW,éfnÆqcõfß „Íä2eRgGz!-c˜dy…RHtũ恍Mž,”Ę’{^ūüĢTŽQÍt ×d-?g\FˆĸšūÎÖ Vė´ĮËCˆD^äŒãŦˊcē´ėŅâ‹ųËSž=MîŦBa•[š †ĄDpbŠz°/ØMFđöôRÅ˙a¨f™ž¤F0›Į@—Ä”TŌ4&,HđáÉ):4qãÄ/.„¸QdÆ$NĸLŠr%˖._Œ)s&͚6oâĖŠs'Īž>ū *t(Ę @ÄI“6ŨX°áƐE^=x1ëԋ =hMhQ+ØĢ%RaŅáŒ=b=›lƨuĨr…Ø€(ßž~˙,x0ᆇ6høtĶ­rŽt‹1ĒÆ•ŗ’MÛõr\†tÕnf›W2ÉÎa5›…ØĄk]Ņ7 Ü{x6íÚļoãέ{ļQƒOŸF†\w5CØ­ĻĻ[Vd[ą$Įr6؜ķ]É;Fîē–tÁ!F —îØsFīÁĘŪ­~=ûöîßÃßŲ[ārhŒ•aøĢЍOUj“…&kr”–î÷ÕHŠ%dB–†si¤™…ĨūŸ‡‚ĸˆ#îô |vÕ}úM^w’™§–@ŋ!eUCá1՟}PMXÚBĀ ÷PŽhŲįH•ĩšĀW\-d#dåčÕA)Öe‰[rŲĨ—_æļĀUĐÁ}ųíQgŅõCMg™@›1EÕTúՙלÉ9Yj|‚akp9%d„S*8•‚)R‡Ņrr¤%˜“RZŠĨ—ĘdÔD +ļp`pįŒPAEåE<&„jǝ†đã›HųV¨~•Z¤Ž;ūV詍-™j‘¸‰ë@@’¨ĄNA'^ IŠŠ´ĶR[m|‰!$@BŦø ExÎh䎚îZ(qāúūŠSąčĢ}˛ļÚj@66o¸BĒÛĒŠē.ųë­äÖk¨Y|:pŧÖU„P‡Ö2ܰÃû%æCÚ:u@õeT§SÄrœ'ēņ ‰,­Ä†|gRęŌk¨w ō°x’\¨Ėš’ü˛Ā„ēQŽ“ûEĐE ąĐC]´KbĸŒlš2ë ķ°ēnŒo„ʲĸöžĨlÔPCFk¸Lģ[¯Šaü4Ā_?}ÔcX7ũfž-l´ÜsĶ=í|ŧĻĒÕ|Į4ßĸĘŦ×y3Ëk­[Ĩ,¯×;Škxá{ĩ¯€âÉ#¸Xõė6Ô{ä´AA×ēčŖ‹(1ŽI1fÚdnÕ:UR~į‘”fūQˆčœŠeãGœYgq ¨ˇQũGßEĘIÕƒ “ŪŧķĪß&ąâXgfū6ŒÍšÆÜíÁ>å‘9‹¯šcgõ8’öĨŨ¸U“P:ļŖÚ+ZŖÃ§7ôûķß?_ķ ŠCĐ÷,¤&ã!0;æĶ ‘ČgģË`iLXŅ]d\ä$윯 ÁƒD|‡ž5("Ėķ KhBš( ;xë%h')ĘOÆ;¤äDCžgiĪ’#hCđéĐJÅ1 0–Ļčpč„J\"WŌ›™ ?ˇōVu\×(o=Jˆ]ģ  Œŗ:ļ93G$ÍXÖt¯<š.”agFØÄ7Âąy ¨ūbˇÄ¸IdЁz izV–v‰„\ ŅĪYõ&ĢéŒF\#_únˇ¸ÁÁKläa#itũÅ1“š”›ôčcûHņ2?„ĐZ¸(FĖ …jŠÉJЏ§ĒĨË{éē#€’´*žĄqrzSPŒÆ˜7n2˜Â´VbRxĒ[w™­ōV/gūL’•ë•ãđ֝iN‰r–KFūuēfŽLqų*SvĻ/ûԌU]A#;ƒÉaÂ3ž•zĸP(ĶIų›ąl˛”M.\ŒŒŊūé˛ŋĩ*$œ;Û˛žö1ÎŲŦœmķgAŊåG5Z2"ī”'G;")€"er 2Áw3 ĨMShū¸šŗ.sBÍ]x™JįÅGĩ0ô]“ca‘XÚĶÍ)ä7í)ËbVŖÖÕ΂æéĀF=ęÔ§ļ‡žŠŧŽ[úuP‡Š+O(›ÚŒŪBļc, čtËåÆ Ņãüko‡”iĮΈUwqL+Z3[ãL¨â5¯ļ )3 ųēöŗ•g `×<˛gNõ—8õ*úŠsŽŧęŪû­s –XØ[+ũÄŗ› Äz-ioƒ"¸,†ôQ ÔTŦD°"d9 „Ž—‘ Õ6Q Ôâ ƒRļo|Hbë*cœģ–6šĘ ŠQ’Ļ”.NUxvâ_ŋ÷Âe˛R¨S¨&â삐{~‚MūõäŦ .J+M].{ۋ“búk€ZŦng¨Šģā•×g۝¤¯čEņ¨ņ…zr“~É Ã° ¯—°Q°]ŨëāëDĒ4ŌŖ ĩKņ˛o<Īj­ôÃˇ@2’á ŋ剤,ëkČurXŨP­Â2ž1ës&@ž§—ŽŲíf×'Ū™ĨŒ~"ČđgžK:ŗåđ´ëœ3ˆƒįurglåöšEŅŠŖ•Púē} g•ąĒB*ŧX“&ŦĖ2 Ū'*š0ĒÂˌNqõÆÛJqžzš2ŸûŒ4đ•éÆcôãœHEˇąk‘ÅĘpų|ŌΨ52ôÁîWŪvNˇvÎh•ûūėéŅjĒ œJf~ėL¯ÁYŽV‰n™WØĖrķ{÷ĸjŽN9œ õ{›ĐĻ}É[_kšÄ1ū4ąĄŠ­mm‹ËĄBh@Ķ"Íąąh°ŨõdTŲ2Ε’:tŽ1}iü}Û×%)6š—ÛIŠĀbģ͘@Fā´h[nz-få-Ęl÷‹lå:Ŧ°Ū–6ú†;ĶŪÖpF‡]îƒķĪŽūõÖ ëˇ}]méÂåžBx/Ą­e]ŖžHÅZ`ƒ›ā!×3´nrŧŪM‘û•—â „ę‘•SŋĪ´ŠŲ€5ĶēŒĢúÆŪ†8į#‚<čyF ~ōŖ7Ņtx }ûKŨZēĐ)P )ãū;[ŽŲįæ-nšVđ¯‹\čé4ŌËŽÄN>ĨzŌŲlRtŦFÂīĮ. īˇbk<čŗž>tą‡}čr1ēŲ ß?ĻÖdž ë˛~hÕĒÄ2l6ˆŗ2žÖ‚ŋū;įÁ~g>ôqLaaŖKÜĶÃE{+f`øŌ#×gxw8ĸtģyĪüög-ŲEī{ŌŅŗ+QDS}#ōZ/ļ…EŽŅøš>DŲf4Ī´ŧî̟û`C¤÷ŋß>Ũæ8ž:.sŽ>mŠBŋ•y›5ƟŦqáŦÁoâ~äחŋü/Éũû÷¯“ų¤ í´í  ŠÎuÜ}™û4_ã8Dļ’ūZũQßüšūQāķĀ—ŠąĶ-Ŋ\PĨšÃí ŪČ üy\I “ôeĐl”UB`įí^ÁUā Ž=ŲæĶíĖØøSŌÛÅÁĒĐNT>WäT¯ÅŸ ]ūĐāĘ H‰Ô¨[kyÅbÕøĐË[āÉšÄ ÛŊ’}™GÄmÍj­`δāß-! >āāAፄņ”’ĄSXA Ôģd\V]ÜA Ŧ Ö .ƒÕIßĘŊāæčÁa#> _ųËâü•c‘ Ž%VĶDÎSĀ aéĶú5Ûæh%}ÆÉ„Æā:â*ë<ÅRx‚YI@ĘŖāūÆĐũüŒ A^…YŪVčĸĸ"^Ÿũąâ1JKsMO@WŽõœđE_i8G€56Ũ2…ÅûČ0š"7ž"‰‰á!ã8^‹b ēE:6ZšaĂų‡fŒ™žHŖ5Î]UQ†"2Ü7&"§‘c?‚‰’bdΈ!ɜŧØ<ڗ9ŸPe,™õš0J 1‚Ŗ8úãEęFi„.~ b Ę"„td‘‰mņ’ˇÔNDâãDƟ*bäK‚ˆÂ­–•"MbZā"ö’<¤%YråYb%Y:€Y†%ZJ%\ÂĨZ‚%Z~e[Úe^ŽeV–%Y˛e\ÎĨYVĨ(@\ Ļ^öeUvĨT.ecēGs ĨHâNņ]ŅdZĻ“™Q;’ŸŖIæ$.Ū<ކ6G%š‰žX¤cĸĻ_hŖŊVNúŨ nž‘Î46žæk–pAŪ†ũ6ōbƒĨfpšÜĸômZKŠÜqrœ}›rR*ĘŪM^įEER įuş5“ŨPwúœw‚įwŠg‰Ũuįy†go y2HzÎd8bg|†ŌO  ™§yjŨ6âį}Ękđ'wŪ#zų'ãÁã~J‡vūč6JĮiĘįƒÚ„2~ €.'×a¨lâ$†˛›æĩڅf¨m‘JĨØú]ôÅĻc8€‰@h‹…ŌŠ…†Ąâ ¯%^xŨŽŦŒĀ0ä–‡Ëސ¸Y•„ב Û!č“(ZÚ°Ī\}žēh”…LĒ T(ĩāAB#D¤.AäîüÎ •_Pų[ÎQˆUØXCiiWŲ$A 1JéœōŒRɕō¨ōH°,N5IĪŧ; ËŪZ߄âĖ!V˙ŒPy)šßŦoQMúm„ƒŌéĨRé›\)Ä N]ÕW NŲÎA\NĒ Ĩ•ņ• ‰.Ô˛RŖRVŠV›ū<ūaēäĨâjMĀčW( ŸX•Pé[Ž9\žü*ŋąL$ƕ$Ŋ ĩ!ęŧAÎČøÍÁ˜ œ2͝)_sƅĨæj”Ęd6ú ÍPŰbNą¤ÉhŒ¨đĶ›•Íŀ`ĢLjœ0V”˛ōčĨMĒāQ„ļnk‹Ú)AZ×L1–žq"ß,ęXą'‚ ģ Ē!ņˆbqc‰ãp–9Ō ŸĸÖÚŲ*a8ÂįžzėKtklEŪûąclŠŦyE}č˜UŦĒG™4ęČĶI ,ŲëU0V‡Y(ŠÎb“UęĮíJ|=ų,NŠ(E˛‘íM6 Rô†>-Œ|Ģyb>Ōžíu*ÜŅf¨h×zí×JÉm4ŽmŲ"•>q¨š-U5‹fmĐJO>'ÍmĪ♈ŪmŨ—Ūæ-ŨúliÚ-ßfuž­|ŸÕ#u†í!ŽtFYâ.îņÔV‚amáĸĻTBå[rî\.ĻYzî[fčzî]ūĨ@eéū%č˛nTnŽa’.čŠîįĒîėÂåė*ĻꎮėÂ.æbŽÛúnđ ono{p@Oīđîk@;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/PoolingDataSource.gif000066400000000000000000001325041447311732500312060ustar00rootroot00000000000000GIF89aJĘ÷˙˙{{{{„{{„„„{{„{„„„{„„„”)”1œ)œ1œ9ŊÆŊŊÆÆÆŊÆÆÆÆ÷˙Æ÷˙Î÷˙˙˙˙˙˙˙˙Æ˙˙Î˙˙Ö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙,JĘū5H° Áƒ*\ȰĄÃ‡#JœHąĸŋ3jÜČąŖĮ)€<(ŌbɊ'Gn<™RĨ˗0cƜIŗĻ͛8sęÜɓbˏ?# ŲShŅŖH“*]Ę´ŠĶ§PŖ:TĀ€ĒÕĒX¯jÍĘukÖ[Ãbí*ļ,ƒŽhÍĒMËv­RãʝKˇŽŨģxķČÃŋ€˙ Lx°a€1^|øoâÆŒ OP šrd˘/3`ЎŗįĪ C‹-Zâ͉Q§FíXukĘŦUÖ={õé×´gãŽ[önÛŧoĶf a(éãȓ+_ÎŧšBĶ™Ŗ/F,}0j —#ûÅū8{uīāūÃuNžŧųķčĶ58íß~'_°Ū~õ… ķmÃīž˜{îũžÕįš€Gqę%¨ā‚ 6H{ö (œ„°…Ęfá„Ŋ§Ú†ŧáöڈ’ØájįāŠ,ļčâ‹rõuĸ~Žqgá…H`ákū&ßl؁ø—Ö I_Žņ)ļá7ō§X§a—ß7ŒXfŠå–\~$#3:F$7:ļakÖMĻ~€%‡Žą™ß`;*‰#’ô9Ļ'lzĸYĨˆŠ]Ų堄j(—_z¨†žÉä…ķ1é×ŖmJJf“—6ų“fZzˆK6ĒiĻ8Z &‡ŧ zčĒŦļę*sū_.ŠjjŸŠjį­­…z+¨ļ^zéĻŊ† ,euRZН§{gp˛ÂĻęĢĐF+í´P% \ŗORZë­¤Úē-¯ŋúꨨ’‚Ëm“– Š’î†íkĪR+īŧôÖëRŦRxϏęZëļŋ‚;îã"Ûiēˊ#Āēúĩ-ļׯŊWlņÅ YëîŸn†:*Ĩw›Ž˛‹\+ĻȞdģ–> åÆNŒņĖ4×-žaVÉŨžĩņ_Ÿjļ7dbrvw$`;; [ГõhâŒËlķÔTWŊbKЅŲ{ žÖƒIiôؖ‘=Ÿß&ĩÕlˇíör-Y+ ŗŽũŪÜg÷ūÜVé¤ßwŖļöۄnxgdvaE/îxa‚5öׂIų¸Ú!xøæœwž„ŗæÍ7“Žwߨã-4éƒ{îúë°Ã”’â“_^;ؒÛŪ~^ëŪ@KšĮ.üđÄSô•U`_UōČ[Õüōe1¯ŧZŌ+Ā|õÕw•ŊVÛ'¯=÷·Vņä—o~O)â”>LëŸīūûđ#%’ÁĨqõk¤@ūņ÷ī˙˙™ŸZį‘’Ā…€>!q6Ā:đĄĀųį‘ ēĀ÷Ŗ 7ČA0'piGR˛j°ƒ(LáëR„ĀŽ\I„yaæTHÃē÷ģ a"ÃÚđ‡ū@tĒZ¨ŋ‚Q"ĒÂa—ČÄÂĨh~'ŧˆs¨’!6ņŠX´ÚúŽˆ+Ē$}ĖĸĮ(/āMQ ˜I"¨(’$ƒ įHĮW•„~ ,ˆ ”3æp yâ@¸XĮB=ŗcãLâEȅˆ$^‚<¤$'š"™Á0#$LH#Ÿƒ ’’  ĨgĒâ÷š|Fğšä§@ŠDsb“ Mh@ī N…:ôĄ}HD’·ZtgC/ĘŅ}f”!ÍcGG:ΐrr‘$MŠ:MēP™TTĨ0•%K2Ķ™ÆôĻ´ŠAfúRœúô:5âFęĶhĒđŽUIܨÅĸZˍ *AL*@zAÕŠ-bXJųRzĩĢ`åĒXŋ:Ö°’õŦfMkY׊VļĒĩ­p}Ģ\ŨJ׸ēÕĢ>Ŧ Oįjמōõ¯uŦ_ëVŦVLĒ2=Ÿ¯jØõôŠ)aŦDĪ‡ØÆ6§˛å+‰d5“Í.(—–fEÉRĪ&h}Ļ ­y YžØ4ĩį‰ū¤jĄ5ÚP֖Uˇí2qšÛCõVˇŸų-P) Üi אĮTr‹{—åŌŅš[‚.sį"Ũ1VKםnT˛‹EîēČģÚm x™8ŪJ†×Uå bz´ŪķŽĮ§íũŦ{q _âÎסõ5_|ī Âü–oŋüŊ €U8āô8Ā(å­}ÜĨįtÁ ŽŽÉįāˇsÂÅ̰…GĸavØ9Ūp9Ŧ_k)Ä DņrTlâo’øŋ-Æ.†‰ĮâŋsÆÃĢąC#ËLđ8¯*ō}Üã cИDr‘‡ä$;šÉPf˛”— dĪĘJÎō“§Ŧå(į´]æō–ąņˆ;Üâ°IŖûrŒ{ŧâ ŋ[Čū/>rƒ÷ ķN(ÎBˇ›1EIŨSj^–Ŗ)!Í62ŋ‡hÎģ‰miöIZ`ēs yÍo­‘€lC“¨ß$ũIūæåtÎŗŸGéHB‡úËŠ345å‡įŊÉųmZ#§QĻGP NĘ!tōū`€M”nÄū$ŦĮũMzjZžįŽėøįéĩųûÕųķ= ũŪ0t˙8ž3 YũMŗųQoāūˇļ_@đaŖáĩŪöĸ=FōcâÚÍÍϘŊÁ,6(ŋ+Ņã=ōüSĪėvo¨Ëæņc#ũž$ų ņhVŽY;žķ”¤ŲëÆíą!QšãuÛkūH”ģŸjN›œ[}úÂņYĘūŠŗĶû^ú›ˇwöŠŗĘŋ†öĀÉú}ŠžēáŪôc/ũŨ/"¯&˛(˙GtrĮ,˙ĮG3~ygsˆĄoÂ×3r€Oį5ęx'įyS"6h’ņWy]ƒ6t>cp§|ÂĄx‡æ$Ū dˇ~¸ōv@RzG'€!z!(phÃ'žgvCv”‘50#hĸĄ1:wgō{ë÷w;c~}wyŖwsʡ7á7+I€5X$Aƒ}’w"Â7‚ŸĮ!ŧ“0ã7|E§y´}ĩ‡'°Į5^G0˲&„G"ŧGÛGPŨ—/Éâ)Í7,QĮ3q2!!Ķo˙7*ūžQ‚4HtJˆû‚}W1ģiĮÁvųĸ-Œá&wwŧâtō1w’ō!‡ ¸z&č3Â{`ÂE{(Ú…:r!‡ lwā‰įg,؇xSˆ'3!Ą'$āw|(GTŒGƒaŌ‰1h0’u#ƒG"á˛0ä7Ĩˆlr&_86×w„“÷jŖa„Â0Ö芡ƒķ9h‹W€9*܂*n"‚h6Ķg#w’v4†ÉW! {éR†”ņ‡Ãˆ&č…F3$ĘČ'Ķׅį˛.Žōˆ0Aø(?+÷.}x,¤ōvŠh)rˆ)’2’ę‚)'S0šB’,Ķ.&Y)Ķū2šĸ‹ėލąEE|žŅ1 c.í‹,É+ Ã)#s‹EI.=“G™)Ōג3é)‡Ŧˆ*”"¤ø‘)ƒ’r’”'ɓ,y+/Y”æČ/M]I“‚¨y8PĮ‰Š"$ū˛# 3—é8.ÃR0$c0WI—Š—yŽx ˜ķȀs/Taäx"ÜX—ļB2æŌ‡˜ )‘Ų/Áyi™ž0pI"ū˜~Ą0–)0ŧÂÂ/ŽØ’ģ˛.Ąé—#%a™•ĒĄw~Ō–Պ:Ų‘ŗŠ.Ũîč+^ššŽy)øÁ+;S™Ÿ™.Éé-ņ˜+ƒœKH%ūĸt`?a‰arœĩ2fy–žY˛É/éR–Pįœ—y#D"”æ‰+1šœ§é|3ō€á42&õų˜C‘,y⎷č˜_Ų™Y){å9.I“ƒliŒh˜Œį™“Ņ0Âi› ĒžßRĄ:)čų0ËŠ‰áb†°ŠžČ‚t´‘l[5X.*X0ZV_ĨUũö›‰Žžō#„)ĸ S+ę-;ō)ЌDē.Ā›)z˙’ĸx˜ÅˆDhؗI'ž)$Í˜Ã˛¤vY›ĘYĨéx0•Y2dķĄ&u"€”‘‘īŗ‘|h2ė‚ ō™”žÉ•ÄÉĨš2’}xŖ!əe2–)™”ˇš/*z‚ūA|Fß•ylj[š#Éš”ZÄÉŖ(3*xúŠæ9Ÿē)2!3’7H7úš‹"Ķ‹uē•‘ŠoĒ Ŗ*—HéĨV ė22Ĩ§‹Mr‡§á›üô–,w„Ũ}h§u’i:›ĮBĸy—ę¸ô}ĸSxmJ‰†ǎ‚Âá4V8IRĄƒ|„xž%؍†'âĒ‚QHu6šĢˇŠK䚄§zŨÁ†&z…ß§†‚ē:Î÷4‘÷‘Κ¸ēOĀI7ŽĄ.&Ļ2zmˆwPŲ| (…ύ†ëpi'vÆęŠœßˇ–€g4~ˆ§ĸ'í2€ƒŠ­ļ‡¯ŠJ‡|ĒĮĮww§ūˆ’’ˆ‘vø!(CJãu‚&đȂCąˇņ¯útŒ˜3 ĢąæzŒCk‚5H˛˜G|ÄØT ĄĨ¨(7y¨ §@#+ķ*ÛĩtĶđ*qŗXc¯ĮZ|ké†íZ‡U2•Oķs+†ą÷zu;ųG…gŖ†ČčŒS˛;Íjr"ĄC‹ą°qƒj"ˇ{{P+ƒÄȰû#f'€’;¯p˜{Ŗ m4 @­RË3.{-_˜ˇČę$9ģsV‹ŒC›¸äįyÛ1p*ģ¸õaöĄˆŸĢƒTÛŽOãēEÛwkˆ€­‡Ŧ#˜F?ĨĢŠ;yU+"čĩc#zxˈŦW“ÄH†#ysū2 i¸ Ž“&÷ļėēą‡ģ˛14nëI""&KžËŗŊ§žŌˆ!Ĩ™?h´č{UĮˇĖ;‹vø”įŒŨ(s€2ļüĄĻîÃ×{;ßq;?CŽēs ŧˇų80” ÁoVdj6?\6ĄAXÂ!œ'Ŧ5ہŋRŠŽ÷čļÜqLÁ(l; ,…­´õ=ZŖ/JXh•@ėÃD<ÄF<ŖÄkÂ72âÄO,MėŊEüÃV\ÅX|ÄYW¤4<Üĸ[ÆZ<ÆWXĐs°:ÜŊJŧÁL\ĮR<Įnė9Ÿ–ÆĘqĮS‘j3ŅKŦūėÄt,ĮuȅcTz 7•ȅÁ ŌT2ĄÁ†Œ“LȖLĮ ÄČÉĄÉüĩ@TÆ1Åȗ\ĮŖKœŒĮōķk„Ā7hė@ЌŗĖ\WâĘ ĄgĄüĮŽD<Šö6ĩÜX üB"ĖĒ|ĖÅÃiŪ‹dČܡ„T™ŗtÎ<ÍÃ5UÔ|͒TUIv%ƌÍŪŦEšÅŨüÍä<5ÎDkÄGåŧÎ5D‰ÁŊėΞüÎ`Œkō|Ī4”IÁ„ĪüĖA`ÖĪũ>Æ/ãĐM_Đ­ÎnVe ũĐåãÎ Ņ}8XĶÁŅ¯ƒËŨŅxÁŅŌ—&Ō$í9 ]Ō(Íū'Ō,}+ŨŌ0ÍP1=Ķ6ķŌ4Ũ=(9Mw´Ķ˛ÃĖ7}>­ĶZä CŨŌG jUE-’ÔA;NŊhO=ÕöbĶMÕ˛ÕRÍĮXŨÕņH^m8ōæäFÖf]Öh}ÖjÖlŊÖjŅUx6JnŨÖtM==<×x]×z×oÖëĄ:€Mæëģ́{ŽÃ ~"Ë¤Ōøˆ÷šŲ .˛bŗ~§†Ü1ŲĸĒâŪÍâĮœá5ę}]c,5I"šä k*&R Zŗ`+Á3.äė] Ūá,įbŽyą!¨+‰ŖūQ—0įév~â˛2 ŧē)ŨįØ=ā ´á’¸“SĘ­IWŽyrˆ}Ÿ<*¤ëŗ‡čZŪÚ¤°Ž„Ūد!銏a—2Ž;ß;ģ܉Q¯2ûz+„ Žč6áåųÛ{~œĻ"“ “…(ŸKŲ.˜ė°é—;2–náŠqŲŨ4ĄÁŲëÄūĻY*“e’ŖžBĸœb’| –į ŗBėŪŪė+˜x¸Ž.~˛h  ŠũšÂ2ĸ]j†ūҐĒÎ.×y)îØĄ”B$•žĸ/~čžÅôl•‚ןüīĸBĻ5į——g›{‰.ØŠ Ē)ÅĘĨo!?jîĀÍåĒŦëßū,¨šņ¨‰ĸ[ú/ą™›Ũ"vY–č"¨ãŪßįn“ĐžUDįGn,(¯Ą°Ē+ã~¤ŲĄŖ,JŲņœ —ÎŪ"Įën¸í ´éëoôôžô!Zč!š1Ÿ™’JÚOŽŽQä¸höx"¨X˙+ZßŖË.ô8ōœĨÂôŗyôËâŽA¤ŽŠĨ˛ø°HõiLōėžÜë•z#oŸ[9ĒŠš§/Ģž/Cš’qēáe/8Į!AĒĢâŊŽøā^2Cɒ‘bė˜2–?/‹>Ÿí'_Ģ‘Iđå(ø°6õŒž/oū˛Y3ã,\žž×… yé­ģđģā—îéŗ‘ķ ‘ZwÄķNūZ9#ŪįČM4ũ=Ųk~čÍØuN#D§~C>„é.`žëŪ}Ŧ äōšé(Ïz;žgHŒūáũčģāl[áį^`“<õž:æoã .`HĐ Á ,XpCƒ /L@ąbŇj”p°"ċ =6šP”)UŽdŲŌåK˜1eΤYĶæMœ9uîäŲĶįO A…ĒTŌ(ÉŖ *Ո‘$ĉ)ĖbU;¤čqĢԄ §–Kđ+T‹%ĶĒ]Ë`¨M o5XYÔęHw™~tēaÕĨÎōøĩäÖ î „:ø`YžxŲ"=ŠôÂIš™5oæÜŲķgĐūĄEĪ,ŠvrŪŧģŽŲ˛ZÔ{ ›yQĸDĘ3â6ģqõĶϧŗ‰y4]ēC“§dĐĐôd‡ÎU§UØ÷ŪĀSŪHáWĔ#ŧdø¤ÄKŨŪũ{øņåĪoĪā÷DԒĄC”€^?kSĩÔŦL˛ķzÃĒ6îÔKo+ö@` cĸPĨ SĘpŽēŒ:˰B¯@čB40?ĪĀŖ:z.­ūD1ĸéŗņFsÔqĮÍ`āG‚üąŌH$‰DŌH%‘T ',RČ"“œČ%‹T˛Ę'š´2Ë/ĩŧ’I/šlrĖ+‰œ’Ë+×SĖ7<“-ąūtŌ=äVŠkĨäúDÉOM)Í6ÉėË2å”rŅC-tJ(ҤSŌ'ŖŦ“LD'ÍrÎJ)Õ´ĖGålĶM3Ŋŧ´HSUuUV[Åąš So#ŪŽŗ(ģZ×ĸÕĩ\m‹ĖVŊļÛõ6ayĨÎ×kôŒÂ YŠ Ph˙”VĨæ\LmD] C-ĨûõÖmõļģ]}åÖšÁÎŽW‰ÜŌ`OWã•w^zë•Éžcú­Äš ë?~÷ĢÅK˝W˙fĐÄ´”]VЗĸ TâA^E§Ę.ˇĀ.ø@AŲ*u% ģ…Œ^{[vųe˜ákîVë´ckF}=îļ˛TҝŸū‰Ŗ*8œņXˇXĻoĪ 5\nŽåžÖ@įĘíˇháėųhŖļ6úëÚĘō å}yÉŨ˜ĶV{mļ…*Í!Ķ“ģŠŽãĻûîšķÆ{oŊûæûę’üünƒļQj””†if`Ĩŧ;s› īņŋ)ˇŧō×Ā…ÜqĖ/HēmĐC}ôŠŖ+€oënØÕ[WŨVØSįœõŊ —;°tg—=ö°>ŸŲ Iéĸœõá€Ĩ]o jΗsÛuwúå§ĮîÜëvŗz 'ũ{đÃWV&Ŧu‚^ųōÔW?ũŨQ~ˆPQ*Ô”~õŧMņ—(€ĖQÍ@ˇ>i­yū@^mh–žĪ}éŖ`Ęöwüą†}› 0@ņ…P„#l]žcĀķ҆BČĐ.ä=ĐE^IŗļôQd†aa‚D‚­ûĩe§Iw"4¯ m/āÛ"¤° PėaëZ͐âæˆ€až#J'#;œâxÃEŠ1!ū‘ōHÄ@ŸuÍ$-aÚÄĻĩ¨E b$äcGčD,V@Š`dHEDąHd7Ck ôeÄ""BÔČĐĐĸŊëųk}Œ1ŨFX°žh‰k‹ ã,Å’ˆÎŸ2Ē’“Bœ é­+"æ,ēá¤C‚I‘,¨/ū"Č0?ÃåiZ€ŌĐ•éGhFst&I#hËBN¨"ad /ЍMöđŽ,Ļ6ŋCpÂ1-,¤9ŅGô…1ŒÎ‰ áĀ(0Pūį H[uÅĀAN’‹Ų$§ĶŲHm4Ąęä"8J›ĶtžĖŠČ< 97šíŗŦ mËXvō +Ukw +Sœ"ō¨ÕŲęo{kŲínq°ŪõovĨĶŲĀÁ5Ž1ŽL@˜8įFXÂō ,WÔ˛Å‹Ž1ŒCM,U^‹N‡‚ąŠāäčE!Kf]VĄ"Nč6gŲ<ĢWŊMKū{™č.ĶS•bŖPBj9!”mTœÜtŦ63RÅorå°q͟F_kЇ&šyŠuåvŌČÁŖ]†'žp—ŊėčÅ ļø—Iōâ˛+Sqܘ/âę/wfŽ š@âæĨÁōbiq –DRyb×îŋ/fnˆ)[j2Ō>9Ŗ™ĄÜŲ­H ´įwé„Ë_æt§sØrIā„d>ˆ¨‘bęBĨŠĨ—ŦÕ †ŦēA †¤3ũØXU{bŧŒ33tų D…šVd‚DšFF˧ŦŊ‚ÁÄmn6A0íilgģ„ĀqŽr†ĢöeÎ ķũHŲ,LLŠ"Ņŗ/tͰūņŒë…čz×.ĄĀĄKáFc3–ˆĩv2gßZāëM÷˜ÉB;|^[Û g¸f@ŊĀ,˛ņ.äžĸæã$hˆ›Ës]×ũgęU›Æ!Q8(PokØhlžøƒŦÅTgŅ?$Ųģ?ŪņĪrc#¯HÉūs ķäĨ )Ģ!ZĶ"ú{‹Éĸ,¯"KŠÎ˜įũĘU¤~u†Č;UŊFIŸWßlĐāŊˆöūÂŽúvĮŖŖvÔš†ķ:)5s÷Í|tŧį]&Fáy[(ŖF?ãž‚Č-[O=Ē^˕œ õģįåō•5ŗÕÍŦČFŲÜŗ@Éxuˇ§hņ‰ Ĩņū­xkë]õĢīÉĐšJcų˜ˇ>-Œ ŲĀɍ;ŊQįũčåøxߗDë;jbKâÛBT"o†ĒėČũfi z 1N}đz&0=sd}÷ŊOšmYžąqû{Ņú¤ŅwÎĶšúv›|lŲŋ>Ö##‡åx}įģJ‹œū×Z‹áō•‡hšÍéŊøĢ?ƒ;ĀĒŲžŠú>ŒĀÉkúŠOÚĒŲc­´/b‹Ĩrķ1¸‚?‘Ã:Kʖ›Ģļá#>jQ –ģmJĨt1ÃŧŌ)íq§ĨC ŋCŊ =Ąq63šû“@"ô˛Ā’.ÁČĻæËŦ›˛Ąŗ";4˛)ö 6z:ÁHĸū5ĸ?yĩ\°‚Âų0SBˆĻĒ(3”Bås¨Ė‹ĩ—*ÃRÃÂęë B´w›´y0=t0˜Ø´=ž>äÃDz#D:2DgAD=QDdĔđÃ@ÄA|Ä?ŌŽÁ#ąRˆķĢŦÜâ)žēŠš3vãĒ9Ü,˜sĀR>€IAÉ# ˜Đŋŗ ‰‚˛/ü°qŖp[%”Ņš!7¸ãAŦ둚DIq)%cĐŨ“Į˙,H ÅũÍl´J‚ ŅŦ‰°ÜLHõJKËKĨĘLŨJãŖLļ9B0’ĸ:Œ,š§8›ŗĢˆ 8ļŲ(0,T$íØĮ“ÁēŦÕŠķRÎđĩš¸7(*:ŠsˇĻ‚ŖĪ›)5Ŧ9$‰a-Ã~™ĪuG \-Bi}ÅJ4äc4+ēĸaÚ.Æ(Á!ĩ3ĩ•æ;%Œĩû| ÕrMUƒSv ž9 C›ÃĶ$ c‹É¯Su̎\—8ūô––[czĘĤÙVƒũ˛”#ņ '5L*r§ßØ0ŠJ- ją‹J1!cŸ‰-ĩÎĘċĶvŽw ĨÉCđ#kjŖŽ ą‰˛Å œÍĀ0ō;JdSq#PŊh=XžåŖ”Ä*3) äÖúŠŦIZ,īâ­ôZ˛ĸ *ĸzÅ8돺f Ų ũŌ÷$ \Y؆šŠtLšJ,RÔǚĢ#ģ˛Ē0@â@œĩÚõŌ˛žÛĄ˜ÔĒږłēōËÄ4*üz+Ų"ĢŲk¤žUŠ€íšvôBˇĨą‘%ŲAÁ XŦ-ŸKą ۖ/}…˛ŋŊ•ŧCj[mļ•[i]Üūēe }(ąmŠq2ÚĻÍ\ŗĸ¯ŠmŦûBŦMäŽ[YWųØ 5ŨŅ0:žĻ˜/ $´¤ ÛŽuēœÂ<Ųu¤ģÅÄÃ\+[ÍŲÄ]Ō%BßIX¤84$* @Ė:¨PœÁ‹eXË.ņũŠtt!’ągŨUœ7•‹Ô.šu2Ūr˛)c+ÃSnÕĮĮtJGž)܏KÜT„Ûë]ā›đ]—ÚŪ?CĩŨĮ3ËŪ0ēK*ģiŗ¨@‹6ÜĒŨŨĒE늕Ą‰;}ļni´gƒ6×Ě¯˛ ^RVaV …ßFŪaL=Ž ĒΊæšÜÁŧŲ-2+\#âË ūPŠęlÄģģG.´B2țČžÄŊ˛ A‚ŪčT`.c–Z€1˛ øáâø ų17~YŠØņ¸XãŸŅPē ßü4+CTĪZIÅÄ9ō¨š›EÜCåŨõ0cFÖFŅ)K9.W€kbJæ›×bũXI'ŪäJ^ŠæTæØc˛˛ƒ\ļ5åŨĩ”Ú0ÆbļĢF~åŽËÚ´ļ‚Þ5ŽÃ;Ļc]БšbÎåôųä›P“ʼn{D`VJÔļu3¨čŧVvÖĐĨGX~eaîÍŠbĢĄ¤Næd'–KĘJ1Ũfq^âwåŠų\hÖ>îIäŦžCF`ƒėŊjžf†‹bzūé”(iCaLi“: ~~”€ūį}†‚h„6čB h‡^hˆ~h†Ū‰n"šhkŽåė´Į@UæZĸ÷-eSãhĻ12ļg”t6ã•~ āɲᏚ?VvVÛ(ięÕÍzNiž–Imi΍ˇ•îFYž ŠE-͗Hayļ ũÎ Ŋ‹„™gœnםîiŦū9…;ę>˛HxIjžHãäæq^ŖöģĸŌCâK.k˛nëŲĖŪŦŽÛĢū>0ĖJŽfĸßôŌ´:îk÷é6ökÁl–=Žëëkīæģߡ‰’0Á’SųՖ”Õ>ŠFm5ą81מm0ymÜļíÜŪíÖîm…ĪÎîYĐ&ÂjVŠ–‚k˛næŸâ.Böx&Iĩ–Rë}î¯ÜRF%!†lnƒÅîĐvšär‰ņn–“úĢ=šnäRīnī—븎nžb ‰ŠoįĒSņÁŒsŽn÷īæ6āéCûļŖųæ#â Ą-|îo˙]ī–oÄQš§˜ęæėų(%Wlp đ†nœ €ō~šķæī—ëŪpg•—Vā˜†ŗđ ĪđŸņ­n…<.”BîĸæîŠY)åĻq —™Īn/Ãī ?rž…qÕÃū4 ^qWīŽöT$Ÿōˇ0ōŦž;iôĢ“pr*īr/_n L?"æ//ķ\rī#-h:q3oķÍāōÅūžô–ōīQs7ŋs Č^8_=%!+_s<ôÖCķîëc@tDÛ>ŸũŪqĮNtIŸōFŸöÚķ­[ôI˙rLįķ8nīŌMuĮp† 0M'u ¯ô [õCõNguZoWo¸Ršuņõ˜ŅõZ˙oĨžæ[īuGī_?vJ…åa_›ĪöldvŦ> iĮ;ęäīe‡öiöõ†s n?õb×öul—ôīé'ÕęËwuŸ&Äö5:fŅÚnjĖÆkūĪčuõzsŌ‰ūõ­Á +ŧđd“ŽjaĻģh×HČQüéÅSä[^>YŒœqúĨ,ctēz2G¤hÁ ¤˛Ë1˜0Âjš+1Î迌›žŌ"ÛąŊ)U\Īĩmq^ķĢ3ĶԞ<ŨÁ3cÕ˛ÔU[ įŽĀšÜôÖ(ÆÖÛŅ SŒ\KŋIëĩĮ#ôØsí/ēڝ9ëÕLUŠĢ¯ŽRkŨ}û=UÍiŪüvētÖ§Ûq˛…]Ņ{¤*˛ōž¤öŅÎfØõ…NCD+B˙=PÁ{oõĻ蟛.séjív°;'yņqcŧä5Ątė§–_ėŸíkūæ›îyß㌠Õúfō Û}:ôŅū‡;xë„ģŽåS2žœ ‚Æ‹Ÿ~EÔ)ÜŋWītd‹ ,Ŋf!Œkķ1ĪPüėÛo˙xŠ?¸záŦŪ¤’E2 dĀP+:\É.Į:ķu­@|Ȏôį2í$¯y< APĸœƒô ãB nP„ŧ ­3›Y¯…įS’†ō%ˇŒh^}ō“–Õŋōm-} 9^ RÁX°ƒFĖ AŠxÂ%2ņˆ&dâƒ(ŅĪRsađā’Cļ0Z `´Z™åđ)"UjđĐØ:l5ĨFS<á•XB"f„N¤ãåČA#Öī~ė–Ü"EŊ,^ĪEÚS–Xƒ/÷üĮk^ūÜy¨FÍųpe‘ Õĸ¨Ä>ęņŽKŒŖ'›Įõũą”Ļė˘ 0  XĨ*Y)ËĀR P%.i‰K\˛R•ēĖå+céË`Ú˛˜ ā%+o9K\S˜Žėå2ĄŠĖc“ŧTf+ĄšËjō2›Ûüe4ˇųMm&S–ą¤ĨüRÅček“yŦã;?IÄ(–P„ėã)ķŠĪÎ0ĀO'ŌĄ—øžG4ËʒFD՘| T| Ė^“ Cí”# 8Ķ Ą— u&dySÛ'Hm…ÉŠeUĨ2cžę$ yi/‘Œ|‹"ĪĐ­”ĻKéŠcŽžnLĘSČŨĒ2Ԑ•<tūXæ"О×Å'’}ęĩԅ§UĪP”Ä^Ę ÂĶŋ™F‚-ķhQÃ*Š­ō¨ŸŽß{ēGè­3DC'ĸPˇēŒ ˛lÜ3Pē˛ĩ¯|ũĢ_ûĒšIŦ˛ KWIiØÅĸ ˆļb@$g˛MëŸéēĸB-‹˙,2^ }ŠfmÚʎ–#0YšĘ•Ąū”ąŽ}íAúÉ$–T`h|A¨žÆ'ÛäՑrŠė{l{ßMUCX}ŽUq #¨m&ĩÅ+Č S§ˇÂļē>bmŧ$’ÚŽE7{ ,_1đ¤Ûˆˇ.ņM`Ņ›P‹ØÖ­s9(xã ØųĘ×"ŦŧQ‰7ˇ§Žēé´.ū€kŽöøĻÜ]WEåŸĖúvC_] 3W¯ åCí5L‚…Â›Ū––´ŖåO‡7ö%§dqn€SÜ-ĢnĒān‰ŠĶŒ‰¤.öâŲ_TRąviLŧĩ#ŠO"ĮvH1Į5¨q‘œ[•čždR1”ŖĖĢŽÕÅžmplb1Ä 986Öōą°,Ų.™/]4ōLÃiY•Í“ V,_†]ÔIšÎuŖ”Ö<ŲšÜ˜.2Éą^ŧÛ1ÁČÅŧ#áĮ|ˇgÂTtƍÜ'ŲæXS÷UŦįlįM¯IĶ šĒBeBč,kYË%!ڟģėįžTŒC“ŽIŌÃhĄ*Ō’ŧuEūdIÔærēמÎĘ͒T“ļÕ¸Yė}u_Č6˛ß›vÅés&̚įŠJžļ­ŸŖ:Ī”,ū5¸¯›g%ÕđŅdĖá}2ĖtûÖS>ë1˛ĪŪö#dÄ5UąÍ%ĮĩÄáū÷žŊŋŁGĪĶ˙øu8NŌ€f„P"vÎ÷(\ōŖđÄā"ö'ĄJÄā.2ÄpksÆõ=÷ČãVņųŖ6tS1k$WŒ )zR32}&ze "ĶZĨŠÃ&Ed D“Œqœs=@9ŅÃ3ô°'lėÜÜI¸ģŦ=)ĮJI QH&ū|‘Ī”"†áž ŠwwŊ"<į‘ŲĨÂëĪ ė†˙L°Aĸö†CMÅŨģÔû¸AŨÉļW22E1īŋÍŖėڕévpøŅ‹ģĘ:|ņâ_:%˜ŧüéËZÅōŽ%9šĄA(†oÎyH÷}įŌ9­iÎnøÆgđģyüä/_øČw>ķŸ_|é7úŅŋ>ôĄOz?‚<ÁnוkŦcØņš'6VÜŊ…ļėzá$ČY4\„ÛyB6ÍÖxq'ęđ‡éŋŧĐĘ˙ūõ˙   øtßöŒ‚‡šzãcaœTœr` ¨„O =RoY˜´Š[9˛ˆ;NHä’ãmãŪåâĩđ"›â("І˛Œ×*ËCúYAõcnųS`#А[‚ŖÎH‹=6ęĐEb¤ |íI5ĸŠ•ČÉpܛ6"‡9"‹(PXĸRĖŪ ŲcE%vĸN2äŗ8ÛMšĸúÅåŗŖ˛š"JĖūDîeŲ¸âÜäí›q°ž˛ųā]ŽM\ē…ZJ%ŖĐ$Ž ŌĐ@ÔŊu‘{Q"T-KfĩÕSjŨgUÔLõ– ŌÔčĘ ÎÆØ`ĖŅ NĻfåčØŲŒjžfâ°ÍÚČÛøŨ$ĒéXq|%fî™@zÄb2&Ņ= r¤^‘bJ-Įĸå^SYÖ[3˛¤Gf#ŦņāÉdLHBŠ>RĸČ| —Õ&y&Úmaī ÆMŽgØÍmDžÅ°Dn~Lb^€^öåpŸjJ !FD 'q~œqnŌiās´ˆ’P`™YæŠ …ą,hĒhJŪ—4ēÅíá›v.eP%§L\âf{Ō&Đū4ŽžđҞ§ŸŅ&û›lúŒ[*ˉŽ]†\–%€čŋaXs\†‘še ˆŲ-&Ĩ^\"3ZDøF<ézŊŪe‘` }ŨŽ0@Súqũeĩ‘`˛ ?&Įā%Ø<[܅(–žbÜ)[™Ļ'}“xŒ–ÆzēĸÁ‘ŒŸØ ŽŪU&(Œ™m°žn‘ŠnÂâ…ÎfnŠ›—ûI#ŦåPJfŽ”jįhæJIa]T‰C‚įPˆĘ"i6R§ ãVB§ĶŅ\våĩ•dŌÅ‘åxōՍæiĀí)[ŧėšáŅĮĒZBĨÚʛ˜Ų'Úī$d™­†Åū†f•ęĘwĻŗ”ĖyPTg>ãĶ%’SA ÍYg.M\āb\)åFĖ*­ūJˇ[ü~Ų`ƚMÄ^Ž„ėtL,ÂĆŅkĸ”ŪՈ¸īIš:æ„\ęĻ %Ûĩ$ËaČf*ÉÂŪU´ŅIēgáTAŨ"˛öÖ­…ÁĻĢÁ€Ŗgė ĘŠaO´äF„õĒŠÕÛ>XąŨEŠų…ÅUžqF‡xÖ¤îŦßUiČŗæGWFVĶ-TtŽQ#elG"JfĒŠšL`PeÚ žŦՊĸĩ  ŨÖ`’YČÜåŲäDך"‚íí¨ ¯Šä‘Â$ß,[|l‹!Ü66)ZĩūTHž%ųx„ ‘\sD,˙Ň…gŊĒŧœˆĖ9]QŲÕ>×Ŗė¨ļŨ(6cƒÜ[In UčfŽ ¸vDŗŦYŒ™#Ī6ĢjĀ-„S-YŸ-2åR9]“9é’.E“9ÍŌņÅŽéŌ8)ŸëöRėÚnīŌn,ÍŽ/Ŋîé’î“2ÍŽ2Áî*-î՘…Ȇ#ÁmLe>žë"hJdĮF•ŗ…e‚)WĒHÔĖÚaįåĩîĀ‘ˆ•ãZ&Jõčru$ž$ūčDUãĩ å#]]äē:īūØęWv,Ō^|ˆ õÎ"ü†åbÛe•očf*ú:ˆʇ 0äĘíÅ%ė"%‹ūđK'Ŗv‘Jģ}åŅbĒA2í}%g*WÍ˙"ŪŅÕ]^ŲPfnV°R’ė-đ$đšôčēíæTéļ6éģ%§¸ŪUŠ$ąđõ˙žˆŨ%PEŌ#R^"úÄđ ?Hôʰs¤ėY"`H§ÍVī(’e§ĘŸp ĨJEpÛÆÅœõJėYējØÆ‚īIö]М¸Öo…Y+…ĩžŒoqu%Ž>ãdūĻ]āĮnȇz)"š}1ÂaQorV‘fR’iKēÎĐqŅžšŽW$†ä"OÔUîü"éą"KM{qåXJډmíj*Kō‹pu&Ûg†&'kūG2gč#īX83@écĖ‹…ÁIŦ~,RĄ9æÉr„s ãGÖx¤ũ&¤&j§2Ī2wÄą‚|Ÿâā°Ņ„œž×ĒąbÛȧœŽâ#Ëo!—Xn§SUw6îVŲ4›ę~ŦôéíwŌ ˛Ú4FۅbØ1qĄ´ŗ;¯eûØĘ€¨$˛ŦfğŅëžúØ5(a,,&ķŊ1<{N8ŗ3KsÛPLÁ_ŊŊ¯,J"éŞf˛û6ė@QæņF„-.Ö´,‡´Âätv™ŌŊ§Kđ̰ÖTĪkNx—pØ]}L–ÎF˛RĶtLšīy€ôeDū+Į@ķB?i+.ŊØ˛âŊnāĪh´ŧÉ+Ęĸĩl^•$>ßåĒzÛ ÁĩUwG-cÆR {éĒŸÖ›z-*aĮŠ` Ŧ™×fIō Īß´ŋT*IwJĮÔ5!;R™ŽÉڄzÍEĒ_ÔŪĄ=´ĀjāfF|&N s„Ō V ųĄr VdįiIKã[’ÍøČ˜Øž)o™í)ūĮ:îÖ%Ķq††ˇ¤ē-dŸÅwâ…3ß!RčkėŲÎrßEŧ[ļrģÄŨ!ĒģĒ36!Ģ!u^Ģ0–”÷sÆds†8!zæū…—ĨZ×G'.ęĶÖcM7Ąĩ´ūZļšŦ^žĩÅ­´~Ķ,ŊŌļ–Dmë+ÎGâ,˜sꎃĢįMču‰ËėČ ™h 8?i$ 5´üî?œKÍ#epežöĩjō…íYî¸XôĶåĨ7¨¤#‹Ö jŪ––žõŸEu˙ĖM¤ŊÖhŠ6„˛¸CAœbā̆™Ųâė{叓‹”— Ʌ`Ũ$ŦŠH páp´ ˛FãZųߓŗuũų!‡žæ(‚‘5“aĶNŽšũņ”D1ŽËļŊU§yu´ĶØÕnš*ÔÅ89į՝×9Z`ĩI.¯UˇēÃŲį “o§2,x[8A':LúWDkģXė ßjpūI_8åãŖ­˛ž|ąūĢÄâČŖÔHę Öęŗę?ąF“Nģįēā5ķ,ŧà 5œMŠ eã­ĩĩSé# üƒę0Ņō)ÅÛjI5†ūģꂹS ąėtômGėxô.<îęâËÃÛHË$e„Ē8é^´Ž8äJĢ(AģŠÁ÷Ēb°?* z;U+ ˤŅĸĶĖǰČ6Ũ|ÎÚøę0Nŋ@üM*2‘.Wz" Įė-ÅöžK 3š T;!Á ˛ĮGŽ ˆŦķ¯ĀNRO<ô ›>ä4UĸĘ \OOˆ*ú¯Ôå@…/´ÍnĐYj•ÄāBŌķŖ(%JMA 1–ØbĨ‰ŧ˜čĨ"üYpC”ēĶŌ[æ÷oģ¤ūqĸĢß27ŖīĄ­[ßH/æ5¯dŠ@ôāŌ"U æ$ú:Œžę>n!î~œŅcđŊ °q(<].ÕĀķ¨J=ę!La>g"­ j9üj k:ąsÉ(F):QĄŪ"Ąą•ˆOņãÚGŗđ pq taQ8E+ūDŠ ūtÖÄč>č”*TVAÕX”Cœ÷-D>K[OdJRÄ+ ΃đ2Ÿk4yĩđŠ8kžSЍQŪ“hT73} GDäŌÔödšđpÎ9Öä×ReĩE%‹yÄ"Đp”Ÿe(I9JS–•§Te*YšJWļ–¯”e,[éÉPĘfNšÔ@%h­ 9 *ÎÍ4 ÉsQŌ!KVĒ‚A—!h…ҤŖ §‰<^‘7é€zđĮ¨@Í+*Jsö÷ØhcrLßJg%¸D,p_cŌgvq–;™Ô%ONKž0lũ':ĐGT U(A•dMãõåšVÜū"ĸFuŸĨ­…VëyŠ´'ĖX'2ÃŲ“ÔNŦ‘°Žs´c5ΧĪõiV‘ák42ę'TeTÕ}ÄhĒEUI8:mĐ;Ą#œ]ĩĨ"îq•QĄ5IϞ/.ŨgNލ%]ĩ,XÕjVšēU¯vŦ_kXÉ:V‹YęuštÖŊ3­bІ{?­EÎÂÃęm4W5ŖĖŨrĸpbį[ Má`ĨšRöDtŠöbÉ`ŧ™šŠŽŗ+î\9ŌŊģîtŽaA“e­8îeé>˛ŌldH÷ĢsQd*Zɀĩ07!ŠNõ&0Z˜hĻĶ–!ūŸˇ¤Õ­ÎMK\Žu‹šld3úÕšuāūka+^jí$É)ž´ÔGÍhÉW A*Ē9Õ .;iJéxŠiØ !օ’K§Tĸ- NÆ}Lō(O?“4ŋ Ĩ–2˄Y-–K6E—fÄÕúŠ…šÍ LÍĮP„‚­rĸéÜ 1÷§k —-{ĻąšP‚Z-5 &JãļE鑯¤ˆ!'į(ˇšÛĖ;0Ļ,Û Uķ’—°,œęÃ4Á Š™^i™LËF(ų—ž$0Pû#L%;yKÆ\“‰Ų_fF>ą‚õ˜c?™O‘Jg-7ĄŽÅėģ(e•§ ™ÄKâxš¸¤ ‰Ņ6Q“öJēØ+¨<9\—%~įn'ô– ū‘ôe8ÛXĨ öˆúÔjHNÁ !ôn?sSã$í2Ō• SÁ’˛4˛UԋRvéÚÆ–€×ģaŠ$ë¸ŋ Ÿ= V°:íįū-Q¨I,‘`XeE~¸~øL4ßļšŠFeÛ! Ŗef}ĩa~Ú`\ÎZ0°Ŋ9Į7V!Ņtɀiį;aFWK‚5@4‹KƒĨÃ9 FmuÂOEsTiEXĀ—M[ŽÅnŽlWkJ­ņJØ ßŧ7!˜1ԙN  ôi$úæįą'åđ°^˜‰ū“ZŌÅpfLu7ĢËma}hm§ŊZŒÎr‚ĢÆxÛÍūķ›ž¯čũÕ;o~ö“ĖéūĪĢ ä“r‰Äw,tōo„Ętš*]ÔŌx4>IBãĒ<Ũc‘XW¯ļZŨÖĘíV3%‚Ą`=?UĢī <3‘^ H‘8?˜+ü¸B˛*5‡]^Æ=ŽÛƒä áĘíŖŊaMĀÃåęßĻŽeŸ6gãķÕF'82OLĄ!ú>ų=GaĶā[Ē$÷HX`ÉâwJ¤Æ—Iã=ĻWÔá–G`ÄŋŪ^vQäøœ ’īQYëŅÖ}üXâÃÖŅv7šĄēOÉ)õ8Š]Í HsœéH‰syāq푩˙b*aD ŨšjSjōyßúå!đČz÷¯JĐ}ÃBõäDĶQš(E \ūwl?+ü­—ÉZĢ3ÁJK°øįBKđœ R–/š +Û띰­øē-ZļIg,ĖE\Üjȃ€k§î&OĸfĩŽã@(ĮfŒ+`æ'DЎtK0|ŽūG.¤ˆÎ¨Č'fp6$§ß'~Ėe=‚É"$K9øĘœø Īīpv*ĘP‹§ÆüpšBėC(Ž=`#ēTEę>Ī™öKVĮ.ĄNއ/*RށĀd–††>,˜Ļ!¯RČ(?|ŒP”Č‘ÆmžšŠņÄ&Ô kĐŪBŽƒōåՎ ąGFƒipÅę"‚Ō`e´đųęĢŊ¨Žę^eÍpŧX/6ˆūÄë,`oȌŒ.†š˜ˆ`Ā úœ0ÖÄ0ø„<Ėp`J›¸ŠąæîŊ*,|œßĖŗDÎíQđ6­.bFP–0ōū*€‚+F1m.¤ōj¨lžMhä‰úđPl~ސÚĨoä ŪÆ°ä<6D&9ÆÄV-™0būâ đGeqëQuĖø°bijÅāoé,-Ԓ°§–*3D ĪČ$°.TP§8%,KO˜&8ôãæxOōĸQĮ¯änFšĪ- û ĪZt-jđŨ°ŠäîŪŧ.­Ō+Ž?ä°ôđËāĀÆ¯I%cŅu2'{ƒ_ĒˆãÎŦÔL++ÚđSūĐÄ3 Ļ ŋ°‹Qe|ŦLTϞ8ŠpA ˛>ęĪĘČ&- ņ'ÎqCĻq#ī"fúŽīĒŨŒ$ü#€tđnū.$҇ü8‘õī(&Ę]ŌņēPzâĶ “ â'!IØË+?ī+Ü1Œ¸DTÖâ,2Ŗ{æk¨L-2} ¯fŖ)iϤŗ–ŽĐÖ ,yB,•'7LL#eŽRjEs¸Đ5nû ŗ -ņíūX 1Ō%gĶ, HíČĖE ‡ÍúĨčą' Ķ9 īÔ IĨÜž ĩâI†Ė˜B¯Ô‚‘ŋŽ ËJoķ˜d<Īd˛Æ 'ķČä;ŋ8cbizbū5›‚,ú†ĻÅ/žQ4æîeôą.ÁéPS6Čc>ŅQ;‘øHōoT†.;ßÂpšķ0wŌ0ˇ-1]GS(‚S4§ÜÔ3#Ķ‹Œ ģ“Š‚ĖéR ę$ķD ŌĶ"ŌJ 3ȸ†%5p”6rô'xC\s@á*8*LŲ)} Ü.gūHŌí’Ä‚‚t@["5C šđ™ofvæąØ4Į¸0ô9™“'Ģiå4 û…–%>uB!d ø´OáķOuÔxGû´"•Ou4G)ĀGƒ‚yęŗ7ķ>+DōŗZž/"ãâ[xū+Ímäđ%ÅÚ-T_sŲn4dĒ´j*ÍbÎMûun†đÔBÅ4CëQtXîL‚HŦŅŦĘ XUXƒ•X‡uX°Cr´Qm‚Qi‚GŸ>ŖUPu& ĩZuZ­uY=Æ&€´,åKœLĸ/méäo0æ#ų,"$Q¨Î1Ε!ĨNŖĖčBņĪ6põXLLėCˇHhaF2ņÉŦ´VgLĄ1k_‡åÕ6ņyđb"vļ+N)ļļ*6š0VbG$ō'–U[ĨudõOE[­uZG,'pPõÂCĶ‚Ķč•ēčufĢĐ2lv8:mIÛhô‚°Tx6^;-Lū/ķōyHąė;ˆôFZ1@"ĩ^Į´`y­ōj˙5ÃØLëN[ĩ?Įk!ål”u'Pve×VeIVZą•mĢu[™âĨ6.Āí\Ûčęōöĸ\ķļfÖ§\ev,ö ö.—G:ŨĐ˙dN1Xõט BöŌ"ĄtjĢVsŖŗCļNĻQtR‡ŠÕū}õ}ã~į÷â-,ubAϊāĻQ=w˙|—üXyg–hŅĪUˇ…TGe"ÅęwąĶßŧŅ@?ąuË"ģh õëÎM—/O:¯|Šv„IËßd–Ā”li”@ɖ\˜bX”€“lé†?ɅmX‡k†{ø†s˜„x‡8ˆX†iøˆq¸“>‰ˆGI‰;IˆŸØˆ]XĒÔ'ōˇ{ôCŧėk -É,蜪Sôω4=ŦŅÍĘI0*Ô§×/ǎÄöG ' $gŋč‚ˆp|)r˛„7ÎîōšRØCøÍ,biKcu’9’•+Axđū×( ų’7ų'`Áx#7ŅĖô"?•­cÅĮ.lDAĪĀDųŠ|}ŗƒŸ¯­Â ˜8*ŗ(åât”ņŒÎŸ@™|3—]Ļâ58Ɋ”ĸŸDĐSßmeR0tC7:ūgM¯{a,đ›đ‚­­iÔÎŪč´_fšc@†…cĸ™O~ÁĒé÷X; ÂŪšXÛ2ak9G퐯ũRžŌԄdÄ_äŅs؅-¸n‚‹YLĸāVŲfcp0{"Üûd“jņå,Éû1$Û `úĮUuOˇDuŖMˇ‚ö‚EÉHš‘%y’_ú>-6c'y‘+– ėŸ%*×כ-ZÂūhdúPt?)šéΘ“zbx؈X”žš“ š…ŖšĒ§ÚĒĨĢĢ:̝ZĢģ•ús_&&eLÆGØļ†÷ ē7RĐŖ­Âã8ˆgæ”B†˜…š¯ˇZ¯ģ:¯ųz¯û°˙ú…AÉŽ‡Ø‘ā™ž[ą›ąmÔ#ä(r‰“s­˙pĪún.ã­Āʂŗ *Rō¨YŠÍ&”9d‹\°ŗ;X5Ncä^JĒ3lü’zÆãh&đĘkS‡l!;–E™WI†›z†ØŠ‹›°›Š‡Û¸ ģˆ›ģŠ—û…›;ŠÛ‡Ąģ‘û¸Ÿ[ģQ) ķšjp;_øH|‡,†ŗu;ūŦQ¤kVĄw’uMÛuĐYpöu÷T„Uŗî„TBBąy5*čÚp돓ąšÛš_Ā÷ZrNfØI…îÔLšLž]ör_Žļ‹zeęí#+ü¤ 蠚#O ;|#ĖŲÁu HKŗĸ) °˛jį‚kŊŅēųĻ­Ŋ‘úŊĮ°-$ûÁŲFŊä/z"°¨|užî=!‰‡Ū'7Ã#č )Ļ<œ%(m",(UõŗšĖyd>FMŲĨ/–‘iú[›Ë'vcIˇH)Åc/XĨą(~ėģQ^Ûoôĸ×či8/ŠP€9ËˆŲ‹kҍ\Cč›GčfėĻdQöeƒü8zDøäÉ[:;|H?Á Ŋƒ… aöjÂū;.E“҆Ύ ڄīĶWw‘z|ûĖĮq=ˆŨ>Í\õ¸g nå…?&Å=†‘Tn´Ŗ ĮįŦyrĩ_Ä1ęÆd°ŦģןR"á/ĩ\& ƒĘ†‚ƒŸe]/í ™Ŧ[Ŧ+5ąÖ-ųĖ7f2Ĩŋ5áĻ_Ö>ɝsŊÔŅÜPÜãqoˇryK|˛tf-Wm˙˛ĶéúÖ5‚Ôī)đ´Ël öŒŅAėĒŗLBDL:ƒÖ.í˜ėŗĖdÖŊB Ķ/jEjČAķS dr/2ŨmĩīĨ‡Í0[rkœOķŗš„æ–gOE6Z¨ŦíÖĶ!œõ\…ūG1{e -M1ō˜/ęxŲQ3Z#ŌÅΠļ7š ‹„NĐ“šxĮÍâdX”WF‹4+5ÚŅž’LV>ĪčM¯<ŋb‚=¨‰3Rxrø-ĩ”֝ĢOŧÉXQÖ4æLō‡,Ų2,š´°ĪÁsĸ&{ô˛ ÆN"6•ė‹ōU|ĸžŌg3҇y ƒ´jųgū]6@ö&l÷vũ4Q%úŨx e$ŅíÃ<Ф;eÔv-éĢ5kō+Ū48ʘ–đÉåCԂqRā>nę6!(čKsûū_Ę÷ŽƒZÆô@œējÆËØžÛußj4ŅȄĻ—ƒq÷ÁūLXņüÛTķO÷ŊŖsC”‚ęsĸdįā[1ˇ'it*ŋV…Ō´S€Ā  PđB 2Āđ„ƒ ' 4 !Áƒ #B4HđĄBŽ/BD˜Ņᅆ &tŠ@ƒĖ™4kÚŧ‰3§Î<{úÄÉĀeB‰*TXH0dR—!_J`xA—§z$8áiĶ–B…NP ’ęË­-›"ÛŌŖP˛\™vm+˛`˟tsR¨‹7¯^ Ä†Ô öŖÔŽ=>Mšp*D‰5Nĩˆái\ĩhUÂŊL6ķ[ļœģvöŧųmËš{Kë¤`gj Ģ[ËtÍZCßĩn˂ž\ëmڒiˇėÍūõsoĨ[Éo[4ÜXCmGƒ+EæŖÛũ%ŠĖšĩ”[Đim_-tÉŲö¤_˛Če—9ŲUA5Ąz†Ĩ!yaIˆ’n!%æ›F'D’Ĩœ mdÛYČI6Չp Ęߖ]ēčeĸ<-˜[SO‚õqūb:e•Ą)Ґ6‰V Č…ļۈ –8č¨J2e¨ĸØD“@­Ž›Í1ĨŠVž%AĮ-YĢ^%wAP~øŖĻÍúĢPĮĄõ\”“úv+¤2”ĒĒÖ¨Ũ’UĨÕŌDTŌEíAHY}ˆÅ 'juÔŨēÕi–o:v'hŊĄØe zmŋ51ęŌ“šFÉ]`÷ūˇ^Y’ėnŽc)FÖUĄ–:1ĄŸ•xąˆ!­čoOüžæņŋģ•;āž%ugĀ)†É¯Åæ–,­L2\d\K1üƒ 9°ŗWVÛqĐu9ÖVaĘ.ˇīŪˇ_œGËš.b+åɕaíņšôžqIuåūZ$c\1h!]ž2},´ĸã6ą‰ĸu]Ûaŋ=÷Š`ˇņĘ^ĀqÚtĄ–Ŧt1˛z‘ÉTĪŋųvU8.Ĩ¸Kƒš…ŖÃŊ ŧ82÷ÖtÜl™úyÜĶGļßĻ×táļ%t)Fx á÷-b&•ôæœQŗg!Iâē$ UΕa6ŠÍĘΞž<Ļ2g¨Ės&ÃŦK)ƒ‘DÆÉ]aūXb@TÄúhNkj<×Ôæŋˇ¨%0Jė4ß Å<ĘešåËÖõbš:UŽĨ}ÄęŅ,9åÄä҆^ ņÜ8­Kĸ¤įĸ–ÉĖf&s™Œ¨<)>dúĨ†=^´sÁ†pŽ#š›Ī$›ĻŽ ¯ˆQŖP#‹$D…vŽĸ}&fÚŅč͒I2ĶLáfeŦ ´I.%×?'ō1cLíOBPMĶŦ(Ē9}hpô8QxVtĢ}gŪ2:QiN“Ē?1¤É”’ÉíNwTi$׌°„āô‹†@¸MŽf5žŖēN̊-š]Œ-íģÜAÆĀ–ŠL:ŊTĨä–ĢSōuęá(ūv, Ø˛B”ĻÅ(V)JE~ĩĢzģ€Š6˛ÎÄF?- ×â„'J&‘™2Ī„ŠČJ^„ve:jIĩęLĪn毙ĩŽpÜä2šĖm€r“ë\äˇ ˆ.s§ Ũė* šÜŊ.rŖģŨī~÷šÎ ¯tÁŪįv÷ēĪ]ŽrŊģŨã^ˇŪ¯{ŪûĘWô5/qëĸÚâŌÄŦžėĨ Œā+X$)3e‚ŧāCXy’ųoqUgŅ8q\„N吘]šk%Üi­§ÁĮÍn^%íhQ%āûÍE˜•ą ¨]ą­;N¨ÜJÔÍā3IĄŖėãŊUņÆƒã§˛ūčJúOąŦddÜĸhąÎSYĸŒō\ÚŽŽÉdžÖ\\æę YĀØÅozģûféĘ9Ît†ŗį|į:ãyĪđÕŗŸķ č=˙YЁĻstƒ™æ/ąîĒ<ŽĘÉ|•Ĩ“ė>_Ū;ĮøŸf‘€6í,4ũščP'hEõNȡfS˸ÆĒnĩlFæ>K3)3t6vJ%6…ƒ%ãŠtlY¸gzē™ĨvĩŠcRlcXŲ¨ku˛ĮJMeŗļ*Ū)‹•˛ŗZ3„f˜ãÜÔÄâ%ėNZVšõ÷b@֔ZĖnwObÂąTģ{ĩķv5ŧå X|—Ā"͇éˇKvI{ī1w$¯ū„4éHl ^žŦē/úėzĮ˜4—xģõ=JP€Õ6æÆsJ41ņđ1ۖەšnŨŒ¤ôĶ$ƒ–å´ĨøŠƒj-eë™Š[°}ãøÎ ŠėŲÆzU ėhīP‰"ēmÉ%žJÜ%…ĐHļM’Úe}‰ĢßÃ;CP˙|ŪäĶųØĪ>Įķ% ˜fGģéBδÆģi„æž4Ф üeÚ*Î!Še=Ž9gÁŽąģ=Ņ×ĀڗčÅÛ¤í’ī×](^yķ[āO<ŠnĶÉMāĄ kUŊc\ÚÛ­ĖnĘč­ë÷JēĖ3ōĢ5ēą)/{aĘdĒ3Á}îEū´f)q]ūiÚđõDüũŒ åÅS>[ˇöRcM–\1ügmŪGß˙Ūoņöhßl/jŌ€û‰*öÉĪ"YŊméYwéüės–Ŧ÷}>ˇEĪĶĖŖüŪyękfŧ˜˙ŸUЇ~2–:hs~Ļ6~h G—€ Ø%Á‡T>-Ú&ļ„K$kU“xTGOD%f1FĖV›ĩP¸jÍf(ˆ‚-˜†r€.Xęˇļd)Ž„Mƒ2%ž(Ī‘iũwI ÅEXÆ)ûKâ„sæG1(ƒ,"~5Á{ȂM˜ßW{ThC„ÎÃzĄŖc !,8(}UV;#|s–Pa{¯7 ūLˆ…Ĩņ1mĻ^č‡qt†âsxhf"B2Ją,_¸S4&HâBx3Eöh`‰Ŗs‡|H‰ÅT‰Ã/Ũ…—øv…crįh>R9Ģ„|wUŽÄ3Ōr2ˇŠ eˆ¸–ˆX*j!b7ˇnČ1‰œ¨Sx{ēˆ‰˛Ą_ܕ‹ž¸{åVm)įQ'í‚$š“2°h[ĻW&yS.Twj5‚zՆ0ŒÄˆŨH€Ūø‹âøvXĻ>=”HTFWÛԌˈ'6Cˆ›zÜ2iTĄI-f‹_ŽäØįiŧ(9aHD¤MQ“[î8.čaáb;Vá5ĩSŧ#s€3ū‘ßCzÂv}zĶŠ MHäx>Ô1’ ŠAˆ‘T“I+Ewg5ŨTđĸí.ĸWŪ‚0žr÷§Ø§$‰’v1€{X”æ…'™”)yKÁ:ؐ/V![&ÕVhRzøØÆ'’Xî(\™LؔgY…‘‡–ģ’kÉP‚Fé|Y#‘&W• ÷[VÁ'ظ‘>irߓ'”‰G”n …Y‰Lš–ĶöA\(ø÷|yIō.”Æt°e™žŗa plH–Ņ„˜IÉ{ŠjĻI’†9j˙FAĘb0ö8 æ8ŗÔZĩ)–‘ķ°y›ėĘQPIH–ŖūY4ĻšÅ‰š™Ehl¯yrØDI4p¨DmyF"ĄI8ÂFcT‘(EfYœ%$’ßiQ(žÕĄ:_Vrˇ*7"õœG&%Ļa“–Ž âƒC8›ˇØYÂY”ĮicäéŸÄȟ•˜œŨ‚eÔSC¸/)HÔupŠļ1A6D›Ā‰sŪYžß9 |ØĄ|8m%‘ŒÁaēvKVKĒčšáö#’ŅƒˇT%÷hĸ›ņ5ᅠ‰s*cHšĄ?Z~Rmú Gĩ)T:\ˇMÍšN9BWãCÜŠU:ę>ēx< ¤[ę”o1&=4dŋ‰,ņ™ Cn_zk‘@ūÎŌŽžFOJĨ2¤Ą\Š-j)…t `xú‚šqGq‘ˇSpÔ֐3ŲrúW™•´ki;f"€c|Ũäk"לę‘zꄖꍩ#4ĻŠĨ§S ’sŒKd7Ɂ˜™ŌwQY'C5šR'8š'š#ŸKt#–ŖúiĨūØŠ™•̞Ģ×ry§3’ŋš64ȌœW–dŠ$pæ™ņįĸ:NęÂø# wU§ƒÕ̘ęjšhoø•đeŽí…ŽįĒŽéĘŽëęŽčÚŽņúŽķ:¯ōj¯ĖÕnbŊĩ;{iDöh•ŌØVR0,…wđâ:Ö餘D1šęÆn⚠ÄęūPBą^ÂG8aÆą;a•æąëmę˛čIâĒjÆēØIäAI”9?ÉZ2 ™“‰)Ž$¨V™'~â°^W,”Ėō­žČ€qxąoI(čF'dd‚Õ´bĄOJë´%YS´´ˇŌļ?uWœöŽ›ÆĸŽsn”Ö…MZŸŊD/NF/”zxÜ(ąØr´ųfoĢ$˛%[ˇw{ƒ${ˇ–DvëKwrZs+**&/ “†ŧ61­…KAˆŅ5dOh ~iQn8"Cë‹XzvqĢ*  KI†"AŸĸķ´Iļ&ēŖë…`s ›PÜĄœ‹ą?éZøEŗ†FčC՚ū#$ŠsH¸ĒPˆ¨„X…šâ(ģsDž‚;Š,ÆirV”%?Ŧ÷iĶëī'ŊŨɁël~Čh¨¸S<ĨO†ƒÛ&)'šŅ+3Ėĸą4˜é–ÉûļiFŋÆÅžL 0—™&ĶĀKļDärXųNw2ųœ_ŗōŖČ­"š;qÁ‹ č‚ˆŒ˛™83Ē+c:Ēü!e‘ÕŋlĻ8‚7×ļŌqŋx¸ŧô´ÂĻaGÃFLã|õé<1Z2ūTT͉WįœX"ĄQ‘‚Xčë(ųAĨW"ÁlÖž ą>æ8|o§˙+zH4ĘĒFU‚m˙įX–ĩrī€`7§õûū2ØÂNČh_72 į~$­ōƓDmҚāaR9˕rŽdIŠŸĄ˛Äû6Dį8äÆS !ŗjP–aAšų[x%KX3Š:ČDĪ‹Ŗ)ü šÆĒШzá˛rŧŗ|œŽēŦ°}LĘSƒŠaXq¨D,.ĨŒÄû¸=ƒĖĢO†Hë¤Ŧvü;s5™tō˛°*•œ9Ė“i™ŸYČŋ•kdŧ„fl\áy{kl‚RŦͯŗ¨˜ŗÂŦDņĘru€cļ´Āŗ tü˜2l*›Ŧ*I„Ų§åÄ|T؊öLzäŒu9°’p‰Ę;ČÚĘÆ(üCđœ˜GénŸŒË§ÄūĘ9Äĩ\5A;y&g"Ä}Įėņ0ÉúŗÜĮ>|ĐāŖË€Ĩ¯í™‰R‘T•WiĮ°…N™ōǍĮ‘KbĐĨ:Ã)˜7%ÍEŲŧß[ϏŒXÖĒ.ŊŗÜβĮ{<ŅVguāáÃfá îwĢōtŌG—Û*•JÃMzŠ•MJ$+‘Ža3‚õƒi͇ēAK‚BĄĐAŌ ŋasnAaģ˛OųrØė5Q 3y %éãTĩęĶ_ĩÕ9…tû$I–¨ŋs&$æÔ‡ęxÜtR—ĮßBÎĢŋšSĩA+ŋ1×TXšÔ<{9vŠ~{`ŦíÚÆC;Få`{KÛÖ3‹MGū'ĪîųA#›KTˇFĢēKÂķĩUQkĩMÛāŊš§\Ôĩ_ßU]ūĨ^rV_ī¯ÍŨÛ­_Ũ=gĖĩ\ ā_Ō%Ū֍ŨČUŽüÕ^×mŽā}ŪÜ}Ũé…Ûh'+aęēĨ;ē¤ĢßĒŠųŊߎēH$Ĩ tĢåß;āV{ājz;ŦÅ<ø—EX¤žā=–s hOJužDÖki¤kŦ†r1ЉF^ęĩ¨ âž9=O\’Z)ËkĘũÚ3ŪÚ]$ã7îą4ÔÉžĒÚ8îãÛ26čKÍiiéķãKā%4X§’´LĢS{0(/9(„đâWkŸ‘ĩŖÖ€‚k$ŋã{ˡū´­ö`ÛÚ ąĘöŠāo~dúËc‘Æáˇáhč&P^įŠģ7›{ö¤Á~qļQģätˇX)ücc¨ßôébëņx—Ún ßm]—]ö…énÆéüĨé–ęÚÍéāÕ_›nęt(hŖę¤ūé^ęĢūܰ.^ę­ęĪĨjˇÛ4Žëf.k3äžë$ėyäģåÛwMBUP‡æĀíÚqÁˆ)~X…ļŗŊą3ԗånöDíŊ ˛ĖžíŌŽXŧÍÛĄ æŪūÃ`îéžK¤Ũnķ•]öõî´ī¤N^ņīô~īíĩép†īö>hë-īũ~Žų…ŽīãuZ;^Ž;õūäʂD^įŦ‰ßYž_9.äāMĩų:I>=:į ~ß UánNå|ōū]ō>āŽĻđׁ”/…Ēũ)¨ņ>âl͏k8NĮŊŒ…Mą|!o­Ė ší@v#ķm”Ōlų{ôŊ@‹ŊJfÍaŲT=Ŋ!âņ.o(ËÃä"q+ķ§“ąÁ!Ëtl㉜`•‰ã—ŅΑ–KN7í"ãŖÁ‡Šļ2*ŧ$æØųÉčDš"|ņ5ČNė›Dø>ÃâëûziZæd Ö÷ĸ#VŌLccOŽ`B<ÁĶĘäÂw>ŒÕ ĒÅÜĮWMúĩœRB[ŗÃķ›ÉÍ­ĪÎ/ĢėžˇõīÖß<ū¯öņƒX LîM"eęÛˇž,/‡Tĩ¨ĸĄiĸôtÍüŊĮ@ߌĘMĘLÍà_ËŽŧŦ×ß“äųãlĘåá:¯œIh?Ž:ĕâ{^l =kP_ˆ]­tTã{UÄ+üŅnˆĩ8qÃ@ Ä0CA 6th°āÁˆh˜QãFŽ=~RäH’%MžD™RåJ–-]ž„ŲRÁA0xƒN:wŪÄy(П}.ôŠ3)ÎĨ?‡u(@OĻ8‹ōŧIuĸTĸ< 6Ŋ:5'҈5 ^ŒÉmF iŨĻU01ĸ‚RŒŠđ„Ŋ14ūÜ*‘lAĄ=iR \ąđa¤Š֋”hÁ§Nu*ŧģĶhãšCWqí[ŌĨMŸŲõjÖ­]‹d€ĐĄBŠT%Ĩ –˛ÕÛB‹JũikUŠGo‡ŊėQāĘy}ĒWË~ķZ|­Auöė3+ ØĀŽlŧ˛!'^H;'ã ĪˇnUH¯Dŗ 5/”9¯Øûž/dHîšÆîĘŦ=ü+Ë ˆ#¨î„0ÂŅ"¤°B ?ōÎ<é& Nē¯x›Ā3¨vã¯˛Ļ–ĘmŠŖDŦŽÃč’KHDŽTŠ,Ÿ’Ž1Â&ŧ°G–0K( .ūŦûëŠĪČ qŊÆ2Ję6Ëk1ÉūzČ3ĢúډK:’.ō˜újŗÅöK<$ecĀG7ß4Š­6ˇƒŗN;ŨŠ-"õfË ĸĀZ2 ›M =aüĢʃMT/ÚęĖ1 ɓ+ŋAũ:īēąús OŖķN—fĒɀŊ0˛<ÂJtr/à Ę0čŌŗĒÖ2¯ãmÕY9ãQŗæĢhËûŽÄĘIĢ0ÛUŽ\ep!E…ÖÎOŖĨļZ u4ëWJ1Íąf •‹ŅĀøbÉn  ŨHŗĩOMtōķˇšĖ›&CĩvĨ<" §!›uō>+ÛuŊŊx3в^LP31ŸĖŒD Zˇ‡īz5>-Žu"ˆ””Ázūķ%ų5|KFŲÎ<ßE XNŖŠ¯assWŋšâÛ ĸu÷$÷!™bhs˙k4͗ņzˇžO{Vģ”S"U˛Ę’Ã9*Mx`‡gíéãÆÄÔ&x ač.XĐž ņ{x'Ā„}¸ŗž ôzkŗ‚âĢDĘękđiŋK;ųoÁ/T-ęDŅķļŧÄkFZq5v<´Æīāü.˙vōÚ4mäÁ=ĘPa R(oĘ6ąŗ ĮŌ ė%j[ėÅâfŨ›Ĩö)ß HcĖcQ3ÕeŨ=?Ī?Gž¤Ā“gžĩØH§ņ5Ī]üņtĢ—^ōJ5×rĖ!īŪggiųæ5zū÷›ÖōūãĩtQLu9ŋų‹Tq—ܞAĨ˛]dÔķ?EeŠO€˛įΡ@¨†sæc`eĸP‚l@pA 6 ‚Ô -Č r!4!C(Â~P…&Dá GXB*`…tĄg8²0…5ŧĄøÃ JđAš‘ϞĒā!î|ƒLĖX@Ėp[ëŒÂU3ž…ŦwõšŸ˙˛wĻҌ!ßÕ8Ã9Ļr‘ƒcå8G:ÖŅŽw¤#!ø’=&/tC@û e†E>øáR˙ä>Ÿ1LGŦRÕļG¨´­-Sžbš‚¤q‚Sā'Ey’ĐqézĶËū*U9ÆT˛r•§te,ay–Ķ„R đ“–Ļ4ÉųiJr:ЏC˜ũ•Ģ—‰ ׸&ĩHĘiˆ6Uģ"hUÆQ2¯ÕÄfFâÂKNNJ{k˛^ø°÷Kę}“œæ§÷ ˛'OĻdNŸd¸"AĻ gÅĖ˞å›&YgG̈™‰(šiŠ˜}úÍļ—Ef>Î,is•Í ŌÎlVÔĸƒķCŗŽv”]õhHA:R‘–”¤'5iJ€kēs” (ZDRÕÍ*ĨM,ГšbÚķĢd6Ž'hS“{,,ÍwVSŨĀt6)5ą"uŒ-/úˇ–Nõ–͌ßčÍ8n_å*ūŊ:ΰ*n/R%MUũ֖ fáOŖ‡Đ…€B›Š\ŋ$0Jŗ‹kķZM ¨üėĩx R˄“A=g¯í[ęŧRŧPÔĒurāe­ēˇ ŒÕTG‘Kå !—ē^ū).ņŨ5=}Ũ¤1ęÔ>”1ŦÍ_ׂ%…XVŗY@ ĀHEŒ’|rąĸîuC W"ēģ˛L….@9‡˛;5(‰Mx_!™~š%Yņc4Eˆ\1€ÖßZKNjmoķ‚;[Ī Ë¨w%^‚ iSæ¤×/˜,zlJÕî‡ģeMÚĒhŸöåd+ė… žā[2\¤ 9ĀLūaĻĢōÚJkLíŌŽ<\<*ĄéģnW™ģįļ˜ē “Õy9sLJRRŽ/ĩ|›cä…Î(øŦ‚ĖÆÛF‰–zC~­/ũé-` R …ĩAĨĢWVĒŧ‘ĖŽ]ĸĀ §ėyyëNP>VÅÄ7˛jE0ŗKÄŧ ąLâ3ÕPŖhɆž¤” Zæ1fÍŒĻž2Ĩ™Äk+Û čģ“]‘W°ģ)UÍ[´%Ž´hEš)[q4E›,ŸfĮ Ž–Ny:¤Ėk["Đc† ãĮ-‹ŠĮ‚.o8ŸXs-`ã–Õž„¨ļíUũÉęzŊlfWČĮ6 2īXū]ŦŨuLxÔūâĩ!ļm°åúl1~Ŗ 6ۈÁēÕ.J֓nûœSäkŒÚŒx‚\ŸõZÍgÎ)î|=îŋøG6#†5Čú'ąéąpÆĪš%­ģ Čøn­* ›Ũ#:uyâÖ .Ŗî‚,Z Ûà uÁŧdæ`WÛF™ĩ™Ģí¨“ĪÆl+į•^˛JĐĖH<-Į¸Q€HoÉs[5ÚĖūŲsŠØ¸‘¨4”jã…-NA3ÛŊ0Ÿę_EõL4§–Íąū7wŗÃ¨ÛT’v+ˇ˜‹äYķ5ņBŊr5oÅVm[*¸ŋ D_GuiwœŽÚ °Īí,R¤Šõķ}šrĒÅįĐˉūŊMrFkŖ‰U ÛÁ+{ëĸĘûåŖ\ Ą+DX:ņ‡dš”âGŌoŽ3‡TĪ^ã$o¨ˇI¤iä!uŖMĶgĸTŽ2Y9Ål(ė3Ģyf‹x™)82ÚB ß Rŋèˇ¯´Ũį¤Ļ+†ŠgP”¤7nëX­k>­lŋ¸Ŧœ{ŋGyr­üø`%įļĩsÁß_į§}i†VūäQ-å;įŌÎĒļ1ʋŨÐQŠ Ö žUc÷s>>Yēôr3ø¨Éšmq".ŌEJ˛ëpŋ%c$4ŋīû@?ŧ뛞ƒĻîQ>Øņēã&뀤s˛" ‚ĸ`Z[kƒš:Ķx75Z€ū2zZ>Ķ?Ēš""´@ô"ĐĐ' l(#ƒ&7{Á§Z&ęsŒT“î Á#ŋ- ?Õ(ŋ,„ô;mņ%-š+Ąa Ŧœ ´žīÁ'äĀ-*CæS¨ú“” đĀŽ˜/Ô1ŲP ģžÉ⠁Ę?ķX–‘ã¸'; G ĒÉŲ8ÛēCŨi1… ˜šÛ)Æ; ,Ãˇ>ÜD )4š1Ģ›ĢÃ@)œˆ7,Ÿ$HAj#ŞDB (XŒŒ< O•/s€ĢŅá*B:$aËŌŠ'™ąÂˆŌ$wĄŽŪŅ“%+3žš;G;ˇ˛ë3ÆĐÅOÜEņŗ rn$1t•›ø,ūę‹r!4|ŒT4Ļ5ņ“ũ‰ē7\ē˜á™é™ÂØđbĨwŒ BŲF‹Š'ƒãĘ0ģŧq Ã5ˆëŅ!ŗ‹éB4Ĩi PŸöQĩsšt{ČYA2+á@p˛S?1ĨP°R;} r\§4Ų›ũÔÉ^ëĩxaP× 1A-•6u{ģC]T 5ĶuFL¤ROáF$ %ú;~kS?u#õËF>‹&Ÿ+žSd–L1uT˛Aōŧ;”ÕS “ĩ€ÕX]–LHå̧ČāšĪėā1–ģ읅 ąāÍ[ŠF#GĄFFš™…ČSį4Ŗ?Ú9‹ž.rÅt<4 Süq< ¤yū˛Âp:ēU-B8ēa"ÕZĩÕ+Åú?,}×=m>*¤Ŧķ°1u%BbĒ"JŠ<8Å)rEdō3š›š;NpZ0ėĐÁQǰŖâ`UTlŸŌV1(†ŅØõ+B%ĢŠ›ŧ™…õ•Á‹¨Bō‹iÕQ´ w­WŌā<ü¯§sBDYķø?Ci¨˛X<ģ3×wdBá8UˇÔ*zŠĨpŧ%y Ŧ’JyBT(n}žėņTWM6>۟6LU›ŧXTeØ7ÖÍyŲ•8™‹x§˛=ŋÄŲŽϰ•ą\&6ÕY#6gŠÛ- ČûG=éŲtēŽēĻ~Ū‚ŨVčK—Ü@é%ÁšĖ–įëX)´ÃÆãË˙AgéÉjj 1äZhuįë/Š CššÔ(_‹Ūtƒ¨ë‹K)ŧŖ­äŋí¤x6K yl˜°kg‹ŊŦ§ã¨XėSo…ÆŲrU†ņÖ¸Žlö-Ü×EĢÔɝÂtYí’AĸqZXŖE4ą€PĻMÁ~›IŦiÕęŠ)‡zÁˆîũ~íƒXîXMnT+_DÂ$qÚ%ãĮēUˆ É6E-YĶ?ü3įUUdÔYĸãØ— <õšŲ™cÄSúo•V'J…Û,aŅJ+ĐÕaĩ(ÎͧėĘĖÅū=ū^oq q[­ĮFīđÖÅ?áŽ7˜ŒŊēPėŊRĖ 5W“{C’ūûØģ[hs:īîŨô[oâÆDMæOC”æ~ŗd$mČÆø<‹Æb1ËÔī-'ņ6ŧņXU€:G _`Ŧ‹ ‡[RKŪWlPnĪå)*QN\ĒX1Ĩ+ÆãL$ßŖ>\¤”8ˇ׿ō7OĻhæÉČIėĩ&Å3ĢŽgôŒĶ™Ô/q5Ąt;…ዺķÕĀká2Čãę•`žû…¯rt°×IVÃ@–ÜõÁ€QSVáˎb519WZu ŅrLŋôGļę܍[šLÎIlū=ã ˍ2ŲZŨv„xvã>nĢ%-?ʤ4Ô­ÔônĩŨqQs;^ä$9ļsJŽƒšĐœw÷NŊc[ģ8{¸y9ŲZиrQimõÆtŖE I›DēƒâI‹Ė_­vĖ’ŦPö îīÂn–s¯×W‡Í_ŽÖ‰`LpĖ„Ræ%>Ē#UÔJL3! b„‘˜ŗM‹_OÔ+šGĢŧ`GÎÁélŠvØfīãôé|âĨ@qēۚ—&ÚŨ%UGõ°ų—€ĶČú†X eŽ}%b€v›ą3QÔ"“Æâļqų‡käEš^wގx÷<Қ¸™ķėŽ ¸lO6+VŖ†¯zøiŨųŋūôcĻ0’Ũ“×ĩžú‹Ûną¤ûöĮg^ūĢ7I:ŲÁnԈ­7ų×Ī˙Ņ—UgĢĐËí¯>}ĘÆŊ\ˇ¯ ēŸÄāTqÉXQ†Ũ‹\ŗK`&ĮvĘ<Ŋ¯K…ŋįTWŒÅ]_ū!Ūņö&˛&kŠŗ­šnV‰˛îËĻ[Ŗ¯Ė_ÉÂéüĐĮˆ­ŠÎŋ‰ĐōΈō ī˙~đGĪĪzŌ’w -ũŊ°>Áōe ‡–GBnu@€Ā  œ aA ,(Q Ã‡!J˜ˆ°bD‹ fŧxQ†’&OĸLŠr%˖._ÂLÉ` H‹ N@h°ŖÂ8ū/JėšS'†œ; J“ãÎĻ’&ŧāķįG Lk:í¨ĩŠÍƒ$c‚ +v,Ų˛fĪĸ-ɀBIÜļûVnI pOÂÍK÷ŽÜģzãōM{–­ā†Y*8`1t^`ĖøæP…WE2¤IŲc֚5Õ8PaįĖQ1Ś™¨VĶV•˛fpx6퓄MÎT úĩîĸšE.~H:2€ĄÁĨ’æ 18E P•û\x!ƒÁŠŦyJ§YĄQÖŪi~­-~<ųōco›tëˇoúõí˙ūÛvņ^Æé囇‰>?˙•‰JAqUYGw[udšh=eSw;9ÔĐnUÄŅUOÅ`Vßm¨ū”MX”Tģ %PxũĄVn]y֜d6˜sĄap€ÅÕô"E3´Øj\ˇ“dé†! ÆH#$z•ĸ“OB‰–zėáGĨ|đíEĨ{÷öä‰Q:ɀuCNÆa‰?”Tr ŽY„)Ø\‰$ūølĪ…4§k4ž‰āˆ U˛ å~+š‰•Á—ZWA†ˆsŧų8PEĮUjŖˆCiČ⤐&¸iG<*—&œjĮ䗅˛Ú*ŠûŨwå||Ņ÷V­ņŅįW­ļÎę*nĀęĢx ÄY⍑„XA”ÔŸ,*ˇæoz2ä(e8­–Ü€†(įĸŋ={†˜-”“ŠŽū*l+2ĢdD27Aōž;¯ŧÄM/Ļ8֋īļōŌûnqCžë¨dc2ú"c’\/ŠĐz—ŽēSLĄúąŦIŋĢÆ×vqÅâ5ĀÛE Ël9]AüžüŠ„#Ōېk&ĪYęByÅoDÕvļí™rU`PĸaȕČ#Ķv(‹†´o ÷[éBúV=°ÖīJ„ĩTīK“Õ3„5Ã%,•Ų(hŠ:IĖ´Üs›7ZwL7°z§ÅV  PãąÅĄēŖEu瞁\J™ļVų,įGD˙IaĒ8ŋ\ęeâøĐU}’ÖįAŽõi§Ũ|§ÅîÛKŨXf‹n]¯ĀTūŋëP“åË6Ž3ŪNõĨÛÂ~͐ÄMÄ\đXŖ @ ŽēôŦF?ŊõtįV€Ę]g¯žÉâ;ģâ]‹Ÿėc)~į xoû~$t÷ Ŧī­ ųuĀÕÁčrYÚõ΃D=[õû´FœfkÛ]ü’AHĨ-yÉĶIÛrw˛ØY R°ƒā¤ōĄ›­ÎD\! [(šđ$bZHr€īŠƒ Đĸ2ˇœÎqmWKˇÛůs+kXĒ’%ļ!FĻGķ’b|ø­×øđ_›gRŊļDu×ņK$/ØQ0!:ŌņŠ˛Æ…‘fķsūņp'´˜‰D*5x#Í@%Q ų" iHėí­.‡TÉL¸ ĀgáãÁÜHIHrwC<Ÿ&…¨8ÅąŠđĢH0ŖÅOv˛Š+ķ×ŋ∪+%Z9C™§õæQ劊O#@§Ĩyv:Ûö3įĄitŌ—AZæ"úFD!¤-̉1kŌ†š`ĖŪė4åĄSn&‰J\å*CEOĒm;įŲæ<'˛sŠB<į95IÆÍS‹™Ą8=ŖM[ŠŅy—›ˆ´:FSe‡7âÖĻđ(H.ÂÉ7[lJēÕ5'&é—Đų'6;Z7ÎĻ–MĖE_$•ëü.Ž5ã]ū õÉÆü=å_ÔTÃDķÉå”)yí+Ÿ:s"™’ŠķĻō<įų(RlâĸēŧVŌ$˛9Ū¸ 4q`i$šQ_ÚÔd ĖÉGē#‘`‚FÔAaģŧԺdžh5‹Z[ČÍE.:äŌĒįZ„œkŨD'̓wūTQ UŽĸK‚–fەåi#GĐįÁ&!t’RҤqÆ\1W;3KĨ2… 6uCŸÖØĩ.ō´¨]­ #"™´/}2“č\1ZęõfÎėâd 'Ēė`vĒËbŲfúd4É6´Ē;9Ē5“*M‘;– )wéY;aQg{ō ļ3-Š(é29ŅŦžūžĻ*Öĸ7Ŋ…ik ŲÂm1ļßåNŒ¨š™Jîpsē Ë>ƒĻËZBĘáY#ēáZN+<ÃŽFÂÜjĒ P€PaHøÂư…ĐáTØÂ ö0…IÜa _øÂą†5ĖâÃÄ)îpNâßøÄ ņˆ_ŦcÃXÃ=Îqw\ásøČ.^ōÕ‹Vö:1ĢUĀLÉôË:M(5Û-A­ËÁĘ5gVAĄi%qÕqSM•ĩRXՂ‘ĘŖķˆpĪ4gå†ŲOœa0™'ë2ra7ĖÃlÍf=Č(?Ņdķõā ŽInëÖ@ĮÅĖíĩŽĶú3čū;OîîÖ40ˊ–ņĒÔĨ>­Ŋîw[­˛–¨´ĨŪtS8û#¤čŒÖķmuøÂ—ëƒb€ŅŠ–ž°×(ˇđ?zYĘõĘ;r´ÍiV_š-~+PšžëPJWĄ–†4{%+°Íš^÷fËĶũ]jĒļÜ"ģ^Y hę3ģëíæSŋ›EÅļŪ€l~oŦŖ„×ėŽÜņ'sÚ#=GÍ&NöeŪÁ¯dŖZßMN\õĨįPz-ŽX›—DŠnŽZriŅP! ˇŧtŗR>"kY<ĸ.G9Ígnķšãüû¸Üdķož \'đŪ ‘5išījŊ[™C|ĒĶųQO'§&ĩæūŖ@bôéŨĄWÛɰdĄ1jø+ĢF/0ōCîGŲĸõSyŨ.ĻfÜmž–ļ}I4WCī*sĩ¯yl ~Ø?ˇĸ ā° J$*ŧNļÉÆĄ’ˆEė$ã5ÅĖą&ļP4"€|ČųČ?$‰ˇˇ™v.ŊÛËĒ Ŧ@\CūÃîvˆœ÷,qĮ˜õ æûÔQÍũîcžĀĩĻīˇĐŅ&€;îĻlĖ×8ķšI|‚īéITˆK•Čžj…Ëĩ@L''Ņš|€m˛—eOÕŲUÍMŰž29w­^šĸ#uĻ)ú4'ŌeĄé,˝˙æúĪ?˙%2üā`ÅüßÜŧU%E…\Î@Žíˆ äūŠŌ*ņͿБá ĶæÅ–¤Ø Ž˜>q‘´p`㊍SȔ´y×ß9ŲLTûT@úaÄhP•fh Dd@ƒø 8ņW™}dH’˜KäčaaŽ ĄM ` žÜIŦEųL.ڔáÔûÕā9KŅOÃyRžßøÄ¤Ņe^ĀāĪd8ŨÔĨõáŧˆĄ<ų’@8!9Í0€ :TNÉĪú4QĨ@JAŽ•! Ĩ)HÚÛ`åīÅÛn!I0a{õ^Ončȗ"&Tyɉo]ؚøĨíŲŖå—}ĩÜÉeÜ ūÉnEŠVHKuXA<"ß ĘūšÜaēá<ŊaðáéDA Š Ė´×wfåĄŪ{ų#ÖÛyrâîũZ#ĸį{ާ{VÅŒ‡eēJÉŧ%é Ø Ô ÔŨÔSîÖØŠ’ũ3UøūüÕ§QíÉpJÚ DJöŲ<c BhWXËlõ' JČå)â[xbåCy¤}ĸN#iÛūąh˙š¨rÂ^‹Ęč‹ēč ’eY´æjĀßhGāĖ&á , gâ\’2Y†Sž"ũpDqĀ*nÛčq×omÅ9VK~›oŪŗ čĨāJ^Î[ŠŠ hŨ…DfhY…<‹uąŽ¯õ#e’(xzÛCtŠŪ PaßA•ĘÍLa‘)d@ÅBąŽ˜!ž áwiČZŧĻ9ŽDŽēDlO÷|ΚęĪø¸ÖŌ-QĻ^aįQ]ÁĄųŦXQÉMņˆü(ˆ–‰ŋđŲ -9įÚūå͞ĨŲ)M3yČ)ˇõUíiW^MĻd–(dąFb{ƧVÖčė¤Sp–pT)`šEôą.ë"žg+ĸ`Ŗf X8*ZG ]@Ņ9œÁŦ“¸Fü\ ú'æS(}šDvMōĻqážĻ’ÃõëŦޝŨh$Ķę) 0%TwR—ģŅ*]Bk†˛ëoh'Ž(ąnäN +QkŪQfŅpQVšYVe —ˆŽ){>ŖŽĨåBøœˇĒD°Ü†{1j5 <D’3R’Ž”Ņēë%eQ-ÆI¤IyPūQž= õ ŧjčAeÆÆēJnl(ë}Ŋ*ū wĒĖ žßę+sJ۞âß/eąÎéŊgˇōģ|,dë~ÁŅ)ŧMVčŨ:hÜŽ­›ÄŌė›Õ>I"mõSũtÕ Éį§Žmõ%,›"ãF^孌9))į‰!ĶĨ„ĸVbg ZöĒa†MvŲráÎt¨×ƒ“–"ú-Æ˛­Ūųaeîք`Å ŧ=ëth˜‰hiĮÛõîí†bAÖÍË~kK žÕqP*ĨTĐžT¤Đēnô%eĒbá×íŽø ːoIõ÷*¨r¯Ņ6Ÿi.ĢĖyՈÖNáũTĒų¸“ė ãN5dĪ*]ŲX™œ¤­Eū âxv$îFĖîÎ-ŗĢ€/øB­CęáĒŽM%ŊZÆ)S­Pj€…Å,ĖvŖz.¨dËdâ iĨʛ(PļÜ$/9Ę[ØŽŊļ°\L&†čæ\ ė áŌväâë9­’záøö/äJdįĐ+ál‹9)îÜŨ“ī&°ŸWyĘiodE™ĒŊHíøˆ×DNØčËņVʂYąÚäD€cI„alnT˜ŋl°5 œŋĀ˙-œ‚FLĢ MãÕŧÍĒ>ĒpԑCŌ˛g/˛ū S5˙ÂčSËäŸy—B4ĀĸZôI8ZĻ-J¤á)WsH,‚톙ũií Ēhŗ€íjĨŨ(n[3õQĐ"zŨū؁áY*~ˆQ˜ītļ°įBuSyRž$‡Oąœ/īQ_1Đĩ#8īŨĄz†´DëīvÅ5KPR×Ov6ßégkŠRŗ˛‘ļ~bE?™ĸ\ũšÂL,ę*‹  ņ M$ ƒ} Nih´Ēt°„3&’yōĨyEkĘÚ"•Z/h„v*6&QKwˇí>COā‘–Eôū%$1ˇTÖõē5ĢŅhyËdS¸ö ŨlA܏žË€ 7›!ܧŽFä čgūĩŲļØÉŦí–ļH V`ūuöķY3ī–vnĻ%čĀ5eXĮAeų#įđ$ŒDx¯Ŧ Đ|_í×â8÷Ũõ˛Ž|¸\Vkma–j͏߭-B˜ø% ŅMęÛ(Ė[]ņ09•ŌĩSVĪH×Ũΐëk;[ŲCļR({ĄjŨ’ŗ °á¸zaXbĖ9i›+ĒeŸÆ´–ˆ…w–JĮđēi1cļ#Š÷D-ĸÅĘ9ʖy•–âĩÔo)ŦÅĘ-›CÆX“uYđAŪ ^Ę(ž<]Ôi2N†‘ ú0€9Õmęį‰žm qßK%`:q\iiĮ†fŠ§æŠ›zĒĻū‘ũČb¤Ÿw!/ä^ (.­yŧ SŨũâ’Ŧ*[6›kFŽËo›˙:‰Ęõ Ί›*¯z“ ˜{÷š‰°_fņÕČņũõU§ĻíĢ’đÖŠeúEYõÂߎ^ Ž<uaAɋ#g…Ē9࿈b1r$Š!´\Ķč"TŨuÂRĨEaÛ\*[hl‚E âŪ‰“å…Ö?uīļŠ01Sޞ;{V~\ksĀÎŋž–>zuë׹g×~–Ū™HūkZ]CåÎ}ĩ–?Šzõ㇙-O†˜7këųŊo•ė˛âÃ+“oĩžĀ Ч‰hĒč@¤, ŖÜ.#ē”{hŨN¨œjz)(×ĘːÚ\à §[ē0<ĢRJŧ„ŒÛJÆ—;nÆį ”PĮyėŅĮ ‰öd €¤:h5ķlô-1øÃ,! ëŒÆ ՛ŠÉĮėŖīJ‡ÚK¨507ے+„ -ÁJ‹´‹( MN9ŨäqČū|3¨˛üÖChĨToŊɨ$¯  õ ĘjÎÄĢ ĢņĘĮjŧ*Į 1ÍTĶM9í4Ŗ{ĖČ$;?ÅęO7žd|ūĸ ­hĄ¨>ŧ ŅŲn‹¯+VUņĒÁ*uŧYŸēÔĸŅŪlNãtĶÁ:ˇ#ɤSŖ-—dÕI]ŗØ`—J5ŦaÃԝhuˇbWŪŖ‘NZiL§%H@`T—ŸQ'܈ *(†tZhë­nėCŦa o'˜dēMí sSõÄ‹ėŠČÜr›ÛjT-LūŽãŒ­ķ@eãœŗYf}LM@ã+SĻ.9K”!3Ũ÷=)ymY>sķ¤úÆ 9¯:Ŗ—]ôŅIwĢģ„ č€Qw mÚ^C‰ėŠO—7Ü] ŅØsŠ ÄībĢ šácęMvâJrv˛7ģī¯ŊÕęģ"éĄĩķ 1iĒ ëæ’xח—ģŦ¯UĮ3Ŋ<{Ũ\WÍMˇ}Ą#-ôŌé¯ßūûK:éۜXõš›ŒĮŧĸ¨/B ­Õ"Ŧ}ČCcƒQWlC”â$pCÁÛML^—+ "Œ=åcU į1Uäc…¤”í%΃Q^øˆ>ÆøŠ7å{€T#0ąo>ū#ūZü†öžĒEE4â“Ö4Ģ™-rByéf;§("šëÍ``CĨŲa€a‘ŲļÁ 'xĩƒ"m^å;\UzÔ3%d’ņ¨P{ P˜H%ÃXõŽj™SžÃ$*‡T”Ę`į<‡Hæā‰tä#1e8ā…Gsņų‰åf”.Žąm$ĒÕLFDÁƒ90yeŖP@´Ā.Šë'+åKƘC ž­ !< K’žÁŅ:&ąOS°ÂĘdEZƒ*īÆĄám&"(Ëžûđ˜îkßæ$ĨČųA’›ŨôĻé^Փģāé>;ےÆ.æ<ļ‡qĄ˜gŪŗ%ŽJAÔĶū|Sžå3rNjŅxÉ7ą4Žå\J5“"Ļ06¸Ûĸiy"ĸLĸČoōK‹… Öô(6Š™m~“¤%5éGäˆĸPq’…”˜žõŌļķ0ŋ˜ÎĒh-ŋl+J6û–yVō8*]š›JyIĐé Ôz—ŖÕ.$KŨ į’ēšUƒŲäNšú^TĨ¯ˆ õč¤FzRĩŽĩ›aĀ/‘˛Ōž‰W—ņS˜Ŗ˜­L3*ÛYWø”Ŋ:Ėa‰ÉĀ;ÁŠiqg8u =‡8[z3e÷ô×l`)œ—D%2_<ŪیĶŊÄ–ŦŦæh#™„Q*w‚1T"ūY!Ļ•­ĩĩ­Ā5Uų°y0ՙd÷”@N@6TPÉŗ1É5nˆK[Sxē—Ė5Nš6ĸíS:ĨĄNEDßI%'w(Ød˛ģ[û ­šJe$ŗĘ÷´kVų–Õ*×Ŋí}ņē„Õ2FBRšø9(ČÎēåd’o‚ŗQ(ĩs'aėË~\Æ~eéTĪÕĘDŸBTM‰}Sb¨ö¨ĄB†OüĨ‘dڙ*ō#š.Ŗ|ėfCIĸanr %14ŒĖ˙BGßôčëô)ã æm„OŽ¯lCxHeāԃ7ämrčäD%ĻĖ ~æí8P˙t°ÖPxÆ)‡Ž­§XmŽˆ…[ °)TOÜôŠg6‡IÖÉ ZĖ Xhš–KĖĨûîĮã| ļOų4KúŽ­˙ĸŦ˜^°64člŦj(#F„Ģ m¯įŽˆvpé"PČjū5F[~&Lˆåô ëĻ„ČĖ„ĀúūI5Pģ<¨…ĐŠąŌM1°‰RƒŽ¸¨Ø†‡ ą ”.āĸ°ÎbjHĸ΂ÖĪg)˛\ ßĐs°YņļN§˜ŠŪŅŊąO\-“ë ÍAMš qĐōŠēļeĀ‚Œ+"ą~´Đ¨æC nĀÆvL¤ŧ„mEäFl(‰ŒÆ†ۃŠL…ė oī3Zqy×Hí{*§ZRë[XmģdJēh/>Č$ŸĖ$¨hŋäėdä[V1‰FŦ_ĮÔÚ­*+ÕĖ„[č ņâŽā+üRņm0+ú‘-ō›@cô$=đé˛Â‘eŦP q#É*+Ä,Ū†Ņí,ĖĩúIXČízūŒĒ"Fß^JŖFfĀŸ:ƒ¨K0P…!Cä! §ėæ8b1 eCJ&/˛)ŊĪFЅ#5 *gĖ܈fް2*įm+å‹+Oâé§oîP)ŗ*ŗėé|˜°*Ér"ÃQ5@Мr.OęûĻŌ*í-ãPãŪōŦd+~ܤ@蛐Eį˜đ031s1ŗ1ķ1!S1™’.)ŗ~|/"ažôō ũr/éO"]rîĀ)"ģ)5-5ãČXķ4Uŗ5Qs5]S6ínŠ*ķ6kË.A337SŪž‘Æ<ŗūv“7G“t’Q-¯˛ŦēR9™s+›393:Ŋb2qŗ:“æ2û2ū0“8yĶ3šŗ3ŗŗ7‹3,'BĀ< Đķ<ĪS=Ųs=áĶ=ã>ۓ>íS>ß?ŅS?ß3?īķ?û@į3@ųS@ũ“@íĶ:t­t3û/{<}÷‚s8ooÔI¯4=ûŗ=­4IÕtJ÷sLÍsMדJŲ3MĨ4K JëôLĪ“HũôO-pūí¯Ŧ§6crĒ%ÕÖíŅ1Cō}:ņQÄŪqE5S5uA{đ{HŽ-9 Á.ÆdHŸØR!‡¨…Ün-›č*Íh‚:7ĩVmU˙žī\dp*īršGV‚lÎëš$`|t%ÁŪíč"3V?/hÁ6lu ;C6Eo#ˏÁÎFü”Š’î5`vˇföeh•(VŪNQcųō+Åöo—­ČÖ&DļØ<)†ÎčvŦ,ÉĖĘ.Žáh‰Ą7Š&GąFx+ĐFT305p=÷s¯ķĶ’äíDKšĖč× NķÔhčĻ6`%Ņk“°mvã.Ųf“Ö:tyˇw;ep)§ĐR0čF|‡k+W“ .ķÔķŠäx—§Ōf38´ū8w×wą7{{xŸC åļCd7éj•P÷nŽÕĢ™\Ĩڀ0vTĖąlåE´Æ´L{í÷~áxûČQ%w Í`°ƒWąFŽX1įän%Ą^uGŨ`ņ7‚%˜,@4@Ū [īˆU{Ë34 '9ƒ&ˆkT/낧Õ3χ0('4D•u‚]ø…%d‡Qí€ŖK|zRWøŨ €Ëm*~Ļ1A5Bķzaøˆ‘$dø 'ĪImĒÄd‚ŌŒęžāĩQĨ„Áø [kô;ĪŒ8‰ÅxŒQƒ+xjcXUKŒ7}^NƒEÛ¸FBÛ2BA ‚Éx}—lYūĸp+†Ŗ Ūføk6ęb9CåÆŦ]ŋįŊ¸zotĶøx’)9$d˜ôęBĖŖäŅkzåx'PQŠ&ŒĒĐ ͑#ŲŽŊ8Œ+š•ą—lŊĻŽ°Į™ņÚŽMŊNä‰ (yŧF•\ū–0ÎDéŧ¸˜SŲo]9™+ų’UŖęfú(kø‚ōjv×f•0 c)ķxf2\ ’ņø˜Åƒ••šœ˙VåŒ2‘yTđĘ&fę`G|ÁK”4GžØĐBgîD7ΜųYŒ/s0¤–ų"/ÜŒeŲų‰'‡%ZĢŋę8%°įé(­"ˆm4œéŒûyŖa˜™#l˜>ŠVx§|éÆDh(ūDēWDړ˜"ŗtR`´-˜,šX8úĻ%D ĩTCY¸ĒË!N‡Ēhu7y[îčžÕđė Ÿs÷öô§ĄúOũx Õ`ˆqTŌ'ˇ‚‰‘LL5ŠĒX(¨˜œų7ˆœŖ:­ku‰+č5\gQi÷e+šŗ[kÄuBšåŠÕú¯;T§-÷åčQŨęƒ[<ȨU 'cÂNXĻ(M~™ÚŦ!­û˛‡T†Ī2ž°’¨:Iöq ;…īčx‘ÅØą‰EÉ&ģF¯1;ļ)ķ’Ão›ŸÃuÆú: Š‘mCOÄôĘM䉹q~]ûke{š9öŸe§h)ūŽ›X^Ī`ĘČúÂ‚Í¨ĐøŠŗ­‚}\ ŲŽ‘û1,›šŅû6÷ëĻVÚ< ą9ĨŠ1%ũzš“ã7úލCyö.:šiīŧĶģĀrŊjĩjš k§¯Œ &áČč{ƒ€`Į™…ũuŧSšŧ%ŲĀA|­E׎RđüĸÉįUɓ&úrĸ—IIŠžŲ/ŽÚYø <Äuœ—Ō0 Ƃí”\ĐęÖY{g+¨§– 2Ār‘ŧŠ7Ŗ[ÛŧwŧĘũ”{+í Ē•ÂQרˆŽ'JIüžoƙÎüČ%FüŠšĀ9E/ Į­<ÎķN+úļŖd¯ÛŗūЛ÷~Š„e#Å9búTĐÃoü1`[Î=Ī*øŽ –ĩĖrĐLŌ ÕĒwĨPŠLđq‚[fŨp¯7÷8ā|ŅI›%ããĐØĢœL/4 ė˒3a“6ËÔ÷šÔq}ļÛ8ĢZNuŌ|5Ø9“Wõy¯?SGq0יũĀÍ}ĢÉ QŨØÅ–ĖP=Ûk:GœĘ›ũÛĮŅk›Đ„ƒžô?zĒäõØĩ]œŲ¯k ÜåŊiē{k}+dÕ<™F¤jb;ŸkŨÖšeÔįŊāŋ –˙¸¸{‚€Xä¤e#I" övCƒŨ]Āš=ā™ƒā ~㉙ANŅ.ĮˇCūęB‡mņÉÚÜâķšØĨœRãaŪ2ņ†Ø†Nw…ÚĮĐCĻ˙E×%æ…ūۜģ‰Ģ¨x:qĒr%ŗR ay:sÅ­†ūâ^Ŗ‡>ëõĖŖ•˘ž|ŋåŲ]5,o…8Ô8*XmãĪōåĩūíãE°›Čežxîã˓ĩēä—:ÕTVŽ‹¯~B5î ˙hĻú‡šĮ›5Ģ!Ļß%;UU8æĐŪX§|…?Ķí ?ķ5…­ĨK*C‹OĨŠđȚ\;gfø$m<åyô)_ķaŸSÛDö }ø]Ō[Q5˛ P_qQaZžŨ‰¸¯cŋø~36;Ôq§’ū$ ēė”ōÚi$Ę-?Ų[˙_ßøĩ{›§ļŊšÄ§§„ŋ ÉĪöŗ€?Û^Ž9ëš|>øáŨЎū%qhƒÉhąĸ ķVT"EÆe!‰åõxŪŽyeâDiä‘H9"Fû%dyéwGĖM“TYŌ“~´ŽR†d•Zš‘eĸōø#šÎĨ@’pÆ)įœūtÖYؒY2ôĨ•$r™Ĩw…Y~gūIUŽĮšŸ.æ…hĄmŽ)išbԀ˜fĒéϜÎ9âwíI‘¨zBęP xeĀ׊lRÚęHjR äŦ­’tæĒëŽŧöÚØ§ũq´¨Ú×w¤úĮ#ĄlĒ'k­´NéŗváęëĩØfĢíļ5áŠU"=™k~žJlT°AYŨ´ĻíģŌÆĘ.ForkīŊøæģé’ĸ›ÜĘõßIߑWîčlšŅRëđŧ•ZĢīÄWl1|ĀT¸XVПsjĸGÛ#Âņ.üWÃŗ,oTõ^,ķĖ4×ŧŋĖU6WDZ‰įÜū•hЍ,tęō7‘–ŋænŧ•6íō­6G-õÔT•ąÆdēF—xŅĄŒIûefŌJ3Ė´ËNËAĖUˇíöÛTķ›ZHf&čâŠkŊŅezĸš Ę-/øŲj¯Ė܈'ŽøÄ#˛úß ™UG&Ŧ&øPĸë"„×BcN6āe^øË$ąŊøé¨§ž/ē!ķ9WŠmå\1Û:礁zĨēžvĘIŦúđÄī!ž“Ą éįéjw'7ĢĄˇ›tī„gŸĻđÆwīũ÷Ãņk"Ŗ%AjëŅ"Ė÷”s×Ĩ°ā/c/ēö{qūũøį°{;é_ß; IĖĩ3Ĩ Ē|¤{ūßõā—@ߊĮtú‹ '¨ä!ė;Æ ÍČĸō8֌'y…ōāāægļ’p„öŖ  WČ™ë[c õœõ¤Qį53áwXŊߝp"lĄ‡8Čé,ƒŦ1ŲW¤Dš*YÆP JŽŦĮCRąôK!ˇČEī5Î S—ÉŽu9ęy,%ąáĶ™bS´îmōÃâ×Å:Úņ~rÚķ^g‘ÍH.vnUį4w‘4*ĐsU<äåø-Ūņ‘Œ›û*Â1Ô4į4ë˚Ž,iÅŅô‹­˜Hšō”pÓrâ–?‚eA_ÂdČW1đŧe.U‚Ę^úŌfydū‹h,MŪeLļRĪ ųI\†ō“>tä/§IÍ]åņ$ÛI‘,ų¨MÛ)„uĩÔĨ{HJPūCÕL§:ŗ•Į&M„Y‰ ņb;ōÄ`Œ4'")·q hđ¤%QUīcÆ2Ų į:€ņxã,g3mIGZôĸqâßIžt@„ÄTģ—XĩAQ$Ą}1ã>õ™O–F Ŗ0)‘4úĖuŦ†É;˜ķ2x2:ŠŖ¨z§K'úĖQ2Dš2MĒRã-!đ—́\§šFí Yû.ËB+%e3˙šÔ˛šõ7â;ĸĩj´BRvg<Õ&Ą„Oai˜+kKūÁŠÔŗúõ¯‚1âÆ:įÁUräk,rIäūˆL.acf?÷ ?tö˛˜M Î.ã/éheO3âŖj˜'9Ŋ…GsËiŠÂP‘I”ã„æĶPŌ×ĖÚöļ<šZexĪ03ĶQNgDĶ5āVg@%=î–öYE5”­(n§K]Ą´3w3„,÷Ûue&;Ųu+uzš<-3Ÿz•(mĢËŪöæv6ačeŠ‘´}܈_Y’{ÂåK&ĸœ\H€q•ĸy….yjëŪÛöš)9Ҋ.°™ ‰–vą ­Z$\ Ė,("gj-ƒd‹`Éū0$ v°Š˙jA -˃aĒ*ŽXūę Ā"‘ˆúBÕĸÉÂ6Áį\ۊ‡Ŧbŗ.ĸ$ gɸ<ķÅ.zI¯sĶKĄųĘ1mq„?øQĖ1īË95_Į|>š,ÄÎ3ãlįäyËpžŽ‘K°#‹XK<akŅü/ōēôĪRŽYãLčĨj™žË‹2ŖD•×EJPB3—[?ÉÁ+´ĻYķmˇžnø…Įy˙÷Ũ>ęĩD]{īŇW…õ]čjæÆĄyNĄ'WˆŲ=¤œP1‰ĨãNQ‡6ũ0ļ…ʧ]ŠŨe¨Ÿxũņ#pŌ8b%Nˆĸ}~—ßgLžø›Œ ęĮ•™Há‘XŽŪ’NWãB,ÖAC1ˇā|…ŅLmsĐ:ĀAc”bNY_•FŌ—Ļ’\ļé䗄Žg¨{eZ‰ĻŠŒîįĸO‚)en‡Â—?ë¤Ļ Ú`TĒĸ˜jŲâxūœBš^Ą Rʐ™WļĘ"››>ęáŦ’֊艗&é*CÁ‰žq mÆXŗÆ…ęېHŪwlŖŊ–'댴’Xiĸģ+ļ°ú:(°" û-ąŦŠģ&šMj{ŪžREģgCŠ”Rž“HƒõkF*\^AeT[ _†'IŠÕ™–C9û¯uūžV0`Ė/ŋė/]€…Dōŋc:ÛģëŨģ흟üyëŧįíôīqߎ7J0ĨäO3øŌĪüę.ˇîGcšā¤kŽúéÚ×MŧčÆ{\~ßÁg¯6p@i6×úŌՎ@ Ģ4˙ƒúÆd˙ŋõŋ˙üu qZ’–ä˝q{ŌK6ūqŠÅ"ũ“Ÿd&xŋ†ŅE~ŦËSūgŋ^Ђė_Ã6ˆŋ ęīƒôā-ōĩuŦc,?C  G2”ČO7÷yĪ|íķ‚x)Đ:6"CZĘ$#+ËwøÉP}:´Ą}¨D#J҉~¤(/t%DB6E"P&fÃuRŌ ŗ´ĸ(ĩhJWĒŌ–ŽÔi%å(#ŸR…å4ØāČWđÕO—ú”Ĩ@ũŠPƒJÔĄžsĐAƒéҜ=.0ņĀrtŌĄZĩ¨XŊĒVƒú¯ĸdĮ"ĩŲéGļJÖŦšĩŦeÅgķüeǞiPŸ˙DëYį*×ēĸ´ĄÜhGžQæđ¯u)Č4é'ØĀv°„-l]üôt(,yF;ō:ŋ–€‡M,b7[XÎföŗõŦh;ĢŲŌļf[ ÚԜŠU7õųū4 RRĐz6´Ļ-au{ÛųņÖ´¸ũėm;RhĤ˙˛ØÍ ˛0ŋú6¸˜í­ps›XčR×ļĶÍntĩ{]ër×°ŪŨŽoĶAŲ|’Š­uęė´5ÉæÕēˆ īuÅ;_ā>÷ģņŊīoÁĢßúōˇ>Ųá32W†ļ騎t÷›_üÚ×ÁØe°‚!ÜāÁū%Šj0ŦÃwö÷ÁūoˆéKaŌ–xˇū­pŠqģÃt#Üč4^Ü iØøÆŌ¨ąŽsĖãû¸Į@Öq7†\cŲÆË¨­ [ķ hpãÉŅ€F4Ļ|ã[9ČXž˛–ŗĖå-{šË9~q”ŸĖbÄÔĻũ(Pūzj˜ī`xÆđpō‘ŋLg0×ųÎvÎ3žuĖ m”TŨ ˜mÚā„m‡3Öŗĸ÷ŧčF3úŅŽŽ´ģ`hL6P†tښÕĢÖšÅÉF–´¨!MęQ›úĘFŽ`įį 's#“=ĩŦKMëY‹:Į“…s\’OļÖĀļu°‡-lGŖļŅƒ X00A Gx6´ŖMíj[ûÚØž6 Xāl&(! Ũf ĖiÄPŊÉ7Čp„Ė Fˆ÷†0ílÛûŪøÎˇž÷Íī#A F8A´™°Ã“!äŧ›žĶz@ĨC2Ŧ@4 Aŋ'NņŠ[üâG  d°2´xB[œSƒūūąĀ@uCOšĘWÎō–į›&¸ÁXđ•ų Ŋ _М8į¯l´cÎvšĐ‡Nô•ÛŌāMĘāîĖ čPēÔŖtkoœ ÆEMZā 2˜@׎úÔĮNv˛ƒaž,Ŧa rTãíäG5ÄA÷ēÛũîxĪģŪé!÷¸Ã}ä°F3АŽt,Žqrz ŽŅö¸‹#îÖĐģä'OųĘ[ūō˜Į{5Čqk!¯Ë9ÎĻĮũp × ‡ã3ĪúÖģūõ°|9ŽAƒRŽmiM9Ō D>öĀžđ‡O|ĘsŪGpXX4-zÄYdQŧ3~_üę[˙úąˇ†3hū~P봃Î`ŧÛąOūō›ōœ¯ũŅōŠ߯ūüđŋüņn H##Ú(Ũåņ ūËã˙ō° ģđ 8€x€h€ø Ȁ Ȁšā ō  ˇ@ßđ XÃ@吇7z"a‹Gķ&ķ ņ‸€.؂0¨€1Ȃ2Xƒ4xƒ ˜ƒ/hƒ(ŋĀôx3Ā ü2=ͧ ?#VŸÁ Gyũį 3¨ƒQ¸ƒ8H…RȃV˜…S¸… øß@ÖpÚ –t0aąs¯Ã{, \X…mx…nˆ…o¨…rX‡qx‡p˜‡T(g Jpƒ–PG¨pĖcí°xūß0‡Šh‡z¸ˆxH‡čˆ¸ ßp 'ĐxQé~ŋ×’‰“‰ŒФø‰‹Č‡Õp-æÄÖ@,ОXŠŖhŠĩx‹ĸ˜‹p(ö$Ú0âđ +ø PȀ8€ū€ũ§Œ˜Œ^،Ë€ģô0â0 6Œ|g 3āø0ģ×GĐ â0ŒčƒĪȌ꘎ėčŒîīō¸ŽņHđx…(ÖPڐ#ūRƒ˜'đĄ FP øƒøhķ؎ ‘YéY‘IŒß` F -ņ‘&ņ;Gđ ` I‘*‘+9‘,ų’.ū“) “3)“^øxÍ`€x{Õ3 rsĄâHŽ5Y”Ų’F‰”GI“Ki“Î(ƒ‡‰ áEĐ s×ŅȔJš•ZŲ•Né•IŲ•Õ`%õÄÁܐË–M–_ų–n—m9—ū'` A’–(ČčƒÅؗtų’ņ  ō@ ķ0¸pĀ`|'׀z™3rĸí`äX€š˜íȕp˜š•>ȀüGF0† â“ÎĮ“ˇ S ŋĐ ŸÉ–œ)—ŗŲ–¯)c v1V"r1™! G€’ô虴)›Č›Ęyœ(Æ “JuP[„šÍaHrō.@”ÅūY›Ü™œĖų)ÎPųĐ‘Áé0äč‰î؝Ëiœđéžāéß0–-6@ē )ŸņéũųžüY›äpĖābŌ0‘g‚@ü7*ø Ę ú *ĄJĄ€˙ A R0 Āđ äĐ '™’ų퐗𠙉Œ:Ą0úĸ2 Ą3jĄ4zŖ6šŖĒŖ1ŠŖ;JĄ( (HūČ1rÔŲ1Qz\§Õ€čŖ=ĘŖ5úŖSjĨUzĨZšĨ\zŖįHC j75cSŒô%Šå(Ĩ]JĨlúĻn§X §s*§[J§wĒŖņ ݙÖUIęúa0ūˇ’㸗uš¨yǍmʨxÚ¨‹Š5 •'Āør‘Ey¸ Žj§Ē:Ē Jǟ:§üWĩ%N ú÷ƒĻ*Šą*ĒĨZ̧*Ģļ:Ąâ úbĒ‚”(ÕHœ6ŠĄ*ĄĮjŦj€Â*Ā RĶ„ÁžöQęCp™ĮčŠÍˆŦā €ÅšŦÆŽĘ:ŽæzŖį*ŽëÚŽ zŒŗ`˜DJ„ARē*AEąq äĀ—hŽé °ėęŽKŽ;°[Ž+°í Ŧä bjTäEį%'A’ĻÄē° Ë°äĒŽ‹Ž˛;˛ ›° {˛#{° úūœ“q/“ŗs÷Ē$ŗûFā ÂX˛Ûŗ ëŗ)+˛ ´&+´[´˙GŠ×ņ5íP•(yŽŋ`´‹˛HK˛?kĩAëŗ*;´X ¤â Ēŗ”/Ļ[{´D{ļ]‹ļTĢļ+[ĩY›ŦģĘ ē F0 ō0 ŗđƒ)Œ*øƒ°ęˇ˙÷ˇč8¸€K¸č˜ ũ'õ Ōę ß0 ×đ‡Š¤ŅS` â`€ȡ†+¸č蹅+¸ k¸Ÿ¸Ļ;ē¨kēĨÛšĒûˇQkŠ›zBĻ3Ģ3ũ$'%Y$(€ĸÛē¤ē§ëģŠËēÄÛģÅŧĮģēŊ{Œķp SĀ đP¯Kę:J%'úūœNšŧĀĢŧČkŧŪÛŊāËŊâģŊäûģæ;ŧß;žæģ ŗ }ËwWģ'q!<ĸ˛­lxžÂÛŋÚËŋ˙‹žá[žŦžēPy†4•I”ĖjĀū›žÁ ĀlÁ|Āŧ _knKœ¯ ÁLÁ"|Á|Â$<Á#ŧÂ|ČĢųißĀžy Ąđ(žÍxÃËûšPH8 Õ`ũGÕ` Eˆeđ0˜š?¸€ûÄÜ ÅĨ›ÃĀ+ŰJēSœÅUœÅ\ė ô†S j›1ßHŋ[”$ŖŌ ¯Č—ZÅ\ ÅVüÆoŧÅs,ĮŦ{Įt ŦCęæļ|ūųz3Ķ c! jJĮxlĮ6|Ō\Įp|ÅÍØČƒ;ɒLÉXɘ|ÉĄĮŽüÆŗđ ī{^Ũ7ŋfė8BŸ‘UšŒ‰ĖÉx<ɑŧ Ë7L˚\ËTŧēą\˚<ē˛ÜÉ~ •CUJ°ÄĸŠČĘüČĖŦĮsŦē–ŒČŒČÎėĘZ< wiO…|‰˜ĮÍüÍšŧĖáėÍŅlÉ­<ÍįœÎčˇŧ‰xŽ5ü Ū‹Ū€Žēđ…õ\Ī„)휌ŋ@˜ €ûü Á(1pũœ˛1CsâNËÄIËËz >¸Ī>ˆ•ē‹ô@˜ô° ųH˙§ mŅ^ÜŅ ūĐ =xÅ1,˙×Ō#=Ō?¨ É\ËË8 Ōā0e\Ę%3Á OĒĄ-Ņ?č Ūę %ŨŒēāÅŋā Ä8Ķ!í ”Č?HŅĶ5팝ˆ M˜˜ÕYM0=MŌölËšŠŒsDQŋ B]Ô8œÖb-ÕgŅüˌõÜz}ÃúüŽŌß ×]=ĶkI‰-eí ‹ ֈũ ũWĪ^hŌ” Ö=Đzmŧt-|jŋ3=íĶ$ņė ĘÚŲ؁ аĒŌ˙냁mÖ_ŊŅRMÛÂ*ƒmŖŪ0˜ËhŅ—Ũ ´ŊŲX¸ŊÔ¨Ņ-ÖũÚRŨÜEíԃˇ1ūŗĘĒË„)šh­ēŒÆ Ųw Í˙ᨴ ĢdŌmÛÉø Ģ€ŪÕûLŌļ­Ōš`Īšđƒļpˋ Ūŧü âp1å:&šŋú]Ũ€Ģ ķŨĒk °˜ŨšPŪwíÅøŪ.ÍØ„)ô° MŅÛ]Ø7lŅė ‹R á nŪÝŅ[­ÜŗlÔ|H A͆QZŪ ę…_}Üč õ@ķü…ô˙w ø ƒ ß8Œ50 5āÅĀ0žc(ŗ8“8MK”Æ¸ŽĐ˙ÜÚ ЅíÅ.ë­ā=Đŋ°Ō)íסíŨ÷äYũڝåûŧŅfnĶēü -Ũßm=V¤}ū˗/&Ö° ɂžāŅĖ-ÖžŌA,Ö_]Ō íå+Ķ­ŅŊíå¸-ŦÃ!ūÚī-įĨđÕĖ=ËŦŒįˇC'õ;S%y’žË=͚=܏۰HŅ”}č}āšŊŨ„9ߌMÛdũ×_xßēŽčcä Ä`=ĐžÕMÛ5LÖ ¸ +Nŧî XĪ‚ÎęI; EpĘūĸ\{~]´^SŽ’Ų~˛\æ=Ō_üŪÂZĪoŽÜYÍ Më­ ę _ėŠz}âÍčár~ °ĨhŊ %Ũƒyė÷ÎĪKÍå<€ÁîļÜÄÜž›"ŽÃ°ŒČēęčN˜_Ķ­=Ō×ũŨlŽū >ÖkΠXŨŒHŲ~Üō¸î3Ũá"ŽÖ+ŨÔ~ėY>á~îÚÎȤūĶÂ)āīķ†k ×=ØQ=1ÜŅe^ōŒ=Õ)=æÛ ķUīƒžŅH?į}ėYíîÍ úœØ8˜˙7įÅnĪ[}čFÅxŪÎÕ‎í *ĪŲMį˙WŪđ…„YŪ€¨Ŋâ;ˇō€ _ü ŧđ õ " ˆŒC’â´ÃØâˇ ĶO/ÖĨ… z=ĪM}öŠ` ~íØ{v` ¨īúŽ ˜ÕÂŌ}`xđæMė'_ŲMŅ'ŋŊ1€ũũßnî t/Ņ îœˆČJų‚¸ {ūĐxPŅGũÔžPĪ @Ĩ€ú#ŨM˜ĨЉ0›@ŠŌĒ@ ` đŽī˙÷xĐ‹ĐŒ†nĶx˙Úö?õ­Žüō0 ög'˙ ô7đ_AđūÁãvDœ<ˆō~E¤8Qĸ¯ˆģtŅ‹Hoĸ.yABĖąTžB{Jq™ËãDPˆtéúĩJâMš˜ä°ąŗi&Ŋ™wÉŗ%/ž<ŋ@–š’ŖˇImėā‘jŊoēŧ ŌkHR“v…ĘOIˆ ŊĨ•ˇjňáʕ÷mX~ū *ä÷¯¯A&\Ø0á‚}ōMW¤ŲCˆtoÂ]åņĮR”čŨŠg"GPū“äÂ(Iy%iĨ*Đ&9ą'ÁēëŒčayuÚ_Á'ŸHo’9vDwüŒ´ō/ !u•j„UžˇásĩGüÖėDģƒÛivÛčöŠGR¤w O#9–&3-yĘĢŌļÍ-ái“gÕmÖtÉ*"´äĸĮ›–˛d:JnY¯ŽëĒrCørEēĒĸ$ŽfōĒCÕŌ12yÄ9ĸ…žn’K2Ņcn¤UJÛãAˆVYë›K!PžR¸Bj“B(É;ÔĀŖ˛\ō0. čq)nķ(4yPYPēoX I•6čhCˇBōÅ)Lä+ŗĘĄŌĘĸõ`”ĖDiū’ q‚ęĄ_â9ĒKސ‚ŽĘ(āŗčŠg€ ŋɛ(× gzĻšÅ—.§FŒvö9ėSÁÛ§Įø "ķbül¤M -”Džņ¤WaÄz襤P˛”Į“[1)„ozĸį‘BŧYe’<0Ą§‘EVZ$‘åÁ„T*S%Ur]ÅU6iĒÖŲ¨‘˛ËHŒ~Ą3Eŋūu^zë5Ąxíãļ_֊kD)%ŠëJDPqĨ”h7ZĘ6Y$KzPYä\WV)äoŦÉPŒûCĢũJ‘IPŅÅ֍.ô¤ULōÆŽ\šPVPĖK.ū'z÷đ’× xđ]Q‡d”ė#¤Ŧ-Ä'KšEž]ÆŖTYVy,aDęU@Â$P€ dM›ÖJĐ–ČÅ“] ­‘ē>—žU6Q™a7Ņä4zš8¯éqåÜoJ!$d„ Ąä’<@ĨHaĢ*$Å_Öå"ŖVutÅš+¯„ōÔ^Ö[õč÷iėąÉūM¯Mãa*sĩ܄aų,Šüōo,)rFVšpŨWär§žåj&†/Ą¤M~å)UP9×&›†%ü@Áã#Mt‘øe]AdCz6¤HQAÅŽAi${ļŽąģ"m1¤*D|S;Ōũâ6ū]ÅHž‘ą”ŅŖ'mE)”—Ą˛I>ē°Û&đā Ž pۈ*ˇ™bX) öV sMĸœKEÅ6GŦUx H#–<1‰P@ V–¸Ū&žą A”MqĨĀUŽ<‘§mįÕ8‚4āĩ4MNZŒ˙ÖĸždiĸH/3™˛ ąq­Y¨X !š u š)Uŧĩ0ˆåĒ–Ā[ãąBk1cDš„%ūpŽ•x!ķu0a-jĒģ *ūčAgabJ]&rŅŲnDtZH7ĀP =…ä}BՇR㋇ŌEč1Š\õ0$5ŖG`âēȄ>éā ObĨp&č Ođaô|Y=âŅ ;ÄâĄtđF>3Q1KĐ!Ÿø&ũæ‰ ;´ÂЍG"> 7DÂyā p Š<ˆ0Czš8X`Å|…JEáAūZC “ŌŅuĨb}ÅVņPĐĄ ƒ'îЉOÔĄwø„ÅjЉNüŦŦ *ø€ŠN$ĸâ€ÔZAW Ķ•¨‡0ë‘ŲOĐáĸˆÃ'ˉãA5 ¨ČCqŨā VЁwÅ'ø C`âēŖPD80A ‚ÎjœúŦÃtÁEĄĒxŲĮ^<ę—Æˇu‰á+cJå?ÉcæJ“ECą"Ö áč„>;ĄzTbŸD>]QXŨōŸpƒ" Q ~â ķ`…pŗ›‡NŒ“Å…+qKÔ#ø ąqŋ\)ÔâPÔūk…{‡WŒâ ´EÅ(ôÖPÕ8‰įŒ‰_¸°J#ÚĒ1 Ļ7ĨkÉãZúŦ ĸžp%P‘]IÄ"Ž`.*î V7<–čRH2qH:´n0ŗ'Zá†Č~"Šĸ°ƒ+zĘ CP‚žCĨįė—ÜÆr9ÃZŦ'äP1Ū]Ŧ¨8ÉRåÜeâŌã6qEæŽÁ+E&Í’“L‘Û$Be!ņ†ÄäaĶRÚ<íC&ú C„~Âõ0č›+ņ‰EŧųyøD"Čå nĸYvøÖō‰Šr˛ĸ•åƒcYŅNV,ĸÕD#BqU(Ömđ„4‘Š80BŪ…'ūRązxBŸ'<¤(ū ‰Ÿ‚ĸ ˜ø!=,J)[„”đ¸Sž~1ŦôéOŗŦĒ ā6{c# xE8 oĖÃPŠE`Ko @,°r!ŦŦ7Ģ“īŊ˛~ܡšŨŽŽ+Ajȕ@E‘E ¨p8P‘QÜĻG+î@ĝĄ ÎUqÅÅĸX$p•‰FdB´‰pE%áâĢhpœõŗÉ°˛]&BŅ@øņŅ–į}0øēģžVĄ- R§ņK=ą@đAĄĀg#Ū ¸HXžb%Šz(âĸXÄKĩĖŌ ‡ėŽđFÔįūÁĪHü Æ'%°+ĄZö¯ĮĐđ4ČGâút5h€×ĸŊ7T‹IHÁSēE‹Pų\'CE8,‘ OŊÄk1 7âÔhã+!‰°‹ãģžXLsŌ´‹`E8‘†:" nHïQ@k u@Ãæ!zÃų„z¨>˜ 7€'qģzXƒpH„5xƒú3V@MĒNˆƒ?ȃpX\áˇCĀ|2—D¨ ¸ˆ0ŧ ž`9Ŋ{AЗؑĻãÛB@ĒFĀKú†ųAĀ\q(§?āz8„L>2ĢŠŖ„J€ëbT¨@ CjXū¨üž˛ĒrĀH…E †z \€b"ˆSqđ@q„Ûƒ„4ˆƒ4 „Q-LCX7pļL8„xƒBđ„59A˙™ %Sx ķ8 Oƒ ëX  x"–VĀxĒō ‡;‡M|ŋļĢO¨@!bų†ķM xB(ö„pø„J?ūƒ„˕P$ŗŖķ„yČD0×˧P€1>X„3ˆ‡D[¤oQŠHXÅX *¸)QRŠŽBĻ)ĩB„‘T‘‡Ë¸ķ„7„<¨‡>xo¨JE~*.WŧEēO¸°bûEX4ˆ4ģ}Ę%C!~ūŦJXQ¸ŋ™â:úƒˇĒ8‹ÁÄDøƒP¨‡M„Kä#M¸.\ <:WP\iG…Ę|ĸČĢ@9¨ÄjŠFŌ)‘**ĨSJ%Žđßø†ģ¤ [Ē\€)H{¨Āȕ‡z€zx¤ šz˜J ‰Y¨”f(ƒkĀ;ųr¯h:ڙ9í¸ H”Č%Ãģ0T„NC¸%kƒáŌļ\)6bšĮF¨„y¨ŽV¨žė*ĢĻT\Hƒėō†Lđ2C˜‡Cđ„PœÖ{@¤Iš‹;ŦˆšĢ"xąJ„Á‘ZĄTĒA€q —¸ÉÚĨæÁ„HĀÂJEChū‚üĮ/k°pđČ:Ŧ‡X€û´¤^ŦCĀA@o -4xFo¨šZŅ…w"?zH„LЊ°&ķĢ‹8™ PÃĢž#ˆĀP&[ˆhh•Ė/é(ō†ÂԕâēŠnƒĄ_IM`:ō]Ā„I˜ŸáTE@Č9Ū‹](7HĄ°w&z@ˆ7@PKȸĒJÜ„D¨q˜Ezz°.Oˆ„W@Hx7(+L09zP„Iˆ~Z„üdē#ŧ*IФO(KhBč•ĒĖ Ŧ„¯ĘŦQ—SŒÔá‡ŲųĢĀëˆbÂÉJ„ ŗû8đ#]PŽč’íąãQFL@*ŨūMN÷DĐB¸*oP…}ĄŅąz/K€„xĶ,ۄ?XgɕšĄb›‡u2„ÍH@…îʄQŦžcjIx–õŖ„a:TņD…ēÄL +ŧ ŠZÉĄ;QKˆŅFÎü—nlŗ\-oąpˆ‡p¸SŌ$ÕlĖæD°Ü$Íą2‘Lʞ’M˜ŽppBO0üķĀD‡L„H‡đĐI­OV„šūôI Vh„c'Ņĸ‡sē*! ļ]„yđĀuíMĘ@ĀȑŽFT•+¸Tâ?Ŗü†ãŌ z€¤ĻÂ+€q‡°‡Wđ8Ģ{Ęz(q™Ĩ…څ¨ŧ†"HÕ;QĄÁ™3ÁĻox\ɕ EƒĖŽqL]á@0Xe…7X„5đ„ÛĢŅĒ„:āŸ“ļtƒ?đšHxC¨ƒJx…7P„7ˆ…žä:N¨SÔBÛ7:øZáĸá8ŠČÄ+ĸLŊJģ#Š;ųŒ8Š% X“é’Ž‰Wbq…oĘPW¨ƒ?ø'`Ģ„cD°/Ķ´:HƒOøĻĩƒūD °5?Ô"[LH]ŸĢ„7H:¨ĢU7øĪ4x?OA –5X7ˆ‡qÄVĀSŪ;>ß>ƒø(|aARCAõoXƒC Ã5H„7¨‡O`´@ė<rb 2ŦUœßmz•%7ČŽ E¸ƒD¸ƒ%[C“2ëŨ5;P…ąŌXE:H„3ŠŨ°O8ƒHpĀ1”ŪŧĩOp;7X8Đ,FÍWˆC C ÅZ‡lŽ‹­eAÜ…ÕŲŅgU•šĘ@@T7„:ŒˇFā„Ģ@?Ŗ*Ûp¸…qŒ -ē덃Wü?dC°<ŪÉŧÎl aĀ2Ž@ZŌĘT8„ÖĸVPâz…ß…ƒW$Đ^ƒ =ƒFpƒ =Ũŧ3´D<<›7Ø`q-6M…Ep…΄[ @QGÅĢūĨƒpĐŅ ÅCÔL@<4¨‡čú؊áVˆŨģØr…*î]đ…@Y\‰8SBĨƒĢ‹Ē ôO@ ’m-’éq°‡r8éÖJؕ逗29Ŗđqh#hÁ)Ŋā iĸĻSŲcÆ YÂJšĨyhĐÖjJķ+ęŖJiĐ;꧞j§Ļąqȕ­jĒž%­Ž)§žVé͕ˀ;uŲ(eĩ;>a´.)Sú;‘čü 1ē­z zĀkr°ëĨ1JięŦÎjajŋ<¨@aĸ‡Ģž‡fnæŖîęĀæęĢ&‡yėzģVlģF-Ŧ€P€Ģ‰ø†`ŽÎūėT‘‚@ÄhĀ“U‰°ŦnmĶkģ†mŲÎkÚŪkØ6Ę۞lÅŪkËæmģžęĘÎë´lE‰ėĻ”ė˜úk§ĻĻNƒānגléžëŖ-ÚĻ1jå% aģXÁÍé´Öiø">Ŋ¯î4’ æÖIžœVÜŽ1qØëÔ­p ar­ËNjÄžkzCŖŒla‡ún­;ė6?ėžīúV×ĻŊ6Jj¸oúvđ˜zYú†6ÔēX/ˆ>…˛ķH/ē ëÖöę\ÂîÉžėt-āžjAum7Ę—îâ>n˜ējŽVnŽîqGņTGnäö.OŊŽčāđŠūĩaÖ,JmU‰’2ōjŋ~ė[ēkËŪo.¯l-7ŋėĸîëi}đ¤NęōGņĻ~ķsŖ´nÅVlŠēB/–Ŧ‚Ã=áŊɕūJŖ´¸ʝ\ŲWđɔũ8Ÿėh{€iŖô¸R¸šžéŊĘģ‚đxˆ&™ûén¤‹c€`C€BIõ(GOõV_uGwŲXGuYwuYŋuT_u]'9Y˙¸(CáBT—Ą@ŠkŦÎđÖôÂõģUbD#‹R€S×u]—v;tSu^×vX˙u_˙ö]Ÿumou\ĮuVĪvl7õãƊ‰æ"ģR^´ĨqŪfū%q Ao?u—=tjgõ¨v`wôi/”j˙wUĪuG—v^wl†ˇu†/w‡÷¸YG÷sxCųu[ō č-‘Ķ!ádWë&oAĄĩ÷rY`W€û÷_Įv~_yS`oyŠŋöđvWø u~xS•ŸųŒgykvSöž—ö~€¸ö˜7}Īøã…ō DÄã×cyĐuYx¯_ønWøY×÷•u€Īu’;û„špˇøSu›7xŽ×ųƒ/”_/ÅŦĀmĀÅÆ'7ĩ8nyģøšuˆˇøCOx~O{Æo{´‡uĩ/üZ—{‚ŋøŠGûˇû}Gų™gūĀs( 8‹~ɃkŗŪ¨ žT”[pÎŊžëŦ8{øÉŪūÉpxr§VŖäˆUę“Kžt¯QųôFėF+Ķâ]ĘĨ\)ę2ÉĨäoßåw~åŸū\*jęūë)Îč’6Q—ˆ0ë`žošËdë'÷´7‘¸Îž÷öMūįßĨ§Œ1įĖŊ~§~åß%y°×öoūyôēĸgP=]ō.üÅPŪ/qG¤ÁûĮßŋū2rĖXqãFŽđĸ×đ!D”åéŌõ-ŪBƒeDiķáL:s洙sŪC˜(…úŒGķ(=ŖŪč-ŊɐčL¤LéŨō†đ[J•6ŠV„Ÿūŋ1bėhö,Ú´jײUģcČąéŠ43yR+ÃU å}Ŗ×ŠŪ+zâęy 75Ļ7Ū–&Ŧw5^ßÅōęDČōbËô ėË4ōԄ~KŧtiiŠT –iØ Éġޤ÷[ŗ"íBrlw¤Ú´…Dm?ŦŊS`ԙâ Ęķ8MĪĖi:îųt™Ø§/O>°ûŅy2 ˃™jxVâ'ĢéVŅŖĮnGÄ7žž!V„ûîT­ZütĐ H€˙UgCÜeˇ RÛe÷Ú7áČĶB ą„—zNô<Ō”ôË/ģČã/åđĀP €Š*˛@0 @ūŖŒ:ęc|ķÍ/%î"Nní´ĩdZū`?íœPD .„Õ] U(B#–įå<߄ Sbd~ LfĻų’—ežÄĻiåŊiĻ›h2%j‰čŸÖ•Q{īYT“…zhGŧ]ÄĄ‡ß”“} ŲRSCŪđųKb %ö Vh~YϜiŽhĐbņœ*œŸžÉϚĄ–‡éĒņübBLm…_Câ°@Ņ?JrD¨F‰ÂĮĄ|vexߤWÚĘW˜W„åŗÖA‹§9["_˛ĘŗËŦ߈ØĒ§ā˛ęĨšs´˜AmKŽĢ­b…=Š5Ĩ…ĮڇÛWû Ģ/ĸũúË$°īí3•öūlĶiõD¨K=Ą}Cīˆ%’ĶAFÉ‹uIu9‰‡‘Ųfĩę’iK;eǘBĻŠģ1cœ‘ĒŨM?„¯’ŧÁĶ]ĐÚĢ–‰õĖ×@ֆ;âŦíz9-_r&=4¨LĮĒęšŅZ›-–G›)a˜ą0S–]g(¯fu8_¤eßDi§XĨíiœhĻ翎ė˛Mîœm>-îšÎ&ÍĻÚQCŨ.ulÆdaŊÅŨ*‘4ĂQ ˆģ0§=“‚–Đ*KÕķ aõ܂ĐrKŊæ aŪtg’A¸h\eųÁķTSôŌ“KVUkûÍDc•Å[G+IvÉLÄę÷ū?ų¸fžã ä|  {÷’ƒÄ &ŧC vÔÅ%ÃQĐ6]ųĘëŪC–įqĐ_ošŸ\dWA¯­â{ņ%–ÂϜÆ3–ã č@W?xĸ•pū@O$0 ûƒxēV4Ŧ(4" ūđĶ5L&x2ˆ' 7ŧá )lMÃ烊F4Q0Ļú cŦ˛ í84Ŗ_¯~œ/aČkgKđžÁ9ŌąŽ2Aˆ^BÆ[N"îI|Čļ3”äŽ%…+` ˆČę °'uū|䁸?…”H!Š0›JĮ¨…čY….„_lŦ 𪉙jĩOÚ*1›‘Į<2Eģ#% á>pV0+ņQKĒÍJös+äķ.‘˛ŽÂw“ĒĨėˇčōبŧøũĒyˇŧ&[Õ!0î>é9—,d;,uĻwÅüš1 'öķ$į|'~(E:eńZɞװ‘]UJM‡i,¯“}Ã'2gĻĐd.ÄXņâVHN 1d ã\(F˛š ]”Ą]ŸĨžéML^)7üā—°ŠR€ōšaSÂ-– ¤„ ‡Pá \xb¨ø* Ō oÕĄū&ÁT|Bô¨‡!‘‰D4õ@+˜â‰Cč´™D',ņ‡NlÕ™hÄ+4ĄOĻđÄ7zÅÖŖ>%"*á IŒÕ­DPåĄŠUX‚9ŗĄTábJŗûqH—:#(^ΙQū4T„į}:z%…b6%íü,qĸŠ%ĒT=ŋ`OØę' Aްkž@øš4jvļ(IhmkMbēĶ6íôĨBŧ…WÄ!‡,Ŗ&§ˇ¸ÆÅ [ĸaˆBNĄģ>ôBā”Įl Ģģ…8.Ū•‡/fŠ:°Ŧ4Xc‘Ō.W’Đh´HV /x!B$"Ņ.ŧœĸ}íKßũ:¤DŠīūŸŦāûÆ×„–ŌÉņ$ “?ų‘yå}pGøe)×Q_ŠT…ļÛL+SÁ<|Ũ ^Ņ÷R#N°{ë‹_ũ)ÄæKåcđę‘!ėtŠ/ÄA^]DP˙Œ ‡ōY fOwz‘éŸBôß]XoVKn2dVÂd>ÅÞ+NZ‘RbsYĀũq–uá‹õŨ“Ë–ņˆše%&_Ȅ¤Ŋąddƒ†0oâr‚‹¤QKtą‰FôE&×CŗëöŖļ4ņ”Ô Å!ÄēOzĀÂxŗqˆÆûē•–åĨé% 4!B/`Ō.ęĐ´ŌĨ˛y[Ũŗ^ī:Øuž ­geO/‘H4ž4á;—÷=$– ÁūîŲŊTŊîZ§8ŪąŽwÚŨ¸qv÷ėŪĢdâēĢ[īžUHßŗÄpcá{–ąÍîë–Įįoīn÷Íį=ëƒįüŪínoĐ_=+F¯îHOzžˇ9ņr¯œ÷AgX“í×ô§Y&ÂcĨč1ÅԀ WxŖhpC&!9čÂō(„Ô°F,ôÄ* ĘÁАĮ&7Či,ÁL,e7Ũ„‘]⨛` J!õkb–hv),Æ$čBõA($‚<$B(Đ&0*üÁBŦ<8Đė‘Â•Ô øJõJÎøÖå}]āaā ^áū^į™āÕųŨęĨ  ’ Ū áõ‰…°Īž„ 4A5u ŖÄ––ôÖ ū ęm^ æ įá ž.aŪmWöĐāJ¸Ū"Ž?ŒÄCy \ˆÄÃ.ˇ¨Yū܆ˆBĖTˆØ[Ę}ĄļTŨ.]WˆA>胓`“ãq;ėÃ5ˆÁ0ˆĩ|aCˆČL•!!˛āĪbŠĨ!ÅÉ,ėÂ,‰Β$ĸŊU"íČÛ bz—,8Ž7ChÃI”äŲՌy97Ė€ÎŌļ4Î+Î ,F"-ú%Rĸ$Ž^xí/˛.ūâ!ã-"&ú]1‚H.† 4žũ˜?4ãū°°C¯P^ēŠ™ŦėI!ū&Æb!Ö"Ú"8~ŖV/ĖB<ĀÂĨđĸč­Ų$ļã0Ūb7‚Č5ÎâŸĨ›6Ž„ęäƒėQ˜? ”)ĒÔF ĸGD LyëÍ&|Ÿā‚7,B'†„ü $P‚L‚(ĐC"x&B=„ƒ'ü9 $ā=(ÂöD#dBxB#´‚+‚ÖxƒTÉ%P#T‚7X‚%l‚ ”‚ L…ö̓GjŸ8ĖÃ'4B8‚'„ÃMæÕSũA„îЃ ÍÜm$Éü¸T>ˆ0`, =Ę"6jĸYz#0Fĸ8f#Ÿ„å,Œ}ŠŖ;ÎåY†c Ŗ Fūâ+Ę_Îĸ8ElƒK)É;tƒ48¨Ų jžßqc]ÖcZŌe0ǘ֗<˜ãŽcŨyctĨ0T_¤-°™5ÚŖ n,^ã^’å+‚ןėI‰¤Âe .ŧflŪã<ĘJy’%vŽáēL§ ‚wyR5„â>#äũ#ŨáŌU„6Ŧ"9W\V§:^X8‰Ųį}žÅIņīŲ‡K,„+Ŧ ¸B=¤Á!Ø+„ƒ+ A8„ƒ7ĀÁ!¸A+„˜ß'@•„Ã' "Ä8ˆÃÄB=ŧ!ØA+L$¤Á+ŧ `$,G=´Â@‚Ė.¸A#ŦA, $LUaÔÃ'Ŧ!¤+ŧBj+¸Áŧ‚(؃ĨŌŠ7 épÆČԇˇŠN;J?Ļà ÃņI„Ūčūuhŗ&č…F+…é+î‰BÄ\/jgu>Š‹^'V뀎g’i=žÜļ/:ÎDC7ü;œ”4vC4(=đbBb‹ÁĻõ<Šŗžf‘"¨š&é+Š=îâ,]|Ą\îb~ čzΨ-v+€–ëyJ+ÅƊŠĒĢ8œĀ2ôíҐwYN9„â(r —>ĪfÄ:^;p F|õDÔB­ŲBԄR=E”Ų–­ÛęʉC‡2#)zūD?Ņäà \ƒ8ĖFĻ<ŽünN(­hđ‚ËŌ¯ūί#QJęÁ28Ū9ė?œƒã-à „í/ķīq¨MR¸ÂĀQW°ķ„8”ÁģÂ4Œ@9ūTęVƒC5ˆÃW ûa ‹Ã4­ —09Ã-L9°°Đ–°Û° ãp FW@ Ģ-ŨgEČ^:€€3Xƒ¯pãđ7Øp “p Kq—p Ûđp˜° ‹˛  “ q_q Ŗ° Oą í?1Cņˇą‹p-hƒÕîC?qnin@q° |00Üpŗq§qō̰Ģą §p‹đ4hq “/´p=Dō cņ 3r §0“ą#ō';2=C5”ƒ @ÃÖjD~ĻoGŦÃåúą52gr ›1{˛§0˛-#r.¯ąī˛ _qĮūSMC WņŖq"Sq&ƒ˛0KŗË152ķ2 ÃÍęFF°–†ÅÎ깥\Ąį¤.U^k=Ä*x†‹ĀˆČȎ ĀŽŦˆŽ(ĀäˆŠ@ŽŠøs‹äˆ=¯Č<Īŗ‹4,t‹ôCû3܈ޏD¯HC÷Č0ĐlԋbYÃų–Åy‰€3l1=81g1#;3-s˛(īō!ã˛Jr5ƒ`´°G˛÷ō3S3.csu(CqPķ C1/”5ųÃ9ÜÃFĻ”/íōWsQ÷˛Oŋ´!Ã4Wŋq$c2QOÃ4€Ž _q!˛ļt¯´Wĩ5ģūtW§tVĮĩ5˜Ā2pŊ&6\C9 C34ÃÍZC` v`va#ļb7ƒ1C3\Ã58ö5XeöäVļ`ļ5 C5\ƒ3ÜfyÕ ,ˇÃ(Caļ3Ãa'ļkvkĮ6l/ļfS6bOö0 Ã5 ƒc§ölŋ6l˙ļl#ļpw3 ƒ1ƒ3@ƒ1LA4 ëˆ19ŗEXôC?¨ƒuëKãÕk_Gvp7x7p/ļxĮļföyķļ`īöwŋvx—÷{ˇˇ|[ƒ0@ļ37<ˇKųÃu[ˇtgnX4^73Č÷|ˇ{#¸y+¸pĶvk/ļcoö0Lî„Ûöyw|“ˇūkx†—w{[C9Xƒ1€A;€3?ōņtˇNĀd„îQ‰ŨËBxCĖŅC.E< 1EŽkMĀ å¸@|ŽAQRÅRWMt‰7˜ Ŧ GÉÄR°†­ĀėiđΖ$>‚ô(bîiN1xc{ø{wø‚“9šŸ9nëļzŖ7f›9†+8œsx‚›w0@4đ>čÃ>āq4Hy_8ĄË9ƒĶ9|wmcöz“Ã0ƒk;8z'zšĪyšĮyk;¸G7@ƒ°€ Ė€ AÁ Á Н:̎:ŠÁŒAœ:ĒĪŽ“:ޟ ĒķzÜĀ @ūŒA¨r)Ū'yųƒ6€øēŠ+Á¨ēĢ_;ļgûŠo{Ž‹Ē×ú ŒAd;š—ģšģēĀē(Á8~ãgŠ÷ [7bDãA Ѐ ˆA œģŋ˙ģĢįúļ“ēˆÁŦĶĀĀŧÂ˙û Á č3‚…ėéƒģ;ˆžŗĀÂo<Įŧ­¯zŒA ˁ˝Ÿ:°w<Ësü @” @qâ§8Įģŧ$cA ˜ÆÔJdŠÄÚ-<8ÃŒAˆ@Áˇ<Ū+üɓ<ʧûĒīúĮįŊā—ģģŋë:āƒ>čÃ?ĐĢTûßŗzā~Ūs{ʋAŒ< ”ĀTûäS>čü Dƒ?°C;œ~>¤C”œū駃ë§C;¨>ėįCėĮ>ėß>8ƒ(^CëŸūęû>ëû~:äC9¤~;Dƒ*ƒ,Ķ}Ä:ü4pÃđ??āÃīĶžėˇƒõƒnėköĪ~í[?ö×ūõģ~;\íW€6hų¯ø_÷ˇûs˙ö{?ũƒ.čĻ~:ˆâégŽ„ŠÎÄ? „w_B~íūqk¯ŋtíŌIl—ĸEŒ'rŧ˜ūqâF‹E†¤ø1]G•4œMŧĻĨƓ%cv”IdΒåÚ=lĮí_Ą˙Â+Hŋė˛Ás˜jƚ(§ŌÄyuäM­&ķņÃØ5_ÔtaĶiĢ@ņÚIŽYMļŨĒŽGŦnmļhDąũį0?ĨG 6|qâŖF˙KØŽH3qō(˙ĸ|YžeĖēčQū&ĪÕ*zēä}#]™ô/]š*ī’§ë—åΔIĶķõÚÕæĖē\ĮÎlŲō._–a[fųĩjßģ:ߒ×YiÎŌŊÉs>úų¯oņFWĮ~Y3xĖߚéĒTéēÚ¸y K~ΚTã_­—ĸˉ¸i“ú˙-ūĢ”o@šļRIŦ|ZŠŸ}đᇝņŠŠ,‰,ėjžų¤k*œ6’ĪŋvŽ‘Č0BâčĢ -´¯ž›îc1.ļōë'xüŲg=‡2Ę1Į„rLĄ ƒl‡"ú'x†ZȍâČ}:hĀģ’ †ōgˆÚg}úšH…Ę\2Č3ĄRÍ2{Rˆ2*ŗM6íLķN3…lP>ũaįŸ~ƈą<Ņ+‹bčGŖÚcGJ4õēŌI-•S #‚(‡úąRL× uÔKKj@ŗ!jĄ„”,Ɲ‚ŦÔ)%×ė‘Ô:sÍST]MÅW§Čj!b åõÔd}íūŲ:Mč§ūyĮŸwˆ"ŗąDĩŨö0(˙ŠUĸČ& ¯2ːģĖé 3ˇ8Ր‹´ãrųŗxTëLŗxĖ•į6y\nØäa 8ذ›Nŗ_Ēã÷šĶ^ˎw7ãėŪéĻÌÜsĮ+¯"ôSĮ1}Džņ×fMŪåĄŪ|ė#[]VŲ“KN™ÎQīŲ§JĨ‚DO0qŧu栙MyčIMˆ›nVæĻe.j ›üIį&ũbĖĮ˛Ũš(¤áVCÁČP7,[n ķV)„ŗ1Žĩ&Hî-‹VĸāŅĄŦįūÛnĀŋŧîoŊũmô ,[íÆą\Í/œrē-'ūün˛‰âÛ¨Îc­ķĐ=s!ķÖqƒH}õË[}pŌƒ§Ô;ÖÜ_ß=öŪY÷Ũõŋ\e,nwųDũQ˛ xöIG\ņĖÍØ3ŒËĨūŗË˛¯ūús{W{sˇ/í9Ę:ël˛ķËī>aīŨûéå÷Œcļclđßõ~˙šĮŪģošķīúG@ūĪ1hHšūRĩCx°ĢÛ¯FļÚ1N1Ôā‡:ĮˆmKVŌ]7÷5ÉQoĒk ņ’WüÎ(Z˛Ōä8h@ÉŠŽGĩ  kHBŪ.„ëQ ‰˜Á4hqƒÁ`Ú6ČCvŽ&ŧamČ;C­ég†ūQ`ÛCEząla4ˆ4l6vņ(^T㖒¨@6ŽXââcĸ—1;îËzā#ßxøhŊö}/<ãß=Ŗ>ĘLÆ|ãû#øŲ=ÃžŌ’˜ Ĩ*UGļąuC=đ¤î0ČJ[Žqm ôĮ ,)F˛EŅoKę˛u8ÂG!ÛPčË^ļ’˜šāAt EZB획˿q—ē1Žql ˜ČÔĀmžĶ™čÄ& ‰Âr1ņ\į<ĩÉŖÁ4¨œŊ b éųĖzöS˙\Pį<7PÚŠ`š­äâ?ęO‡”˜VJū܏N‹ļ­ĸ΃žd"ŲQHÂĪ‘Ü _šHÍ rŋ‰oVĒRFžĪ‘ßëčķxČō\D€8|¨< QuŠmoŌØ)@y:ԞΒG ) zĩ‚J“¨QíéBQךXwMMčQĨjT¯úmЈT- 'pLX͖ĄĐ38ļ 3yRԚ‡HÖ*Ęnôį?ēáNģ&毆Á ŦÜøM‹†ĶJ‚Ų‡ņ’Öģ>N[ĩôÛ_ā†wRy= •˛Ødē‘­tÕ'`#[Ú˛Võ”đ ãŲž ×Di–0°•Uâļč¤ÃŪv íH[¸8JSŪ¤%}ŠL‰ SárĨÉUnūr͐–ĢĻЏ8n:Üæt§}­iŗWxŧ oĸmœl›Į-OVԟ•$¯vEÃTļMĩL  zĩ ŲíŪˇ, kyŲ@Úūwy~U [Q%!ÄĀũņ”˜`ÂĻ­—wúWÂÖp†s*BâŽŲZ,cúáÁlÅ)ž¨a—÷„hĨŋ*–1ŠtĖ,vn íƒgÜc˙לâōúúa…ūÉIŽí’ę âÆ1ŅÄ ‰žt;ŋé-Ë-%diY™,™aĀųÆ÷nsŌ.ôĖUŽ.$ŋáŒ"\Dg Âņį”\į ޝB嚝ųĖáōB5ČCtŸū},ĢšEōr MhGĶ–ÄkŌ’ƒŌ@uÖJ—đ×v O'XĸAY“kãZJŽšl7Ę´ĨŋĩØÎ˛͝ Ą0jĨv\ØÕ7†õW ˜KķZÖØļŽ}=8{b÷Đëu˛)¨~ „×ģÎĩĻ=mi÷ZØs>1¯áᄯåÚĀŲÆvĩĮŨęrĮZ×2ÔqĒ×Jé ŪÃĻļšƒMîzĶ›ØâŽ7Ú\­j_ŲŒI&8OŒ-}įÛŪĮ÷ŧŅÍpy˙EĶ.´í˛á¸Ôōv\VĻ2$9ūe,gĪ2ãë—g<ŽÜ} ˛™ŲžvÆCŊ5w\~Ô}ŗu+Ũ}ĐųāˇvŧwūžķkËZ×'Ę „:đëüÜįyŌ{žđˆÛu¯˙–ēŋũ­tŸ/ũŪ 7÷ %pD3ÁŌüģÔ­îôŸ+\ëXGģaÜWŅģG‚’RĨT ŋx—ÉdžŋäÍcŅĸs'^‰ąØ˜c=‹y@K|°€ÆXŠ)ļ!LxņãŋĻʐō™–ŨâęĨN–âÉŖ XõxĖ#^ķŠO}čžXÁ´Ã /ölĨ-ŋúÚŖ÷ǧ“čēîåÍžúe|{ãųˇ7ŊÔÚŅ€CūņŽ?ũņ•Ÿüé[˙đē/ŨéIúm9xE$Į?J~‘’/{ŸI˙–SŠōę­ūÜ۞ûĪĪūū”oųšž-3ސš.ŽlÎđh¯îž…o…îАõđYŽ"^`/˛Čöޝú.Đ30û†¯ÂĒ­â,ą pųˆ7°/đZ/p¤ĸAžF5g°MP‘m—šdqF)ûĪGōlDâ,čV~my˜ œŠhÁKg Įžäôy¨pîoPLnmōhī° ‡Ī Áđ ßHč BvŧOmØJ˜”BîzđöÆPŐG GX0pÁpíŽĪ°ĐČū'v>l€âėQņúņ QI0(œOIȄų¤§ī 7Ņ;ūoyP‰æÔđÉrëo”¤ŽĀĒAžA^1aQe‘a‘cQw‘bąÅáŅv‘‹‘ƒ1­Á‘Ņ›ŅŸŅoŅg‘k‘́˙ޤŌBĻî į0ëp ÅņđĀq _€œGŋ‘Ã0ßqáŅâ¸n0ÚĒG‘Ũ‘åŅãŅ)Wļ0ŅčÎú qũąÛ12 ÍIŸ* › ŖzāÅE¯1 ˇđĪZHŧ"×&2M1sē$‹ˆ#OŌr¨Šoļ­ÉœŦĸLR%q ęšĪvNlārG&grŗŒ'ˇe˜”č'˜œĄŒŌ(ū˛”R)“)—Ō)Ąō(‘’*§Ō*Ÿ’)Ŗ2+)¯*ƒ+¯˛)Įō)ĩŌ,Ĩr,ŗR*ąr)ÛŌ-ŨŌ”áē(ūPōg´~Ō0N "z`$ũb'õ¯HMŲBĀüĢÍFęJ0ŗ.+sĶ1‹í¨0%33ŗģā!ú†÷44M‘v­°<(0C5 #(ĢĨP¸P€ Ž d“6gŗŠ€nķ6sS7ys6O@78{S7‹āds7ƒs8“S7ķ6ķfāN`Ļ` DāĘ@8‘Ķ8‹s9ģ9ķ9mŗ;ms8eķ<Ës<›ŗ8šs6™€sŒ ūBĶZŒvĀ3į35÷ķJ>’Ōā!l‡?gŌÂLhÎPë4ô°)0 ô2BEķ!8'č"ÔBĮK1yīxöęB;pėi%“&?J´#NB-zâDS”EWt"PÔEUTFaô#"ĸ+(â A%,E{ôE[tF_THetHtHi$b"¸áÅ´PÖáV¨ƒBžâķA=43ÛMkp$žŽK_˯Ō) ŋtA1HˇôƯČTMŊž,ķ%×TMSž°Ļ–Nŗ’|M=ØŖ=öÄO˙PUP5HĀd!vĀ!ÎĄ"ˆPÕQÕt¤eÅ 5¯p ?ŊôNUūŽX¨\PS7U°ÂtJT™-2"MO•UEOs‚B'­UÉ´K“J5g55Į&gJŒV*Í™įUX/XYeXÃĐîŧ0!õ Á"t ėPސY}U ķ5[¯P[% ƒUƒĸs’ÂÕˁŸt17'Sq55)ĶÄB1Ų5ŗÂÔ?ĮT^­ ´ä ˜`‡îÕ_Ën†Bßô_AĶšoNSéZė´`—­†°•ĸ/¸ÉžHkvzŌ Č oÚaÃZöbCöPĘĻcodL†Pas5K83? ļaÕ°Sˇä ĸĄdõe…BŊe‰nöuėŠP–gyö÷ eūôL#ƒ63₾Åfõi ķsrFô”ŦE˜<Įj¯k¯æ÷Œ"kmdk¯Ö/žļkĩvo*„Āvlš6lĩvmÅÖkŲömŨ–ž|mũA=:LAĪty:Ŋž–Sŗ ¸tiˇģ:Ķ!9Ôp?įZ҆eCuq#t…üÖÆ"×1ļr€÷ÖÍr'‡N,g*—?ۆsz•aUōnĢd” ?5ôq§´sŲøœBscw1$u—R_ÖũÁ0÷!lˇUë=ĸ.Ģ$'…—@bą~7ĮRVyQ_5§Sį­{¯W{ŗ—{ˇ÷zahģW|Ŋw|˗|ĢWJ ėtOŌĸ´ūų‚xŖ7ôŠ÷/PöÅ W^ĪF+Í‘ļlĐCˇÎAP*L~OÕcÜpAüeOrAå–›øĸđu–0ԁî‘ā ƒ78ƒėp@¸ƒCX‰tā/EXx02…šn…‡ˆąXø…]"áĘĩū6/5P~žm})¸ģrLˇv)wņW^ĩÄo?zļD’Xn؇/4qœĸ'%o§X á!Š×Ąž8Ų´8ÄzgĢČPųÆp!'‘‹ĩ'ō°ÍxąúÔxˏī8…ĐĢ+õ/Ē$B ÃzXŒ7+ÔūÁ‹ûa¸˜‚Ήˇą^…V(!–€ ųKū¸PŒ‚…-ÄH oÕ-"=Yy&øŠēîøėX•Ķ˜•ëņ¸[ųđŒÛX–išK —wPgsŠnŲßánâÁH%P>fŽä"¸mØ!xĨ¸a uÖáæ "]‰ŲBˇˇDš›‹ČQ„0oĨų›§Ö[ ,„A’…‹0Í0ī‰×9čHxˆôŽ_ĩđøŽYÖų…'™Ū™Ÿķ˛ûvšĶžÖGč2Ô"šœQ"’B)⚅ˇ(˛A‰ČyqE(xá (ŧ9ĸŠt”āaUÜu¤‘§5Y‹(>ڗSúœ/§­^čÕį×l:@­S‡Ļƒn0núžūŖöčįŗtú…€ē¨qZgĐ7pzwt¤4¯"ôŖõ(r’ˆ=yĮļ¤)Ø)v9s/L:oDˇaˇˇ(Lš(4ˆR4ÃGx@ũaUv—­ĩĨÂÔúēZšcēŽãĄŸw?× (2Gxø:4=gb3€Ĩ]ļ¯ŸÚŖbUāx Yļ.Oą˙5~ŕG¸áÂúą5ķ/ĩÎÔĢG;QZĶ‚÷ dh‚U;ļžwĪ4m4›ãfĒģ1Ÿų`}ā/yûąu;ø"q Ģ[ÕMu˛so…;'|e›´ô¤ûĩ 7e_ÚēÛuŠ,,ŧūB¤!Tģ˜lĸ{ģø‰ū앎/§ē7}Ģ)šĪœWõŊé°ēá¤Đ!íŋÕ´­°FžšW˙[īJhžąYˇT ¸Ŋa7h{¯B3Á˙ÛŽ ‚_ķÔÂĨČ Mw7œUŗĐčŌŗ*ŧéjšAŧŦú¸K<Ã=ÜŋoVĒS\Å ÔžĮ{´Šŋ}¨Æák8 oBŌÂQ|Ā{ÜuŌ—äËÅ­)Æy—˜6´ČÜ/ŒqĨ<ļ:<ĮLÜĘŲ×pŠĸcGlÅÁˇ\rX<^•yUũ§ÉËZ´œĖ7ÃĨčÃˇœvöœ įÍŅ0…’1ĸ”ŽG›ČûUĘüjÍ=ĄËúÉ "ĘķÜaŠüžé|ŊWū7Ņ=iƒ(“ƒÂJ˛ŋ<¨´œ”s­Î˙ĄcŖíŪ§ŖāũßąkäšÅŅŧ"ßAŨ“â.ˇáOøab—‚ÚŋŨđÛĄũ(Ā Ž}ÛšŲ§Ŋ ãCūã¯]Û#)Āũ`%™ØaČ`ˆŨŨÖ~¤ūTɯ•Įņ=ąÍéĩM:)˛ŋãÆÔk\nĀÆĐK_bÔŨ.y¤/$6äU>ä‘‘+má%îōëŠūä‚ęÅ})Îūëˇ^Üĩ^âMž °ęĢ;PŅ…žˆ:'Ã÷=Ö-œŪĸ>ņBũĻm< .!å`‡œl˛Õ×Üē ~Œ‚ÔŲZááŲ  d˙EFQė9PԝęIūí5~)8žôĶŨ˜}õ%xėžäSŸôûbíˇ=õĶ] Z_ôÍ^ãm_ŨûbÛĀ/Žž _zW]ÎûŪÂåÔPĪ‘_37šfhČwŲ×{|ÁūįĄ^ŠÔ}€ßė•Ŋūäbãi?÷XîÍ^‚ ôãũ)~ô‘^íI?ôÍ^ũŲöëŸ ģū4(€]ģûüd1iđŧˆ1ŖÆ;zü2¤Č‘$KšÜ¯i˙üÁ;hņ¤Ė™4kڔ O“—ßĩŧķĻĐĄD‹=jķe;Đ^úƒˆ4ĒÔŠ]ūãoeEĒ\ģzuúķ*4õ;øÅĢ@¸p÷đÛw Ăũ2.LąŨÆz  bÆz ŧŲ`Å}đž •ÚÕŦ[ĪtŠUlX×´k$kÖā Amûū ūüdL§đĖtƒ÷ŽCžÁ›Kõ§ēbÖãÎĢŖĩö"ŧhš­ŸÎ-1Ãum Ę՛=\ÍčŲķåK°szÆ{´œųąúÆØÜcƆ_|Ņמ?ôgE a“ya„&ÁƒĮ-— „JՎNĖųÔۆ"Ž•?ØŊ¤–2NaGb‹Y„•ēHŖI-‡5ĸŨôuØlņY•c•)`‘q†Ø’}9–—“O>YØg5 $a-Yd“ŠYļPguũ3€ÔÍ“1§FlôĻhn&5įšub'švî‰įmōųgŸšdæKĒ §Ÿ‰"*'Ŗz i ū’.)Ĩ“6ižŊ‘ĩÃVWĩ„áŽĸŽú"‹°Q4i¤Ž VĄŽ*ę›Ŋ9ÄMaÂ*UJ&𯋠a“ErY]Xŧõël1wl†Ė^E,´Č:û*Jí  §>ūô7ĀXcĄŲŽ? ™ęŖ–bj)›qōԎ]ėÔ_iņŊī? ŲĨįKøšÖŽOģą‹¯ŧ˙l#§]ˇ*ÕŪ6÷šûîŖķukĀ•š+'ŠäÎŪ?ë š.Ŗę^ÚqēK2É úņÄ<}ËÜÅ-”RC‚Úhˆ¸Ū<ĸ‰s9Ûš8oxÎS)ĄŠķĪ-ōtŖhūhë7y-”¸OéĻŗˇÕĻÉQˆŗV5čū´]kÔė×WģÄM4đp“Ā\2“i¯A¤ ŨŌ:EŋY˛ĪtOڎĀEá?Øŧ)Đž‡ `Á…ÛÛnß[ēĻžR>si ĩ'Z6/G>?œéÖÁüP:ŖKqŨ(‚Š!<ãļMqëu3<˛Č*›<ģė'Ûî3¤A!­sĘųj3ÔÂ7W4Ą3¯áĐA_Ė{šČ{ˇĸn ęĶéĪĪ”Ām1g5œįĩŪŅĄzÛ§˙øDžH};‘øÅÂSÅČtÃ֘ +×Oūûl3V6ėŦ >ë)ę#/Yļâ$ĄĮ2ū@Į;ĸē‚„Kz~Ã’ÖĶģĀe@Ō@fĻ'l„É ūkĮ:,ƒ°‡đDĨ €žö¯VębŲˆ?6ö´Kɰ#9D Iz@ŽŅQōGūĒ7—Ķi–ÛžæĻĻëIą5)Ú\\Ä)Ö&Lr“:žeE-6‡MsÃß:˜(ƙxëlN;ÛßĮ8ĘqŽtŦŖīˆĮí‘e ^ˆBČ ļ8í8úÂ[ž•¨ė)l‹ôZ#5F˜d[-a‡ "ō…†0ĀÆÔÎ}ė­I~ąá$ōāW{)ˆ\ ` )ũC~qaAÖaIƜÃJŋ‚Ë˜ÆæHFĸÎjëčĮ/‰5d*ķ‘Ëd¤3ƒ Íd2sšĪLĐ}Õą­LΊŠLūŖ7šR5ƒôė›Í1!ķôuzd;Ë _7ĸH{vCúäį>éĮO ˙ü§@ zЄÔ  (CĒЂ:t eF°Đ….Xa W`3ĸąŒhHƒŸĖįq¸1,d%mĨ?aŠK[ Ķ—Æ§!1PŌ<9ÉŊ<åw8€?vŲ’U>å)Bä>&yÉ[V–6=jK&ųžœF.ތĨ?€K¨:ħ{Šd]^ ֘fˆ\iGÆúĄģ„u­beĢ[Û ×ˇĘ5ŽtĢLQ7ŧ–'/ŠėĻ<˙ĩÅfˆ€ Op9—ō„…°…ĘÜÚĨ3n(ļąB CūP 2ô@LĐtZĐ~ļŗL`‚ HkZԞ–ŗŠeíjKËYŧ€´˛Ĩílc Û°ˇē%mo9û[ØĻ–ļĨ}-q™ā„.xA ZШŽP$„a¸aČ, Č §ĄŽĨ2MšXa ^īŠ¨žü‰r”ķĒ>õFįYG&ˇJKŸö…–[ũ‰c|ēˍ T‚vß§‚j´\Ĩ{+€mhcIpC ßđkÂŅībû÷cFëģŽđX?,a‡Ä&1…M,âxÅNb‚Ι †´ņ"áÚeo,ĢĖeœéÄņQF¨7îĐĮĪ͊˛‡H"kg*‚‡6ūÆBH­t=™ciËöÂŨN Ē N‡r‰ø ÅŦ$č`—[™āÛFé@EĮ ?üåĐ´xÆ3ŦĐ[’“ãûxæ^qGĶÛt(ôY^Į‡'Ąŗęžôđ ÷ņ{ĪüO?AŊ›^4W˙6OTEÁ˛Ō;î‹üšWNū9Öų}ôŽoÉ­ōžrÕYܰŋ˜āe í6dŨĐÜø]ôŠûé…rĘ÷´/¤ÍÅGŋQü=—ę3=+ĮK˛ĨHŗ˛Ũ_T;Úą–)qéQÔZ4˙ĪjOÕÔLĐdį 1ü05ŌD€Ķ´zÅŌfW-Ŋæ#í’^iįĀ€ü׀¸ȀHMč]“N@?ÚE)ā8-“Eæ‡c#ÔÁƒÃļXXô~78%˜.Ü`}FĮ~Ų!~g„5w„:—„9'=ĪĐm;Æä‚0Ųc*ĸ{Ļg(1× ņ ȅ Ą€ī°….1†Ē#5fø…Ŋ"†j8,ŅūŊbƒ!7 *a8.ü †:ķ†n¸+Đ҇ 8Ttsŋ2T-ˆq!.>1†ux#~Ȉa7”*}8,Ę1.á2.ĘˆRƒxd  į#3&Ōh¨…l(. (5]˜Š^sŦ˜‡vx†e(‹Š(_xŠy(¸ˆŠ\čŠ`¨…~øŠŋ8Šc¸†ihŒÂ¸‹dH!Jq6W QĐ% "ĩ f€fËqqŲĮƒ\‡5đĀa†‰Ų8ËĄƒQŽ%a3â—A¨lCH3ŧSXm¨B+1Lߒ=^k”DWĻVÆ m´VÖMá-ūøtԏųFų8aPOz„ ‘)‘TÖ Y eY ūQđÆ ađrŖX›RŽ1(k°o:s|!IIĶ /p!(šlč,cÁ[GNėhL='^dĨ“;ɓ=é“? ”A)”>iÚ0:-1„U“Ķ PĐe8ŽZ¨UZUi•W‰•YŠ•[9[QYZ]ų)`fpZ]š•g‰–[9]—åd§•–q™•bI–^)—iÉYNāČĩ[ādLfy—…i˜‡‰˜‰Š˜‡š—N Uā_Ā^āiQĀ’ŋķE/V~.)F-s"áņ†žYŪ7/…/HšY3'Ø! ę(lIy“ũ,Ci›ˇ‰›š)”.ÆxMÐU”@ū×Qõ4RūÔOʼnœÉМËɜ͙œû4RĐPČ oÎi×؜ËPœÚ‰ŨšœûDÕéÎ)#eÉ Rҍžãɞíéžī ŸņIžĪ) ‘Y™}Ų—É`c".˜;Ģ  Ōr1cŖF“žy1ŨāŠ búå,Ë1“B¸ /‘?@NL¸sē„ēj–¸SsQĄf vkG‰"ø¨.Öĸ/ēĸ.Ŗ0:Gf•,:Ŗ9*Ŗ; ŖI t:ÚŖCēĸyŖDĘŖ9ĒŪâeđĀ?Ûa5H*ĨBJĨIjĨSzĨUŠĨ[JĨ¨į-íĐ QāĪåe"Å -hõū׈~ĒE§ŖaIÔ/ģĸšzˆ§…ūéĻ/Rũ™Ũąk˛)LJ¨Hh¨Jˆ„äĸ-Aļ Ũ@Vnã/`6r§&a—Úb™jŠÂß35~膖 ‚Hˆ›jĒûāú•R)•ФĘĒŽš^ VĒĻŠ´Ē3 úļō*ĩÚĢĻJĢĀúĢÁJŦÃjŦ'†Ŧ)fb˜jĒ1iKQ& /P‹ęHē§ąbMeõ-Ŗ™­Ĩ"k¨ŲHظšÎC, ¨ēƎL;ЍīĒĄˇ;ąAĢė8-Øú­¯ąD9@a”¯!e+Ŗ#F’˙ęMĸ(“/Ąn 62Øu0IŽĘ>ĸčūŌ@ž¨ô ’øú3ÃŅ3Ų#ĮÙ Ë.GoČą˙JA(Š‚ą$ģ#Ėà Ũā?•ŗ:;wüŗdôbc„);Eė譋ō˛ĪÃ~5gã4˛B{ŗ!qŖ;đ Gû´öâ!ĀŲ'T[ĩĄã ņO‹43Ø=[ĢvĀŌm:˛ŽZŅi<ëM+Ŗ#ž&˛4cļš’DŽyw;OeFŽwv|ģ*~ęĮą™äh°SN[ŽįH3÷”ŽJ6„˜į˛76D,öJ›u*¸?´Œãȸ{Ú!b7ˆÛš5ĸ L0f+sdģ[Ë>7j›lÛĻnûļP¸ Kˇ˛ūĸĩ§['ŠŖˇĀ›5¸H'9˛Äģ#DH„CUģĢpį~Ą ƒÍÂ=Ûa+B8ŧ­ķģ8ãągŌWLkˇÔ{ē ûi Jž Ļ,ë:¸Ģŧ9ãrĄnwKBđDŋJ{ŨV}é 5öû#PdēŌĻģ=į6š›ŧīKuprŋ§¨Ā@AZG.Ĩ÷ĀĢ]7Č ŗĖÖĀiģJ6Z'„gĶīt5ūK#ߋšpōkĩŲ™E‘>](s3ŗ/‹“Aņŧ‘%Á—ÃQ2<œÃ˜Sy5Ä6ü’J™1rĶŊ˙ēlĄæPuˇ[Á.ō°(l~?EB‡$b|{#Ną¨ōˇ~VW8Āߡū3’¤!žūJ“‘Þ#čņÃ7 /ōCP1ĮėĮ$Ä „BslAt~ŧĀx…cA°Á§Āߒ?hCe<Å‚Ž+Én:Pės4ÃÆ=ûa64Æî'lOF=7”LøĢN*lĀĸŅÂúÂE‘Q‚ ~ėÆvl TA7L˕GØŖĮrĮwÜÜA tËG|1’•Ļú0Ésa”Ť]kÅÍL>g!ĶŦ}ģ!7˙SēÄ!ÉN“?gd”aŧ47 dœû™qK4Œ‡Āv‹ÆLĮC,ĖžüA6[Ë{ŦŗĖÄ|ĮüĖĮČ€L.ķ-ė°¨E ŧNaLä‘ĀØLūÍQƒ,eA~ŗí§+ŌÉUĢ3Ļg"ŅÜyąiVäĸEØXĄ’´0ÉĘu+Ā]‡Ÿ9plĐu,ĪÁ<ĮžsĮËx\ĮqŒĪyėÆ4Ät‚:Ē]KŖÁ ũNŗ46čŽí"ØŅĘîģ§HŗrfŊX\,E+mņÍ×ã-Ųp" lš–,,īŧŅRa$-ÔŸQĶEĪ”ķÃ~Ņû„lŗķLÔw9ņ×7ásfũĘ|‹m„åŅÖRíUˇcgrÉnęØ@s;Ȱ4HĻÎ\—_ËDŨķØiÔk×ŧĘWÄŌR|ëyœõ!>-Đø"×ūâ7;]Ã?Ŋ8ë‘ŗŦ$Č4Ą.Ú- ]ŽcalkJÚ,ŲŪ!ŲŊ¸;4’cņ}ŸMšįz"htf<°~üš1e냍e¯ŧÛ3įēĄ1”ė $“a„ą9ŸV2×wA9øA^R—Jˆaũũ$JBØF Ķ6AüVÁAW¨wŠĶ]ÕM¯đ ŗ“õtQ÷Ÿ˙ÅrjNƒĖmÁX¤§”Ĩc—ËfÖíŠˑ!Äō- ˛]y’‘híÚâą9~ä2ž%īq‹‘‘T ­FWžÍŧžž˛ÔžNĀâ. aƒŖėWcœ¸ĩ+ã#&n~&Mkū°™ą,Ú”ĩŪaQ!‘“Žūŧ˙pānŦ$‡ņ%§•ņÖ|Ąã˜áIIĸēŨUqā…})ÎœŽÜĶÕRžbgCyQģÁˍųį äߚ40SÕ§+ŲCģe.+ۗ/¨ŨÎũé*ŖŲŌ ë@Q̉ņáĶ–DhqBAą$j—qč†ŋ¤K °-]TæL’ûė}ņJ 6X€!˜ôĮ*]íÛ>‚ÖÎíąîíŨūí6d›Ėō4ā>îáŽîâîîíīä.īė>ī Ė^ĖÖÔ/Ąz.á ĸ}Ŗ]1ã¸Đ>¸‘Kd,Ž,&æjū°ĄŪŽũ‡aN”0AßxߥßûmėzQĢÄ% a‰>K wė˙{ƒ ‡>×°`K¨T8”Œ\v?$ŗWŲj#?oŽ@Ÿ’B¯yęŪ vCôK¯ôM߃D/T;viŌ‡sdۃ^ܰfãUģ°ÖMŧŖNkīclępÛä͎Øg=yâö2¤/_DÄAfo›Ŗ8H&ėā9“¯C–/ųp¯ųŽ‚ųčōäŦ—&Ūļų”ßų•?ú—ú™ĪųŠßøŦoú‹bƒfĻ@[ëū€ĮĄ`c8ÖÕđu[ž?Ąkkæ ¯ŪjíΚūsaô:íËs´gzvöxŽƒ&?|q˙cyÖd'Ü' :Ē-Č+lwÖíĐ7:~%w3sk"Â÷jmjôßüĻs;Jh˙ˇ˙°ķčņO ?˙āDxĄÁ„ *t("Ç )JŒXp"F9fœ¸ņbG’Kž iQdʓ&MB„)°;x5•íđ­[7m5šqƒįĪß:ũ„ZDšTéRĻM>…UęB‚˙ÚÔŅMäTŽ]Ŋ~ö_ÕąáIc˛UėZļlá1ŅJĩí\ēS *|÷bMxN¤iūŊ:ļčŅēJŲY<ü/ņá}ą!\ŦXō;‡K~\Y˛d˗?ļŧYôå‚ĄKEĮpņįÂđ˛YXölÚ_ũĩëĻ"?‚wk˙\8؃[áíöĸĘ(Uvî<¨OAŌí_‡Zĩ¸ijąī6YƒhŊ‡GŸômwš ɧ‡/‘ {ƒdqûÕĘĻ~ūũũ˙žvøę (2°Ļj@ėBŸô“B / „Áū¸YđA ųÂ0@Ä/ÃWdąE_„1F_ėF'fÄ1GwäąGäoÁĸ‘‰-ŧČb‹+ĒĀīŸ~úŲ‡ĻķâŖ˛ŽĒŽūrž*ˇüŽ,˛Š3K1 šī ~ "īŊ1…à .ŧÆJŦ$Ē`B˜ĀķN<÷äŗO?˙4PA%TOB÷ėĄOCųLÔĪEmôPI'ĩŗNœØb‹ČH! 24TQG%ĩTSOõĶ *ļhA2ö\ôNPQĨĩV[oÅ5×R+ĩs‡pĀá‡=įŧâH-ėĸ (ČāÆ}njMiÛō§M­Ôœ6[ˇĘĒęLxēIK[øÖÛȡ˛ÄŽ\‰zķnĖX毝¤ų‹^zkġŪ|÷Õˇ_~˙õ7`€¸`‚68a„V¸a|kÜâ˜zĨŅÉa‹Æøb3æxc‡ķMæ zū•y¸F;Fųd•Sfye—[ø9™ģ‰†Čx—Y5 /’‚ fĸ‡2›]ŖŅ, ~˛,úh§“J“#xĸ ÷éëÔ=s „°ĩz-kßôghrAšķķĪ ũÔæ‹íšÜ.nmūāĻ{nģßžģíŧņ–ģoŊũæ;îŋŧpÁ ¯oSčÎ@†?<ōÄ!ŸņŊ%ŋŧrĖߜō˃Tđ8iÂ⯠Ų~ŧsË9×ŧõĪYŨsØg—ŊöÕmW=w¸ŋõænœ°BI$tâ&7­˛ˆ¨Ž—G¨1ųŽe>zĨęM Ĩŋ­ZúÚÔŨš"Žĩ˙Šû Â&*ËŌ92Wk¤×WŋũūsŨšũ÷įūî察ūûíĮũû ˙ Bi´ŖZŠŠ^˙'Ā60ô(ARđg!ƒ#ļũYЃáCXÁ:°„a I˜Bŧ=î* úÖĨ˜ņ—ƒ hŨ8ŸĐžŖUëKãNĶx(Žøá…jBbW°ĻĀ$råkŠPÚĄ  Ĩ1b ›€Lg•*­&KÃŌUÄÅëq‹cPĩ¨E4zŅ‹aä"ŋ¸F1vQplãĪhĮ9⑏oÜŖÉÆ?𑐂P"á‘ ŠMm†ŦŖ !Į4ö1•d$19É;?d>蓈ēŧ”>æA¸)†^ ĸ¯ŖĻƒDFŅ}Ī{ŲÆÃÆôŖˇ–Ķ„øŌ˜žÍ9ōú扏 ä1jŧčÁGmĻI]õMšJf4 ųšŋ>Ņe Lf ÁÍ/8Ā!F\ījßXüÖZBˇíQ­ Ÿ/âĘ‹Ũ}@j-zúTũ’kōÃįë#äįVņAĢ+Ō}°wÅrŲ7l|“ÛÖ)zōM-Š dši†ŒaāÍtŌ€[4đöŋ˙Û ‹ ¨#0üĀŅĀũK@É 6ÁûŊVC@ō‹ŠB'ÚŖ@ K šx ęqž $‰ģžĐÁÉ ‰Üp8ŒKˇÚ{3ã7ļC>}ŗļķŒė?Îč $ĒgØÆCū̃8Åh´ BlHŗLŠw#°LĀĐ8ŒĖ¸Œ%|BÎX@ɸ(Ø8Œv ƒ¸ŠŪģ> 6–(ÁûŊ¸`oC™8í[‰1L āŨ(;zÚ3C6ZĶ t˛ŧøË<áXB)\ˆô?Ö`:&< ͍AŧAė?¨+Eüŋw‹BĸšÄ0x8°Ģ€Û¨ŗ4ŦĒnP=,ŽÔķÄsRŸvđ*ŽRė:fãž Ä–x: 9Ü9:LŸÔ5ņ!‹¸âÂŽvĐĶ Ö€b4€g@+w; D*lBcLDɀ‡sÂĘXũsBÆF D0€b FlD tÄ Ų‡wūH x ŲDBcEõHŽ^ģ\|GR9 l+ÅŖHčŠGsyj™šė‰7u1Š‘ GP#7(Ԉļ“?/|ŠeÜF¤Dft7`@DČü Œ|Œ‰tÆĘ¨Ģ2C Ш Œü?Kü Į@0'd€Ä•<8švƒeHiëÄz|ˆ09H™ķIēļģ¨ m˛RŒ¸ģxĘsG7˰5”ZlŋZë;=7ŋ˜Zš^$ů`Ff¤ÂpTÆÉp ư\FŘČbLŒ´ü™ĖFŗlIpL°o”É‚(F„°Kp„KÅøÆĖøÆ š\ oԌžôF´lKŗ4Ë}X‡ūŠž†p’ÆčÉĄ”ixņšÅųĶ˧QŖ'Į5Đė>+ú‡ßqJ¤ųJŦûĖä; ‚T7rŒyDMH[ČĄÛˇrIHŲËŧäŒŧ\ Œ|Km ĮŧDKwCKädËËæd‡æÄåÔÆį,ÆtˏŧÎéĖÅĀč4 ˛´Nē4ˆv ƅËÉĐĄ­ ͇ˆĮ۔<ō€Č÷ŧ†xŖĄpĪä íhJËs3X„š.Čú,*Û<ČųCPéąÍĄëĘôÅßXĖŊäČÄ,΋Ŧ édLo\Ëm4NëôNĮœNp\FĶ NŊÎíIäÜFŒIŊlŅē‹`ŦОū˃ĖL͜͠XЍhPû´÷0Šë9ÚG Đ*ƒĘ‰ČŠģ`§Ē|0}bŋ;ēËsČ> ŽÔhIÉ KŊ|7íôÎe\Ņ…ËŨNåüĐætŅĶSŗ´ŒíN7 ĮĖXN9åK0­Ņė ŗ2m˛ĖĄ Ō„8Ž´ˆ"቉B-4…†$%Áë; Š‹xzM، +Ēķ¸Ô§4F ļâ[; ķJ밌mTBáÜĐoFEžÜ‰l@7Č ƒRV WÁūđ Ē,HzRŌ~ęÔ!ÚM=' ũMúGkdBDDÂa„7•ô $D\@$äWz­vIĖČ O™¨ āƒ‡°§úŗĪš0ņØ ÃÖuÁh¨ ú@tJm`ūį7ŊUo,Oz-Ä0ŅNÎį”UŗdÕÐK…Žh§ŪÎBę܋te”djfüH!Šé`ūˆ­ļ‰"’ģÖLû§,mŸ—u;™†ŒėZĶĩ4BWļP=NԈĶļh§ļĶđ„7XÆN@m™üHЖŒÆ(íîėh5ÅN…XęĄđšh!T¨#}@ÃĮÎë*‰šsėÔ‹uh :Š |Gí;‚€ĄâŽŗS<ų+ęQˆRöÍī€U ĩČ:ŪåÅüP($K]NS ÎÍæjŦæåcÕ^ŨUo •ÄđŒX}a­î]U>Q ™4JdLäwl qîîEî0WėæîŖgÂ3đÁ%žO”ŨÔ}<ƒ°đz Uá gŦ¤ė‡GäY„xŒú5XÃMí ā ĖחdDĀūI*„U¤É‰ä]Œx‡`,.Ī‹m0[F­‰ đļÆ[îOđHëēĸËi ÔĸĖȀščXkļŊ(U<šƒ‡ŨKA >Ÿ}rĩ{ÁŖĐîŒŗė¤xۚĨclF—Ôãn­Wāaä­ÁX6 ÅÕaÔHxđqË'…māøōę# é^r§Ų…4t5Ų†ā:āAŌ)féę "6ß VrHķ!2!ã}0 xxܡQ'˛Č;`û̞pžTguTwõUOŦ;+õQŦ´RŸpŌX‡õ°â–ÂâuϚuŽ”1_˙uZGš]Įuœú!NsuŠ’&âRā<;ö\§vU¯öV×õkumūĪvk÷vlįöp˙öm÷n÷o—,Üŋ ×Û\įĘwg.xwŦx§÷yˇ÷ˇē÷`×wyĮ÷~ß÷z÷w~˙÷|ø‚øøƒ7x‚WxæĸˆũdŊ2ŧr÷sˇxrŋxsĮø×øŽ¯ø˜Ķšö4ˆüđ9.Zŋú°ąæ6‹&ÛraH,ķą;°ęCđėxŠGƒ0ESDãųöųÉûųrĸ8ŽA´,aa…8é­ zĨĀų›wzDúC‹úîų–P´ģŌgĨzĻhz¨÷zŠ˙zޟúÛ {˛ûŗ߲ 'äÆ@ą/{Ļ{¸{¨‰{ GļįČɝ08„Ü}RyŦ”ˆąĨRū—§ēČ&ãĢ@)3@†Ęõĸi:ČÃč.ɧ ĘwĻh‚Ļ Č|!ÃčŋeŒ!Œ&ë ĖīŦÎę+¤˙ÛĄ ũ’+Í˙[ĶĢUˆÉ˙!ĘØüĖ×Û2}ĘøĩÚ/ˆRgũÜ˙}S§.âĸ0P†.2\ČÚēŲRĩz~ŠūjĢpĢ­Ē~@m~itūīšūīĪūđ2í7įī~č÷ūôņĮ~îw˙­ĢūģxÛŠ1ƒ)ŽXzü,äĢĄ2 ’ë€øį¯Ũ@íūąû‡pá„˙|8ПĈ œx° Ã„B¤˛ĸȌ5dčQáJ’.GžŒiR%M‡0'ž4ŠsãÁ>ū†„ĮO(ũú”Uog?ûOÛu4TdĄ…[$æ‚4ÅĨmŧAĄ„rœd–ÁĶjrØūáhž­vĄ‡#zøāSŗĮ6˙tƒDd⠃Lŧ0Ŗ42‘ãŒ92ąŖŽ<ö¤Aō8¤‘B"Yd’?*Ų$“O å‘NFYå”R.ie–GĘØĨŒLlq>„0æ—XRyĨ–inŲ&›oĸįšrĒY'L:qÅ)ā@:ü™ÃŒ:Ä8¨›t:§ĸvšhĸŒ"Ú(¤ŽJú¨ĨEzÉDf¤đᐔF*¨ŖNZęĨ<žĀč:öđ§UXŅ…ŗZąEN¨ˇÕe”‘ØĢ¯žš&ÔSŠ…øĢą‚XÛSÛ,lÉ>E‘pa0Mc2ļØbŨdË­ˇŨ‚û­¸á’;Žšåĸū{Žēé˛ģŽģíÂûŽē×Ō+ÍÉXë­ĩņō+oŋ˙ú0Ā Ėm2W0Íž×2VoÁCü°ÄS<ąÅ˙ģmŊŅ0ØwÚ^2Æ"“LnļÚ6 ˇĖląE]dqEHHĶm§9›ŗÎ¤™ˆÛ°î4k˛Ũl™ĪB#mô˛'Ū:ū°ĸ~ŧ*ןÕWc_7a0æž6Yƒļ}†4ėQ–œØkŗŨvÛËfˆvQ_ģ]÷~p?Å ˇPla…[Í ŒmäĪŅI#žķV>ÃClâk­ŌˇAŽ8´چåŽ4?K_ÕŲA§9UáįŅnöydĄ?„a鞎ĢfĒū+ÄúčO••ęf“B7WåĮë ŧ4:ĀsģC)"Ŋô–;Øyņ=MŸ}g>žP†ÜUŅņqfoũÛmŌjŸ>oĻī¸úA'{ēˆķŋß!p(žf¸áGéđ†˙ëpÔĖ3s¸Ë€JÛŪe֑§8¤6Iāf(¨,*đ§IÕ0čÁ ‚ áIČŦŠ…%LĄ éwBú#Cę`eŠõBâp…:ŧá]čC ō0ˆ?a…Ä!ĒЈDėaūôG”m°„IDb hÅ%*qŠ´Úāļ¸u#)ÉáÜëgÆZđˆĐÎØ,É1ksnôūĐå87&øoK›#gz'šlp„% Y‘CɐėPš)šĸ¸¯u8ŗĄ#+éČÍE?Ų#-™´ÎyqFëœ~ĸ4ũ•Ņ“éĶ•`†"CJĒBņ[a*c›ĶāoY‚Ņ"/¸š_î*˜ÄŲ0E Ėb“˜ĘÜc2—6Hß%dtØ`$;Vô?S˜Ël&7ĩ™Í⯆Ūė&2ĮiÎrĸs›įTg:ŗŲNr˛ķ!Ëg1ãéN{ÂķžúĖ'?ךOöķ¨@ËICxx`|íĐĪíŠO‚>´ č?ux>TŽō)b<Ÿ-Ũˆ›`=…°ėhnā(9’ô5uĐūä‚SK>Ę4ŧĐ^hrČôĩŖŅ æKSúžWļRƒ=õ)Q‘xø ˙ČF=‹ ŦVŖąMĖ'D§"/†/T]$ąúŦ^ĘĒ^Íũš&Ąh(‚éGįPéÖˇÂ5Žr+]ëj×ēŽÃMŅSüąŽsėO†[Į:öw×Ã"–Ž‘C҃ëØĮB6˛’ėcĸ!ŲĨq5”Ũ,g;ëŲĪ‚6´qĩL;ppļũ9P´Ē]­j ˆĘâ=;(ÚHĮŠ4ąęrm´mkLÚ3ŪÆĻ—ēÄĐā6JÖ"WŽ}ĩër›RØÂęēLî`“ëX"E)‘ŒuģëŨīĩvqDāwūËkŪķĸWą‚ ã}°uqé/k‡ĘŅ%Mîô0Wģĸ\–ŋŊ+-Ü\îˇsüģ™`Ŧ'ҊRÔĄͧC xČĘD!Ћ0D!,JË ~°„KÜa“øÄÂląÎęA8ƆņŒUœâËXÂ\¤Ė ”áRįČ5Æņ‰YiáæČu‡~;hāŦjp=čä“=#[÷ĸąĘŦãkM) 9Ė4N&6—š4x žižæSÖ,ä1ûķ)MŽËī2g"ß9Čx2€w ģĪ™¨Îoôž ­įC‹™Đ9ό"Wĸ<'ÚБą“Ûzf2RÄE›Œ–!ūg~Ä0Œĩí4†¸!īŲņ”¤ÆˆUũ—놔fžt¤`kĀ{ŸcĒ-ÎvĀÖiNˆ…ŖšŊ°cÂLȰ—ÅŽ4/ōSaˆ°}‡ģ=vŌÂByĮ¯2m„8í˜Jšą•ž*gtzͰ MkHÃÛŨ!re;œbÍTŖôÃņ–ôžŨīwˍŽ7ũp~ŧŨRˆ^ĸŸę5uÕžúqūëáH<4é(ķũdF˙ĻąŦÎcF?,´]ģŲחi‰eܜrkF×-ŋ 6Øąfˇ„PkĮŽw`ÚkŽfoūCļ7+‰ųŗ}ŊqËŦčŊKEˆá›ūņč™ĻsLeGĮ¯zõ¯sæ¸HĄÍ¨Á.ĄƒV§4\ŲÍÎ%K˛V7šŲŗāÛë&ZŠs‚CüxPļd.Hƒ[E 7¯ŸŨ€”āņ,Ų9ŗ%ÂË<Í+Ž-c˜[f¸zämŨōj/õ—ˇõãMŸk…Tj‘Ā’v‡ģŨr[‡Zyšûßģļ2ũŖ'đ94ēįúœuņ)¤Yļë€S›™ŸG¤>40—14üÚ¸8q§ëHĘ[nøÔƒ{ͯ˙Į°5ĪūËûįėwČÎį?ų^åØČŋũ_˙lf+ÄūÁžG;,ŪĖ`Ķĩ×åZķū Ā6øSPYķŊ†ŽPQ đÉßŅ]ōF;P— •öVĒŽô=HL™]ķ˜PŒNø WųÎ4Xˆ‘\āUÎŨ­DŽŪL­\é‘^ęņZ˜ß?PžŪėĨü9^ĩ)āŅ-Dũ!Ūû1!˙ĩŸŒŪ†›įÉâųC(G4ˆVĩ F?`œáe–Ū™Ą–9˜IĩĄnTÆ:xĪÃŅTJHĮĩ×QD{X_QTŸĢ b§ußi|yÍZК˛ņZĘm!ËŊR!Náë Û˙IâšQŪįAáäĄ_&Â߲Ÿ5iâ?<Ãe Îy„æÕßû5TˆĄĖ ÄâĄķšū†DÄ˙Ä`-zUĮqĐöņbhŧ BĀÆŲY0ęÆYY6ŒŅī1ŲqLl‘–Í V]ˆ ÆÚ.ËZpŪĐŅ\+RÛO[G`aŗ­įuûu#K4ŽĨ#ŗŲZ9!"ž6ŗ¸\ä%DįY!Ԟ­Y;8@ Z-"ãÛÁÃ@ŊP’6&$IuŦ1QD.ÜįX“EL•ĄEb‰X4đ@G~(Å$ą!=H!jÔ æøĨ„`ĖT!EŅ!ͤĘŨTĖŅ\fāNŪ” Õ¤MņdN%Ë=OGxĻŊ ‘¤G~€ø€6Â9Ĩ€ËØ)UJVĨĩÅP;ü€16ūeUZc°€Ú?čM„%]™8ĨĨmņČÁ…oAänÜdPÚT]öäĘ5ÄPĨOęeMDQ_ĒŪõ¤N˛F4=œ ĪĢŠāV–”¨T[:Ļ-Ąrl”@ŧÎdØI™ä1jĻÆmdE†_ÄYåČõ÷šd×ũĘ3aƒüæLF6Rüũd`îåPęŸvĸnæĘå\aæĻgxą‘1Î4ˆˆd~f†0ĪšægÚViŅ;8tnÆFâĻagTģãsŽf/š˜ė\Ŗ%ĪÉĨŗ€Bܛ_žnÚepūĨmÖ\Mf|ŪįMŨÛŌŨ%Oōfoe>ÄTE  ūhw>’cŦĄy2(VaRRqAdf„.<¨@VzƒĻR 5ŽŸ_˛8Ø 1'I]NÖ­gvH€Ę…mîÖ$mjÆúåfŧg{æĻčMĘ\{>SPž§g€ŪŨ9H;Á2Ŧ…? Ā‚bh…8¨Y">)eŠD AˆD•B<<„réw.įI‰Ôˆö[‰Ri’W\bÉË­™^ÎŲĻ#FŅ~æåB]â-]mb†B]7ÎéŅų Ņ•ßŊÕ&āf°ÜąE‘9Č4RDų…i…8šRÍ\Vjer˜š_pé´9…—†ÜĻžPŦ)Dcˆ§3*’ÚņŠĻČGūƒČjĒéˆ4Ûmūé%ú%’<fQęeq §B`âi°"ëŌŅi^ęfM8D?lü†–Ú¨ŠFŽ4ŧ€|íQ ak%E[ÕÅ-‹~ĻÚq–1 ŦÖb em”éx†ĻNÎ׹i śâā¯Ŧ_¸™^ęŪŋĸ^ĶĨ™&Z!ycMŽãŗ™Ūæ•Ū*ŪÚĒ„ÂŖ°Íi*aÁ*ĄĖ-(6´ŪąĒ#€š>üƒH@X(Ĩ~+†8¨?`*JčĘÂΞôÃËęG÷˜Ģc‚ÚY Ž˜˛kģVÛ5Înšˆ¸ė­RéŪĩj›Öj6&í„X,Nǟ¯åßǟúā^€ĸēūĸz­9&ā$Îã'BŪ*˛#B¤ãԂÆĐQŪ9n(ŽĘĘėĐnš–YĖĘŦĐÜšNÍ_ü,/:ŠÎOeF¨ˇ6ŧí ļ*ēŊļÚæäĢ­6‹F-=‚â×ĸŸŌDŋR-°fí9fm˙%æ=á=Ōcûąãčūg*`;&ÄP¨ÜŽCÂęj˜ŽķHUÎîí îŲüÅĶjfįä+Ų­+—z+į0…ŨŽS‘čŅč­'­¤pĨQĶ‚ŸđFH Ģ›ĩ-*ÎÜÆJ!û}žO!fØh;Â_Í!6äÚæ‰ĸŲf-'zmææęœæœíēÜå!ŦBČîŲSđŸ÷~+P폠ū5oīîŒĢęM68+† ílI#0b§fU{L™™ú¨™Ģe.ĨŅßQY¸ÆŖ:ÂŖŌ¤íÚCÜgĩí_:ļ°Úę\Íåj?ÎcĒ#ėužëÎīLņ_æEėé՟Ũ9Ô^5%1¸ąîĻÚíâxæ#°ÎXėBXh•ŪFņ6c˜jŸŅŒjW­"5“VJ(.•jõR$"ōŽ„ôāOŌ§MÚ¤˙š§įÁįŸâ1 ž__Ō' žįL­Ų¯nŦų̝MIéÔōˇFÍeG™™ņgˆ&<(_$;eC]fôâááüX€,.؁đpÆŨ녀°ĶK|r,ĄÚeū’ûâņÆ6^°"åOū1˛ŪfŖâ¤Ė=́ėB!)'Pę7ė€1ūD|šęĐfĨÉU¯$›)™Vdė!î ;Y•&’3Žų -ģeĶÂeKĒ2'˔.īdCČ&o"Ö§`žōžĘņŒö2ĶŠ=č13>˛rø4bņõŨ.îrƒjXŗIą4O\ĩWQ8iwFĐZ–ą‡fŲEÏĻ)ÅΊ$ĢĨg\^ĒmcB ƒ´ą?Ē-rŖ2]ë$ ŪiëBá?ķ˛m)nâåB(jˇ™FÔčWO¸ØO`ĢsZHąDŗCŋˆęđĸŽc“aīšú^č=ū…h:Ŗ~ŊdCĢ’ŦŌāz•4köĘį8lvâo.ë=Īf>cî, ¨°ϟō%Qēt×ūi0ĪīÉÆ Y iĨfZęOīx5SKR‹‘ąUĒõP5&[õ(Å7 åˆŖ@Ė’Z°xđ5Ž1œūŠî|Ûø%lŽŽœrŗ~íåÖå'ÎŗLû$L%f­žú%@PššS,o^(6×é•ŌŒŗb¯’)Šsú`ČÍîëcsÚ{QÄøüĄËZv&ö%ĄqjŪQ/whŧq<ƒŅåéû­ČąŽ¯Må˛%"ĢŽ’7ÂwZͤ;ŋō-S›=Û6;?ÔtO†Q<ū×3aCE͞ÃB.rĢå°d„&„^q‘Yšˇ–ĘˆRā×Ā—_•˜&‚y÷äǞąŦDzsž:v^Ôĸžjˇâ>zc˙0ė¸Ė^ÔęœũæšÆļ0Nž§{렖b ģx#"€?@7@Āo^0›jB˜Ú9\8ę|ą‚kåRĨnDaErēU3Oø:ÔėôiÅ{ų­‰Bn/įX7…ÄTžã÷>›û†­ęŠbū6Ũū%áŌ­YŌ%ā$ {ŗļ^֟åjĄžĢ"M.z÷Ā6pCÄ:€a×Ō-a [­Ã 2–Ģˆ†9O&;X\rėîūĻ‚RBŽ:¤āhļ7čΝuč“™Č ēšˆ_ī*CŨ a(Ēĸ×JĄj2 Ģm ûĢĀúZ7"ڒmLûÄ˙ ģø^Ŧæf­Ÿ÷pšA͘e¨%†Û`öÍŽÉÂÖv‹:…@•†lšē;ŖƒŦƒS(…ĨÅywžÕvN…‚Š(ĸ2FˇÄ"87‰{[+ZáæúßJŦʲ&`ų™Ŗ°ģâN"*ŽpŗûäŋRû$2ÛæIlÂCla78@ph/š}¯ĖfižüēWNÖYæģWéÉDf'ĢûĸƒØŨ6‹rėõQ¨WYy~v+…vĖ ˙̌_<Ÿ;ūŦęđ°ķ*ÚĒŪ8 %>ũšâ>4öcLãĮ–Ŗęĸ.歞­ûšĩZ&ĀŲ„ËŨÃC(ÄĪsT‚ËüãĐ*ĶL)ŧmëXS҆wķ%Ž2RßSˆ¤õéW 6#ā¯)õ^Á§3‰ĪvlĢ5+Īŗ‹&kl %_kËßsZ—ūpúāTBSŨ5+ŸĘėQpÃW ¨KvāËü…žrŠ>„ctN6wĨ›B 4~GŨ†ūYã)+Ŋđ=‰æ|ĨZ÷æDr°ęå3~ĸ­ kųĢNú3÷Û7cĩąkõCúž§ņÔ[n)6Į—ÕíŠūf5@č€÷`Aƒ&T¸aC‡!&„ĮDÚ@ƒūÄ‘cG?NŦ˜ņßF"-ôˇ1%Ȏünc÷Ũ˚4qæü‡M'Ι jĐ&Bž>‰5ČķįŅĸ Ehķé͟CŖ Jķh;Š5ē;–lYŗáuS1&ÁnĪÆ•;—n]ģY–ü§cäē™-īxIx|Vŧ8đÛˇáEc’˜qå˛(žĩŧī?°LēÕûßá‘5+Čn#ēī^Õ){iŌ­RĄâd*ĩ*ŌŲZŸîTJķ*íÛ˛Ŗū|6<(6x(ũ•†Ë™zuąi'_,IŲzwīßūãĻö×ÎG7n+÷qŋūnŪÃĄŲĮ÷ŖfxŌ˛Ë×?žv‹Šõã 3ĪF;éĢĖōRŦ-v˛ĸĘ*Ąœ’ę¨Ēé'C…"dĮ€ā†6Ĩš (›6ŒmĢ}ŽÂ}ļɈ"’F ĐFËŌzĄ%~4đƁP/BÛgĨÚ RɏÜClÉ'ËrŦ ȸÉJÔîĘÁ0úŦŋ°H3 °#-Ãj& Sė‰š­†ē)!ύú€â,ÄÆÅ nŠ*Ē=DŌä*§ā†r‘ 4O4.͙Ē< Ė-!)-HS‰Ā#ÍT͇LzžlJJoSM›Õ8ې14ôà 4§?ĶÔ° 7D‘&–/$H΍S‚ÕíĻU/õ‘čĨĢûīČįŦ‹chDÆđđR‘Q[‡ēé°Ov1Iūpu9ÜIĨdWaPn6˛=ĪDgZ–ī.6=™= ÃF'&­–‰h'Ȋ .„(šũIq#Ŗ›Ę' ™FėHŌ UD% ĻūĘ É)MāFI^¤HIF ī)Ũ&įâ?‚”&€‘$ Á†FÅ,= k `øa-Ĩlh9Ãō‰,­˛7Å k&t”MœˆÂŦāxĢ ÉęeŗHDœXĢMlâŨ3Ā•-Œü”Ē1ZJf˛ŋjú%đāÁsĐņ´m†§-°ą6Į)–Įl§k’ŒâS)ē*z抧D§ū\déåiåņĘH›¸—L‹ZÅ<‘RčH,ŠČM#Ą>æĀÎoCÜPA7´APųã* Jg{X•qŨķŖĻH;p ¸Š¤d9I˜ØŌšŧ´FŌŅĄ)mW@xŠ?—6-(Qŧō‰ÕšÅ+ˆÚ˛ĄųTA‘yĐŲ”ˆ—Åqāˆ4ÍÎÁƒ #IRI`2”ŠÉô,đhĮ5w¨%˛ļo'1ChŪAÄ Ž!ŅĄg4ĨH׹lÍ NœĢIä:HšožĒĢ=Ë$ŅAĨ7ÁĮ>š UeâÆĒLUSo,T›ũ†˛ÃCJĩŒZȝį1zĘxôZVG’d°ŠÍ™ū (ˆ t-§FŲĘێ…_ķĖM „†‰]ÚcVY#ŨŪą–.uÂĮĒ8t[efO°b,ŨH´6”=v”@ÉÆđĀA‘Lk×wxlˇ9kRRĩĩwr°ŨÎWf"*úB$,ø2ā~Á–™Ėƒ=øĒ)/ÉQŲ7žōœQŌRģ,’‰1mzK¯ĮŦ[Ōí‚}›lņ<ÛĮŊYØĄQeÜ4ė@Ũĩí[HJ <\ŗÁá$ Ā1ë1™ûߡKąqw{ŽšuÁ$Ĩ¯ŦXâ}Ŧ„@^Ũ4Â`# 2_1Øc~Ę`Åsŧoûė‡AĖÂÆ`9nŠĘˆgūS8ÎVKĒ4ÎŦp&ČäLļË}ķč:üYc¯qÅÚqBÚr$Pą&ASūsĻČt’Ÿ:UIōæ’&NF#¤ļ.^‰>úa[%f´‘ōÆÚ#–:ĮËãÄNfÁÂĨpN<‹Û%&¸‘u‘äU;P2›AībˆjܟđØŨ­˜:yˆJ˛@w_äÖ¤3ŖpåĶĐĻWĨī…0käĢxÆ3: FámŋļŦéĮ:>J‹°c^؜dƒ1×Ķ{Mxžwa‡krÖŧ:ǰĄzÛāķÄÜCŒĒjšĶķŽ™-Xw–÷ŦĮ¸ënÛŦĢų ˜rNōQÁ3Nv­Eüâ™wá\î Ô;Ąa¸wS>ĮŖĻ‘Ąõ%īåu1Žy ãÄ{íeÄŨŠĀų„đœMŪyŸ< %Ļ-Ė—Pā3^ņã{uš´CėČūˆŗŽUvÜéi˛HÅ÷nÄ÷ŨF†Õî×úU­6Y"ŧī&ģ8ũņāæ •ōķĒʝĶô¤ŽĖM Gū9Å yv*Yō÷}˜Ą[ !•ékc{0xŧcĄÆziđ}^¨ŠKŋ÷ûül` HĀcÍOy6¯ēhėОã‚'¸øxO>ėKLâîВä(4ā9ĘĮînë\,â( á›Üéŧjn]Fs Fņ˛ŦŪė&`Ŗ|‹ĨúmŠxCģj‰[ ŋ DÆH˛n°Z*Šh#lČ3rP“vŒĀ|@đˆŦ¯p\Ó"pĮ„I|€ø(mÜzˡüēžÜi¸DĒšp\Ž,ˇ|ŽʒjCĖΰ*ÁŦŒĻâĒ *ģ —´‹Ŗ~Ĩā °(…sšP_ÎÅ3 ū0THNVĖ ÅĐølkR6 kæ ŅšEšNPĶƒägšÚB~ü)DZŲlą< XĻ˜Øp7–Ē1,'˜ĸŽä/üK‹Q!&e ŦĻ%(ņdWcŦÆ-÷˛-1zठ‘ §„(§FÂ=ü0]Ē,rFí mdjÃ)Ÿ¨ęŒ‰BØ Ė뗨i‘ ÃĘą9„"Ī<ŨDË|1#ēAGF2ĸ1ŋCVJŖ<¸Aŗ }*_F°Æ|DĨĄƒëQЍVČ<Âņ˛RlxŠÃ— -r7Œ+P†Ÿ¨Š˛JŒwŦ$ŧâīĀ*įH ņņJūž†Hˊ%åîH摸š•Äã9ÚÉĸ’!í¯ĀDačÍF:č|Í8ˆ'Ē áhŖCÎdˆcŊ,YÔlíBI €LŌà P2"1¤ōŦō%q<%ŖØ‘äæĨK^`úČ’Ņ ˛ō™:V.-ÉĻĘÅ$<"õ˛.čīˤj é°ÄÆ+ŧv)ĸ‚cQND2 ʇÂ{Ļi<āR-ûJtŌR"(=ķI€(ųáöú‰4' =ūĄIJF’ÚŌ1珔::s4ë2sˆ2aīįØÃ´ū8([žŽzūa9Ž'ũüHû†ŽeZÍ&BdühyGūCōČę¨SŅDčĸSžSÎūAüéāĄ ˜>$M-ËEÉqUJsIÖ(ƒčVâ/ļGXb.ˇ#úZS!6‡'ŸhæŦŦ3ą0Q: o@L‚57ņφvãOÚDâ îBûŦéî(ĸná)eZČo~iqL4˙ØĢā-¸! ĸ…ÍACAįs1ū5=e~ ôĐDs. .R˛šÚ“-q͈ ÃHėŖ7ãíÁÆæ]Ū@Ų6ÎÃĸ‡ŒK#/7ŠlôFq5NTĘ}Ô$Ŗ ɰūPžō,ÜöĄôᎊō Ųęj’K%ôA5Ņ;ŽBá:õدBc/Ö Žķ˜ ×č…Bė[.ˆO*HߐcČą<=ŠĶjtJķ9ŽisRãNņt‰VâŦēaˆ$‹6ˇÃŋx Ų‘ĐŪĨ­ļĄĖúu$h•Fą°BmÁBœd@Ģ[Õj}ōĒĩäD …M *ægg´Ķj€f´åfâåbĒ~†nØôEāUÖ¨]+fVT›q@Nl<Ų´ōjb#XhĖĒ…Ķ[Ãõ[%ž*\-–b5vb96c;cOĸkØSæøęc/öd7ÖcUcūYeM6e[f]veg6žĸäæįey–feög{6fƒļfå專•Ü€Ög‡6i…Viļi›6(`#|ūŖ‘ t ŋ‚늊d¤"Žl@ŗŒįx‹I‚P~‚a%T)üé&@‡Ũ‰8ôĐ-bɲá-+^¨t+x(ŋÖ°ßäŠ ƒoËC<Î]´ĩ-ŒËĐ—l=bq×%Ęå?(ƒˇ3÷r-7s9ĸr7÷: <€pĘŠ`Ws#‚sOˇt÷u!Âuq sŨK%ĐĀ”õ>žUWĨ1k(Uvju~ŗ>$l]āÎQ}×x•ņx•—  6ĸÂŖdĸ ī*IâūĢ"D~¤ŧ–Ãjˆ“-ˆBi"åœĄb„B,“@zi&b$Ŧ\o… æ$Õ'yå÷Ũ–—~įˇR)#‹yíˇņwë÷k2,âĀô—8€€īw؁ø€#˜ũ‚X‚/XyŸfúIļƒ+„8ƒX„-8„)˜Āâ]Ž6~Ix‚K8…Ox„Q8†mØwųá]žÃŨ‚Ą ‚Iŗ‡TSSUX H‰W܌ĩÖ›Ø~ ø)|ë5fâĢxŅ5¨´âŽ8|e#IļØ'Z"IēX8žJ~Ô78pĪ:­(Đæt"%ˆsŋĨĶ Ŗw҉å7Š÷ø~ųūø•ū8ĄyŸØû8U°ãKž8WõØ~ yy yš‘9’/™’3Y'ų‘;YģäāT?›Ë““!9€?Y•OY“S“ą W™“ •3Ų”+™•s•'™–ŸŖ #4 ×pĨĄ tWkqˇÖ|KÛô6ķãVÂ>ä)7'â*Ŧ>Ģą|Ŗ$ųI• J˜HŖŨĀKŠXQģ bä=*5ĮSâĀvŅ^Ãŧ:˜IU2ˇrĀ™å.›ļĐ €@ē^ÃjĄuæú™ņüō/ķY6 ÚS”ĸ-úĸ1:Ŗ5zŖ3Z‡)ēÉ´Áĸ=ÚSF:¤áÁ¤ūINCúöHšĨÛîĨu8Y ėĨŸĨoīöF§ŸƒĨuú¤5:Ļ-úĻŗv¤9ē¨ú¨‘:Š•zŠ™ēŠ=ĨŒN_ĶŠŠēĒ­úĒą:ĢĩzĢÚ3¸á ēÉ\šĢÉēŦ͚Ē)NĪz­Ųē­;ڎģ! ēā ĒĀ ^´ĸ!s“ĀJæā阡¤™EŖ]œ•–ĒĨAî:ą_” Ĩ¯ģÁą!{˛%›˛#ģą'ģ˛ Zŗ;ŗ-ŗ-ģą›´7Ûą1ĩ/;´O[´K{˛#;ą![ĩŖ!ļ?{´Cģŗs¯A;ąC›ŗ?›ļ-{¸ĨÁ°uĩ9{ĩoû¸Oˇ][š“ÛūŗŖûˇ{ģš™{šĄģēą[ēĩ{ēŸ›ģÛē/›˜Ē{ąÛˇˇ›ēÃ{Ŋŋ›Ŋ¯ÛģÅŧãģģíģŊåÛŊįžŗŋīģžũ;Ā|Ām› ˜!j[ąų›žû{ĀüÁ<Â|ÂßģÂ÷ÛÂŧŗ›ŧk›¸)üÂA\ŋE<ŋIüŋ!üÃGÜÄÁ›´ģĀ ´Ā ē ´` &:éQ1"÷ŠxT>ĸA Ė t€ ˜āŒÜ œ€ Šŧəüɝ<ĘĄ|ĘĨŧĘŠüĘ­<Ëą|ËĩŧËšüËŊ<ĖÁ˛\ĖŧČĢ Â@p`tÉÅ<ÎĮ\Îé|ÎíŧÎņüΏū\ÍQĀv`t@˜ŧȍŧĐķüĐõŅ=Ņ}ŅŊŅíÜĐ‹Ü ļā ÂĀ R€ T€ ũŅ=ŊĶAŨŅ}ČÍĢ`ĐĪ<ÔUũĶY}ÕĮü^Ā ũĒ@ žāÖ_ÆÉ@@)¤1Í„QäûI›ĩ6§Q„94ÔZ­ŨēŲũŲ—:#vÚ<ĀÚ­ũÚ˚øē)ļ°ŊÛŊũÛŊŨ3ē!˃Ĩ‰ÜŅũŲ‰†đZĶũŨąyŌ n= *ũ Z`ØĨ‘>~ŨńÔŧļČöÁŪ#gi—6áŸļfži^áÁĩ>ČdīÖA5Đ>ã!ūá^ã;žcb€2īūØEä>ū䡖ãSŪãW~ãY^å+–%ĘÃ\\žæQæ_>ãŲAå\OqUĀlžåo>įƒūbŖ,Ķĸa ´`ŽĢ@ÁknĮŅ…æ6Įĸ°žšČIŨBå¸ āĪÕŽbn]’$ė dė;Šė¯F:N*íŞíŅžė×î]LîÍ~ĢŪūėãīį^īë^í÷Ūîķđ˙Ūīû2ė^ÚĄÁ€ÛžîŨ>đ ŋņņųō ˙îŋō_ō/Ÿō9ŸņÃjôlG‘$ļßķ'ßô7õK˙ôY?õ[õ]?öaö5Ÿö-ßö3˙ö‰7î'âEuøÔ÷#_÷‰?÷øķ‘ų•ŋūų¯Æė˙bĻQë¤Hŋö­ŋø™ŋķ_˙ú“_ûeŸûŸ5,ū$` ¤A<ē.Iß”đŽĪr•ęãf_LâM^}°‰Ū-~õ ū „7° A‚˙&<(pĄC…#6”čđĄA‹)BdČq#FŒCrëÆíŸŋvíR9‘#ˎ-?jŒšr&Ė›/sÚÔéŲũ ´!ΝH{*•š´fĶ‹I™Ju:ę͌W=RŨj"ŧ0Ņ LIŗ,ÖĒgšĻĩŠV+[ĩnמMXT`ģnҌ.ŒË×lßŖYũ Üv0Oũúėļ,!Áuė~*ÔKš˛å˘3kŪĖ™3ŧūyáeķ‰ĐŸŋΨSĢ^úô^&Ũ$ēū׍‰2‚ūöÜwr÷?Ąūø?­{ŸIáÂ˙?>\9<ãÓ/Nü9séÖŠ;‡Žŧ:÷æĶģoŋîüxíáÁgŸûw÷&ÛũkwšžŋĐLŽK(Ÿû;éĘ÷q7`€ū˜  "( ‚2ĄƒBXĄ„RČ΁Æ5Øá„f˜’=3A똯oĄ‹ÂØ"{ĘøĄ5ŌhŽ;ęø?úäB ^ŽGö˜dKŲ$)n׹ũ&PŠ ƒž•[ĨyÆyy¤˜’I ™ĸ&˜\~Ų%›f*„ÍiūĀ#œuō1ųĸ‘{>égŸ€ÆČ§ čŒÁÁ“ĸ?Ų8öĪ3ōõ3“ąféĨ˜^úIųÔĐiŗe*ꨤÂÄ4+͏ ¨ęånjŌŦ˛ÖJë­ļæŠëŽēöĘ믞 ė°ÂKėŽŸÆú•QæyŦąĐ>+m´ÔNkmĩ˛õC;˙ų$Ÿiāš„íĩäŽknščžĢnēė‚ ąˇîŧíÖKīšyžÆÎ%šęŊö đŽ”"<ō­Ã§IŖCĨ¤F,1ĻīVYQ¨gŦąeūD›lZŠi—lōÉ(W†[œaœōË0Ŗ O78L̞1įŦķÎ<_–mūB§é€Ēģ=m´QĄ˛|ôŌL'ģÆđHÃÄMWČŽä˛Õ<›ÚęĶé†5Ō¯rmöŲžzŅÖhˇ]ōĖ/´pÁn×m7ĪeĪ*ôcBQ}÷ߘˇ×Ū€>jŌ E3ĩá]í4ã&ŸæąÅ7'D8ؐgžŗJckŠųįŠÍüpÖĨnúéY7¤›$­č7ęu—­4ė¨K>kWRŋNģ¨ĻZœléģķŪųíbũiŪÁ'ŋZī +:Ür+ËļķÔˇ +ąņV_õmË~9÷“\<Šë~g^|~k}ŦõDßĮ:ũúÕsūuåô.ēúĀįī˙ÎŽŅOļĄœŽũ¯iŽ‘ūĪģŒwĀŗŲjĩ1_)“>Ōál‚*^+ˆšŠ`PyĖ{ßŨŊĖíg#LaŠžö*˛øãy‡ uæ=ß́]I\$˜Â"í†Ęš\ķ,Į@qqwöâ™ļ? Ūn‰PĖLiLÃOŲĮB‰âɧ’øi1fÔKÔ÷ÅĢŅvOœ!oVŧ‘!¯ŒŒķ!ū⍺ž0t¤#nHæ“*Ę˃y<ÜøŧH”‰o/åƒcį–ÆųųOˆ™MĮ'?Ėl¨!YĖ"6ŽÄÉ,r“ž Œ’IRšŌ“˜$e(­ÄĘß ”Ēüä?6)KĄdq”Ĩle)CɎQ6ė¯DūíÚĄÁBæŦŠDãŋŒE•ˆ+Q˙ `ņČĖKIފsd51eĀ'.lŒ<!wA5Ķ„ tãE(_Ō’–Ÿl§ܙÉ] ÄĸÔË*¯4ĪvÂS“Ŧ <­$ĪO˛Ã–LåA[šIOŌŌ—Ļ4čBO|zĸÁ ÚNō¸mš œŠÔĻGÅI˛Ž!L4QĘčH…ųŠqŽ4c˛Š7ČøÅEvT¤ëƒ$ЂHI#^†¸¤ B úKXÎŌ”Ē&•ú|6õ¨ú„hChi€‡ 5ĄVzåD[ų`~˛ĄŠ„*'™E§fj8}éĨî2ĩ˛-S­=ŧ <<Đ/vŦ ŽĒšæėūđš)e6¤Š -ŖKgÕ?sŪīvUôĸø¨TŽēķJ XhPۙUĘ Ä—¸Ā<9ŲĪŽbr˛˜m§/7;KŠR”´˙ĀĨS ÚMŠ– Ŧ ¨Yo €ČēŌ˛ĸ´mjŖĘÕÎØ›Ō°K9ųZĒ܅ô‡ÄU#3q]ca§Y’IqŸ›™ÆĘØÜKZ1s3XĶŧŽķŒíõĸāPR–ļWr˛¨û›YyĸōĩJV2z;;ūåÆĸ{ļ °,šõŌØŽĸ6ĩRũv}Ķ›ÃáJÎSIkĮēąÎ]‡Ž9Pt nđā­Ų$éŠnžÃ Y,ĐÉUŸĶ¸Ņú(2O}Ģ 7ĢžįvŗzÂFŧOú#¨û(Χ~Aā|Ų[áJ‰?ôŅģÄ˄)I „ĸ@ŠŖæ¤)jT%[löäņņ4”„6q΁E„ą°íy¸>LS8Šä"ŋ!ZÁån°ĘîwgŸĪ8ÆøĀã[_™aÛü\6ųÆ˙æéŸĩ’ā"Ÿß“OdŠ,ėĒū’ĀC,ߚnoņÎųF-*īŦ§ø:FHƒÛîáš")žGá"fī ‡b6°(˘`œz^ƒx*GcdÜNģQŒ•.)ę›P†ôņcö=7æãhI>ÖŋäöO’(ŽŪĄöœųÕ˙-ųĮũœô8Ųëŗ~ú´ŸK€ĪeF…ōVö?ŲF1Pb'Dû! W V°cp ą…û°Įwl˙āzġv…{šĶ{/ŠbpyBˆWpÕ2¯’"ũ°ĸH(‚*5BŗąFˇN +G*Áƒ>øƒ@„B8„DxRbW„H˜„Jč@á-Dv>!Kˆ0D1„ūt> Vđ_ YĐN%qežĮxæLŋņ-ȃ‚fˆ@hÔSf×ø\Č{>Ĩ†{ĮrpÔuaWDÉ×bėĐ(ŨĐU@8 :Ā/°ˆaøL‰‹‰L0‰’H‰•ˆ‰–˜‰”¸‰ž¨‰ h(`d ‘˜ŸØ‰ ¨ŠŦx‰­Č‰Ž‹•hPŠ‘¨f a`ŠēH) ‹ŠČd“Č‹ŠX‰9ˆLahŠa°^Ā…^ €W` ‡‰á.Hm(E1Q•3GŨČ8Ŋ†5rĮWü<į8l-ôzÜ@‚åÚP:ËԎ 4mCĖ ŨđūŅ Ũ )9y ™ šؐyË‘ųY‘éé9‘‰y‘ š‘xq˙ø3# Ë ƒ) V \0]°U aŌį)ãh|¨“ ņrŠŗ“äØMãĆ#•/ŋ!*Ãz¯˛GŖá“~ąIŗGfâ¤6`C‘!2b÷Sø•`IMX…M–f‰„)TȄ>X–Jč–dá)=HŒą[`TP$É ;°ƒ&”ŽQ'Gå7F ˜ä=¨R‡ļ&´D"vŌox—]P ĖĨHÍV‡ô3ø<6*Ŗ+G6…iBŨÔ}™’EūôM\3ҤKĪĄ;ŨĮQ•xO”'wá5én /Ũx†I> ˆŋi85Č2Š™fHŲ>ĐwškČæ97 §H;˜ˆöû!\$mÁÕb*BbVĄ˜[ãHåéxA‰\éų‡vFfį‰]‹gyę9Ÿë㠁…-á č€ŲD˙Vœ ŗfČY† W:đ@%Á™õŲ : G Dîg3x@Iô@î2ËEÄGō(Ąj^5QEy <Šá™„wǍšĒĒēĒŦÚĒŽúǰ̞:Ģ­Z¤ĸé(-EkĨšĨƕ“l—¨vs¨‰Â„Ķdv2 𐧄eĻt;QSŖ5…5Ö&Ī =G„VŸ76ū˛­´Ú­Ūú­āŽâĘĒK™kĶz<đƒZ‚5q“ģˇ{Āj=ąĢMøtŖĮūŠ9øD2j‡z<‰“ŠK´Š&uzŊ÷¨äyW—ŗ­M Ĩ;ąJ*ąKąLzą›ąû¤NC5nä.a° {´Ą; =ŠĢˆ3¯fãLŲXZG|nZMÂņ*ĘÚMVŖ3­gæg"ãƒđí° *Ŗ(¨M̓S抔įĸ cm?úëąKĩkąW;ĩXkĩNŠBBĒ{†&â2ŗ!N[7cd˲S9é),Ōvāâ7ûCiHō ą˜šļõs*%š‹;đ$] eúwʲP0÷‚3 %ĨšLV´ ą¸Öē=ŗ2Qeú#’kDsF†Ģ( GečęūĒ‚€Tĩ[›ēZģē¨ËēYÛē­Ë’ĶûšX€YEš3Ĩ ĒļDmäãúŖ3§4öhvō*.ŧ5”Rˇ ”§M`K@ŅP>)v „x'å-v'ē}cw؇‘ĄŊÂ9ŽŅ•y’ŊFø§Ũ+ß{%¤…!Ph)Á› įĨĢ5ĮËģgØlģÁŧĐ埗k|üÛģ’3ؐKÆkRĄÛ2xįĀcKŖz‹|aPĖ€€H°Ĩ>q?Ā%Á €× ĐĐÁ03%Œ5Î`LP3´÷ëØđ(p§÷!<3Ę Ã€…*<Â%Ė'LÂ? Â>ŅÂ/ÜE2Ŧ%ū5|ÃQ¨Ã5Ķ =ė?ŦŸŠčŲđ*Pē5Kx.å9PY¤ŸUĀךŗŽÍú¯dl4|„y‘†ŧkĨ‘XX8ÁÛTƒŽbUSN° fĐ9菒’ ņ#…¸ČŠė+™=)鏁*ÜĨ7äĶ„H(93?áČĻ‘üšIÉ aɘ<3š<Ŋ>QzžLŅĪ*ŠĄĩg˛o<>J㸆93SƒĻIŸģ|4ĶĘ:đ`‚íМđƒŸzĖLkjDxA°×š§+× °ˆž ėpŊ)Av!ŋŠ"–ŗR–)Ū|RE¸caEŠBžüĄ*á ¸§a΅ˇūŊF¨”ė|"íw`!ēĪD{_cĒÅÜocņúĖĐĨưaĢ`SĐL“@†í0Ą%vŦx,—f 1#öĮ~f­‚0xÁ¨â‚J 2¨ĸNWŅ(âĮŸ"‡)2Qŧ¤/›wŌëŌÛųr,ũ.+0E |P4™ė0S‰ pvąŠÆL:7 WAxL ŅčãŦd€…]fŠēøéĐwöV^ §H=3§ā;ė‹ĀA7ŋ1'ÍīpQrĒ%¯ĻÚ7pm+¤D×Īôúđ#xmĒ%…E|ĐiˆC­)˙&žŠŠÕZēÁuÕčxŖŗŋâhŲū¤ŸVhp›ūģģc {>×D‚•pyf}ÎZušH+û qÄ'+)b­QbÛģ-›•[ŦžtŌ¸×ú¯Į-=ˇ ¯ž„"ũŊwR*=šmŧ]áŋu ˜Spā› Ũ4yÆ2ā ˇ„…ŨėiŨĮĶ1ÜPGH-ēUYRČŌ)b6]ĸ¸ĸ+ŸWß°rß-ßÉĮQ!‡0=Л_ŧŧ[Rô(sø›€Å ŧaȆ¨ß3’“Đ•JwwĄuŌÁDsļ˙°ƒ…$ĪĄ<(߀ŠGļãŨŦø-ŅÉĄôm%*Ŧa ú@ŖqúãƒĢģ<^q pŌ×ÕŦį)‰Ą•ūr]á›Ķ—Õt$ūŸ‰ũĀũ‡P<õØ7ö‘2žēoäS:Æ…¤ąąJ]ЈũõXYžĨüPëĐę IûËäî„–ŗ%ö-)}zK-čeæÚ™.8§z¤%ûĄ%\7¨Pząõ}éYMœ–îĐІ†Čéu$Î [=†b]Ė`ė)ė|Fnåēų˛˛~ž2ËTU’œe–ęĶZĨÕmˇ ĸ†{žŒ¤EC .v•ÜęâKj3Q!ą ĮŅîģâŅ(°°Œ/@?Ā8ā+Đæk—AžusŦ {˛@ąuÛyŋąŽ7Čbv+ë`ū$!ßnkīH2jšëĻCįPĒš4):Č^p›Ž–~đ6ŽČt’ÉĐp’'°>Ú$÷΁ōŅ„-¤číū2ŅYgüE.¤*ũ‚߇Ĩ:É(oîg}Š%0Ä˰2^ęɧˇš,ŅŌHēvōŗLƒk’ÂĘsŪ *ĮDá‡cģĖ,k˛§&AK[ūR>A"<žō€ũņ‘ķąņ3ō×ʘQ'ցō:;ØTÚ(§Įzt*܀ĨT ÁvfķézÔ=,7h|ĘįBî+ qË'EžÜāĄų”7“ņŧÛ2(ęqe÷Ë—ˆwõX_2.B\Oō ÁœÎ‰ā!6áåëūõ·˜Ī´đš…)yĸúá—áų‘É<}.ĸ zđ“ĪäŲ5I_Üvč´ŨXk*ûŠč8ķŲŨ ¯QDXīJt˛D=€öø˛ū>„ŖŽŦŋD$*ž;‰8yûûđŽô˙#ŽÖīübDhÂo†ĀėĀ8 ūYoĢĶ:ԆŪ]ôĸGŨL?:ũwƒ1›Ģûčū‡5ûÆđēŠ€÷ß?„ū&\ØĐáCˆ%N¤XŅâEŒ5näØŅ#‚ 9tƒˇĪŸÂvUŽdŲrĨÂáéVĐåMœ9uR<šP&7&6w%J’a2,Ú4gČĨ ™ÔtZÕęUĢQJš0ū*V°ao ÚPĄ?ĄbÕŽeģöŦAxqˇũ3™ļí]ą0SԊ×ī_…!“Vöīá‡[íFÜöĢŋƒ6ųÚm\Ų2KÅ ŋ^æ\U Aƒ^Ív&]ŦĖ=cļ yŽąiØaĘԑ4öm–ZcFëAˇÕĖŖE˙*XëTßĕŗ=Î5&ĶåŅ/’M{6štėØmž„÷_ģžë˛+ß×uōxôП%l8ũÎŖļE_ņqdĩé×įī2¸āūÆûŦ ƒ S/@/Û.0xøG!“žKđ˛Ųbĸiŋ ;Sí9xĸq/Ï2sĐĀÍ@ŒČ¸…XCÎD1Ō+>lņ6ę4;pFÃū’‰ģîū™‹ŽˇrÄ+0‘zPH ˇ[(˛n>D˛ĸ↓ņIáØņÉH*ŗDkÅõ˛ėŦÂ„J)ĒŊ4“#¨b‚‡ĩlØQČĘ3ÁZjËžâL=É<ÄĐK‡3J‰ŒŌÎ —RŅš”n$Ô¯öŽėŌĪE#HI<ā&5vʃSŌĸՏĶŧ$\ĘÁA‰ËųūÔĄM5ĩ?:%SôÕ°ÚiR(+ˤ•ÖŲāá!.tzÚsW CčP•؝ŪĘĶÉHû$ņĖ@c*R>fą3F¸–ÍļŠF+$ķ[Z jhBbgSr_ŠņÂv‰B ēÃ|ÕÕ×tĻV•7ēXģŌ÷_—îlu/Wá6sАā1ƒ¤wܔPፌ}[H)ņąĄ]TZEnąÚ1Ö86ƊDTՓ[ Wā„[ێטTP&͉eŽ&áÕYĨ9AŠĖ^Sá؁¤×ŧ=Ĩ„ŒÆögĶāÉ[‘ĄžÎÖpeŲj酚ŦÜg؟gCëčę¸Öhʂ¸éŧ{ÉæÔģÕæL&šíž.oŊGöˇo( 3žŸ,`Joė ĒŸÔ Æ7ņŋČí>\r Gŧ—âō ĮÜĪ9:ÜķĐßÛ*ĩÄKGnÕĄžü_Ō[ŋéuŲ-˛‰öÚ'į2õĪëÎŨ"vĶ ;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/getConnection.gif000066400000000000000000002406221447311732500304240ustar00rootroot00000000000000GIF89a¸¤÷- B B!9)J J%HB)RLRR!J)R!R%R)^Z!^%Z)c!Z!R!Z!Z)c)c)c)R1Z1c1c1n&y$lk1s 1p6{1{1†)‚/~9†9”) 6˜6Ļ9=!%J)J)!R!!R)R)R)!Z!!9!)B!)J!)R!)B!1J!1R!1R!9Z)c!Z)!c!!Z!)c!)Z!1Z!9c)!k!%c!1c!9q%&„!1k!9}!>6).B)1R))L)3R)9Z))Z)1f)-P1)Z1=c)9p*=bB=qoIZ††ZˆŒ\‘‘`i””k™™g–™sĸ oĨĨsĸ }ĒĒ|­­„ĩ­„ą˛†ĩĩŒĩĩ”ĩŊŊˇ‰ÆŊŒŊĩ”ŊŊ”ÆÆŒÆŊ”ŊŊœÆŊœŊƔŊÆœÆÆ”ÆÆœÆÆĨÆÎœĖ˟ÖԜŌŌŠÖÖ­ÖŪĨŪŪĨÖÎĩŪÖ­ÖŪ­ÚØˇŪŪ­ŪŪĩŪŪŊŪįĩįŪ­įį­įŪšûŪÎįįĩīįĩŪįŊįįŊīįŊįįÆīįÆįīĩëīšīīŊįīÆīīÆīûŊī÷ÆīīÎī÷Îī˙Î÷īŊ÷īÆ÷īÎ÷÷Ŋ÷÷Æ÷÷Î÷˙Ŋ÷˙Æ÷˙Î˙įÆ˙įÎ˙īÆ˙÷Æ˙˙Ŋ˙˙Æ˙Đá˙ŪÖ˙įÖ˙Ūâ˙įŪīįį˙įį˙īÎīīÖ÷īÖ˙īÖ÷īŪ˙īŪ˙īįįīī˙÷Îīīī÷įī÷īī˙Îī˙Öī˙Ūī˙įī˙īī÷ī÷˙Ö÷˙Ū÷˙į÷˙ī÷˙Ū˙˙į˙˙ī˙÷÷Ö˙÷Ö÷÷Ū˙÷Ū˙÷įį÷īī÷ī÷÷ī˙÷īį÷÷ī÷÷÷÷÷˙÷÷ī÷˙÷÷˙˙÷˙˙˙Î÷˙Ö˙˙Ö÷˙Ū˙˙Ū˙˙įī˙ī˙˙īį˙÷ī˙÷÷˙÷˙˙÷į˙˙ī˙˙÷˙˙˙˙˙,¸¤ū÷í[÷ĪŨģƒ˙üųû×Oa…#Bœø°ĸćũūûˇĪáŋwÜ6˛ķ×páģ}˙ôŠdĮōäHŠcœi‘Ļ˚8oę´šŖË}ė*Ž{÷oʍH“*åØŅdBv'–ĖɓĒ՝WĢbŨĒ•"; ,ŲŠÔˇ‘(É~KĶn”Z娰.šf+ˇnWēwíâEęOŸB…D ŧö¯ŋŽųôŠĶˇĪī^ŊķJ~<9rMÃ=žs—2čGĨ_Ûkܡ˛iʨ-ĢĩÃwboؑ ŅŽŠO¯ÎÍ{uāĻ€ŠÍ—Ų­?ÂÄöæéēšîįËįūüÔ!į û>hØqáčģÃūWøUĨIîūl#,ŦąbƎч.˙&ãÆcŨøMėáŽũpöÎBú ¸ßqdÔŅ€ûp–’gG)Ĩ7Ô~FyDT…æüAhÖH šDg.ÔāS šƒ‚=˜ĐŠ'ēUâ‚-x˜ƒ)U‰ Øc„ÔÕgë`§VZ(Ŋ¸ÖgįôĨg;>•Đ;dÁČ •+ú˜eT[Îᕠē(a—C^‰›™ Ūã‚dÕHfŒÎČŲ@aũcĪaŸ™åŅ’IŊö™_~¸QiˇĻŽŲ‰¸ˆfâ¤$Fę"BŽØ"nXbĒ"••žØ)Šf­č‰Âx'— ÎŠe•ūA‰å—_aƒ”g=At(Aewâ¤Ļ†:'Šv˛øŅ—ŋšŦĢ†YĨ—jžÉå˜0ųlĸ?˛yXĻndé‚õU`vPaxÔRåísގÃĘXåŠ&ļĢlĢ0ž:īFĻ æģBk-šÔfË(ˇû•(iŠRēs`ņy&Íļør”ŪGžĘËĒ•õ6˯ƒų~Éč´ŨVĢ-Ā!7š#ŠĄÜc°›ļ[įģ¨:•¯ m§§ 6n„Â~%)ĸą‘Ž ,¨›ļ˜%ŧ^ sËĒēËōą{*ŗd9ÛeĮŅ2¸PhÔŠãgîR(ngP¯*uuúVŊqÄ,fȝūËcĀ‹žI0ūˆåuœ‡^ˇĄŸĘJž“öjˤū ¯ÁB¯L´‚.—:yÛ1Ū;uÆnßëccFæ§Ī9ät_“˙öÛgAÕē‡Ŧˇ؆)՞ mžiļai z-{ęĮîēđ°’ę"õ™ņËŋūúđÃ3<ėҎÆRFĒ”@™m= Yë€H˜ķÄ/<ķēũųė/OũûęûúŌ˙~BꈤP‚ēŽŊRšáKĪ6âģú„~Đ+^ûĻŋø™īĢK`ˇĀäI°|ČkEr@Ôe*9cž”™ %€\í7ÁŽPƒ)œŸŨ×Â÷Ŋđ$ß )Ö$Ú°D]ū÷šHYĐ„ÄP‡<ßübxÃ.Q†I¤a?ĶÄā]ЊōSāQv#‚@j6STaĨxD*ŽŅ‰5ĖŨ[÷Bô•QŒIšÍCNȒ •…#āûLOŪÃ5Ǝ…mųĮÆAÖĪ.<#uhŊp‰D]û°ĮJ°Į”ã)Q‘|Ŗ!+ˆHb%šĖŨQ¤RÂŋ /H 6tˇĄ4šq‡Ą¤ā ;ųē*f’–w$Œ~ö‘˜u16ų!š€ ÅjfÄüJ1ëØ’cj&?)ÍİC˜™C"%Š2iĖãm“\Æė&7™é’dzČHœ™2‹¸Ípjsœådg<Ģ͐†ÍVųūû …ūFÜTÄtã‹U<“9Ėo.Ķ™äJčAÅéN˛œĖtč;ĪŅė Ķ íl&8I’+”#—Ÿá'?b–r芪§2gDŊŠĐqjŗĄ*gFáÉN‰4ĸ1-ĸNaŖN–&sž>Ũ&Aڒ–S833Š­ŒĸIĸnœá+‰ T—æT›ĨéD{ēSœr™EkKjTØ ÕĨAÍ*CŊĘ͝ĨHa‚t…[ąĢ*uĻU{:SwĘÔĻ]ÕęMšzV˛Ŗ *`ÕQĪč{,ʆŧ¨SąæõĻc­lZ͊ؕ–­ą‹1-ŠQĩnuąŪä*šúvĨā]ķoMrūĘ?ōwÕ6s̆Ũ&XĩzÎÍĸõŗ‰ŨĢLMkSrjvĩ~}I=Ĩ¤/ÎĻ1æPIQzuŧė§›-M,pW*܇ĩ¸¨EŽq [T,Ąô„JŸ(DW‚|ƒ¤œÍĢ_kzÕÁΗŧäÍl~ÚY„ž5¸$…XŪ‘*Ũą„ō …Ėā;%J‚°[ˆCœ8/\íđ‡:ԑĻ,¸Á ~°ˆAėÁ{ØÄ=ąŠ|R0ŌŽ#D)T8väE=ņŠwâķøĮ=Ną}ÜÃŗl8=ĸ]d˙w¸bXÃFË.uLd [šĘXž˛–ŗä;ú/b ‘Ž“tĩ™>÷Ã[N3ū—ÕĖæ5ģŲÁ/V g2bPϞO|ŗžÛĖį=ûyĨķ‹aŧæ |ÍNt›Q|b3ÚĪģė‹:rŽwd¨„ū É­ôIâ>{ZŅ æņ˜)ųbHę#dSK‚ŠęVzÁq vúŨ}ŌÕ ffõĢ]Ík Ō‘ YĨf¸•ŠjĻØÅ6k|…Ŗld3[Ųņ%öāÖąŋs-d•˙øF5ŸÍmm>ÛŲÍîv¸ÃíífrÖÛâ†6ēÁ îƒh;,,‘j1`§ƒą0Bą‰Íîoû›Ųũwģ×ũī€/›Ũåæi|“đdãŲ„Ii ˙ˇ?[˙ÛÚÆsē^đs\ā'8ČūĮũņ†‹Ûä#/šąY)Ճ<ŒONĒĢî¤}ėšŧã)9Ę>r”Ģŧį5ßyČSîîš[ۂQÔR8c Í ]Ũ8įšĐIŽķ¨ŨęTzÎĩnr¸Xú/œY%PĐÁs¨g}ęįúĐģ~î…ŖÛėRĮēÔ­8ķÂĄŽ0ëˆ;hžđĩËũä‡:Ú¯vÁãüTõ~8Ü@cØ+ŋëĐĪø¸ŪōƒÎģaÍ}ŋëHĖcŽ3Ũa#Ųf˙šĪĢŽuÕžõ̟*„Íú mxãĮ=7žáŨoãöĀįŊđƒOüáŋøßHž7–ŋüäķ^ÚĻķRoXƒÛ°Æ6ŽūĪũâ{ŋûā˙žøÃOūņŸųÛH˙6ŽŅyė°C#´ˇ­CŊãxīæ/ŋūķĪ˙ũûŋ˙ŪĮ Õ° Ø'€RURĄüäų €đU ˜}Û€˙Wx˜H|įĮ|ÂĮ ÖĐÚ°§;Úˇo직*¸+؂,¸Üp{Ûˇ{4ø|ˇ0QÖ××į‚>ø‚?„/‚!ø^Ķa ׀ׄN(„Pø„ˇį|Sč|ÛĮ{ŪĐ 7*Bԃ͆Q8†RH†č§~ė×yM—+qß@€;ƒX(†eX‡dØ}Ū ~Ø~ÖĀ’#q”„¸w)h‡†x‡ū¸|Ø~Ûˇ ^ā G0bPG@˜x‰˜¸‰œØ‰žø‰(J°‰U°T€e@°Wđ^…gÜpŠfGpGP ˜‹ē¸‹ŧ؋žø‹˜XUSPŒG`e€fĀ~)q.ō;QKph KŒØ˜Ú¸Üg0p˜x€ģĶa"EJwÄßpŠg U`‹Üō8ôX ¨‰e0K0j° ądq f I`B`×h š Š—¨‰Ķ8”(‘^ HgņÛ`J BŠ ’"9’Ŋ8T`‘AQ6)&  I’0ū“ņxK C`bāfĐ­Xjeą!ŌĀf2Y”F ŠÂHŒÆˆŒT`Ü sÛ C Lɉ¸x”Zé‹Sp^ų•GfЇ`YDa j`‘xDš•nɍUā•R0SP3°č@ÄĀ ãĘáĀ ~ ˜„Y˜†y˜ˆ™˜Ī €Š ŽŠ ō° ã  Ä čc^ļweĐ Í0|™˜ šĸ9šĪĨiš¨‰š§9šŦ‰˜}Ų—á0˛i eP.g"õTeÁT` ÍКĀœÂ9œ€Yš§iœÅ™šÃŠ ãĀ™T€cö$Ī8>Ü œé™Ä™ÚūšÜŲÂɘ€Ų—ɜã@ G@lKÂb` ˛āéđŸō9Ÿ ų—âY˜Ä` –ų<`´ܰ™íIŸ: :œã@bĐán˙ɗZ šĮ™šČМôų ĢI˜‹YšĖĀ Fp į ÆK` ‚Ą(šĸĀųšá9›ĩiA GĐĄ÷ ›îŠĸ8Jœō0;˜Ė@Æ@čšKĄžÆ@<šŖJJŸ,ÚœÆ ÷€R áŊđđ YŠĨĪđ ^ú ¸đĨaęĨc ĻbzĻdúĨŋ@ ŋ˛ ōĀ ŧpĨpē P÷Đ'į´2ʗō` XÚ i:¨ūfJ¨ez¨hZ¨Šz¨đ`¨‰Š¨ŽŠ‹úĨšPŠš •ÍIžĪņá!U°—U Š“*ŠĻšĒēǍĘǧúĒǚĻVšĨ;Ę RĀ væ…268t 3ĘŖ€jĨ­:Ŧ°ęĒąZŦÄzŦĘjŦˊǏ€ š€Ĩ[ĒĨ~)Öā$qĻ÷`ÄāžŌšŦ͊ŦâēŦāZŽãŽĘÚ¨ZĒĨ[ú Ĩ) FcëáX|J‚™Ĩ蚝æJŽįē¯úŠŦa:ϛϏ;*ÄV:¸WéžĪû¯ë¯Û¯^zĨîú ‚ęĨYA€™‡ō“3›Íđ°ËĒ[¨kĻkūą-û˛”jИš šj ĩÉĢr Rđ—\ĘŽđ Κ˛ ŗC{˛^Zа´ņąé™B@^6ÚĘ­ŪÚ¨E{ĩ.k´YËą?š Ė@ 2 ä0ĨZ*Ģ? Ļ+­>ģĨl+­nËĨpëŗ¸Đ ōđ§áPō°˜¯vFEėāĢ÷ēąq[¸m{¸s›¸oģ¸r ˇë¸ˆË¸†Ģ¸ÛĻΊĨšÄPDtöVŖė0ÆĀŗ;š’š§Ģē¨ģē”Û睛ē¯ËŽ뎁y8öˇĪR@!¸UÚĨmĘēÂ;ģÄ+ģÆëēĮ ģÛŧˋŧ¸p h ­đ  Rĸūøx9  ĪĐ WŠŧāĢŧÅžÍ+žĖ;žæKžŽûŦmZŠĘžĪ R@Mą/Â֐Ü+¨åÛŋčëŋįĀę+Āéˇ~)¤ėpqÜ Įpš Ā<Á,šüŋßÚžpû @Ë´ã`u$zdLzYĨ,ÁŒÂ*ŒÁrËŽ.œ¸–ģļ™ģš;Â:kš@ŊˇÂ,|Â=ĖÒkšmÚąôĀ įŲŠĘ180ĻŊûûŊ@ėÃ˛ûÂ+|ÁįĢąîK™c;ēÂĐĨc­i{š>ģŽûÂ-<ÆŌZ ˜°P D@˜Ė`͐ø;ã ĨcęļdLÆĶjÆq+Æūzü¸|ƋģĮ‚Ȉėļd°3<_!(Ÿë`1ēŨúĮˆ<ȗ|ȆlɛLȝ\ȌKșlÉžĀąĪ0S€cK2–#Ö`ĮxüĨŸĖÉ~ėÉĩüļŗÜĮŖŦ˛ĖË~ėˉ ČŊ,Ėđ€ ĨĖÁø*ŊÔģ RDĄč Áp Ū뎡ĖŖlËģLĖØœË܌ÉŪœÍ¸|Í} ´2lĩė{ Ä0č0!ąuÛ ŋ]ę Û,Îe\ĪáœĪäü͚ŧĪõĖŧĪ  U@l~RĐĨjĪĀ ÎūŦĪøüˉŧĐũüΘûŗ&ܨ•ę™K;4æ'@qÆ`š×ĖĐØĀÃŦĐüLūËČbŧɋ ĻüȂãŸTPĨüŊ/-Ņ*}ŌÍĶ ũĶjĒą´:Gwv(ä0Ķ\ÍŗLŌ>mĪÄÜĶŋœŌÚLƂzšá 2đU0 ĘШ\ēˇ{[ĖŽkÁf šXZ°°đ ô  ÂĮ° §L K€+ē’ûāĢãāĩ­ĮeŨļ§û×eØg=؆M؀Öh­ļAĶMA¤ 8N&3SĐ­kk؉Øą[ؚŊŲ„ũŲ‡Ų‚Öˇ€ ° Š¸ģAW2ŒĄ×jĖžĸ­Øŗ=Úļ]Û´ÛƒŨŲŧڅëŲŋ-­•ęŽZē´›šĖ#GtÚfڙū-Ũ¸ ܜ]Ũˇ ܝ}Ũģ=Ø‹Ą{[ĒĢ ÃPĨædũ ‘ú ´žāÅēŨÜ}ØŊŨŨÔMßđũۈ-ÜíÅŅęŪLģ¸Ē’tÜ`k°Ø ÚÛ­ā ŽŨžũāĶ-߂Íĩō°ĨW͘ÍpžJÆ?—]}Ņö]؏Ëß?ģß-áõ}ßÁß+âŒũŦŽũá Y@ ōPŠėgëß-žā=ŪāņÍ✍ĻYŠÚĒüeģŖ­ÚË).â?âN>ß*äŌzÕŅĒš2p]ũÕdÍ´c Ö"žŨ‰ ´´Pá~\PĮ@ã eĐ&¸A|z{´aęÅC<åbŽâū æCÜĻÎįS>ˇŒÍÁXîh›€âúQ[ķÜŌ;č-îä+îã{ŽĨčØMĻiLÔ¸Š…3qü4fũ0įu wžįPnŨ—.ä ]éžũęÖëš ØĨyˇx­Ä ÜŊ;ųāÜÄđ æœ Ŧîãąžė˛Ūäømé‚Né´ūļßŊ˜c ´]ŪF¸ĸ‘U0æŧŗî îėã.î­>éĘ^â'îŪ$TĐæqŪ 0íÅä~î÷~ßųŽé~ÎīœūėéNŠđŦĀ[°áĐ UāĘąGDŅ+QŲ\ë”Îîú]Ņû.éŅŽīüN߅>Ã2€čŸņ†5ūŗŅJūí"mîđč>鷎ōŊĻ`MŗáĘ$ÂÜÁ€Âæ æéžō¯)¯į(˙ļ^š´Ķ+ļé]ŲxĻ.\¨ŗ Ö8 ôÁûį]Ēég õđ@ąš jū Įp ´éÔôÛ0éĩkÍXīįU¯Ž`=õVOõoõŗšéûöęšé¨üõU÷yoõRĨá0 Y€§&ꊞ9xNėĄÅđ ™ū÷‚čtßĻ~Ÿénoųũõŋų`õžŋ÷–o÷ųĄß÷ßzĨ¸9ÛPķÔĘ'ag§Rögoėœ?Ä{֔ßö¨īû“Oõr¯ųĸŋņwú€ŋû|čŋū螟üÖlüǟúÎ?ÄĨ‰āu ­Į0Mg–7ĪS0 îiėÂ_ũp_ü ŋöé_ųëßûQŋüĀõŧūqīūË˙ūũūüö˙ž^ ĪāÁ{ö Ž_áˆMyįĪážûöŊûįīˇãâåē…k`/xŋ>)˛ ɓ!GŠ„RĨI–%˛“`ɛ$[ę ™ō×L•;Uē¤ĻJŸ=ƒÖä‰ĶhPxĘĒxc'ņßģoŪĻ<ķ˜Ë(ПO‰æ<účN›'ˊÛ3&ؑfqƜĢ6§Yą:íÎüe0—א}=†kFeŊúü]ĨØĪŸ>tUˆ[ú¯ÍąvŸÚ|‰ō˛ÎĖūNÃĘĖ‹§Ī¤hõžíüĖĩĶpÃ˛ Ķ—¯ßŋŠīŦey– W+‘šÂ…›š×æč•žIc^mZ'rÕÎ× }ËÚŠKUÆ 7Å:܈Ãã~Ėnʰpđ|WÚÜēRæŌ•+m˙õ}ŅÖÕy2ĨîiHXráŽúŲ§Š`¸Âå–n2č8¨‚+ģÎ‰–dĄįe Gžá†Ą‚Ü&š¨"vļYyäÉŽŠŸN›K5äØúė.ĄÜꌮí˛ą=uüŅ5ú”!†Ú[ 7&›t’ŧ!‚ČĄĖ\r‰Q>‹ĒĢÁ¤ļė´åęl,ėkÍ5›M iqœūƒˆ"ˆH|rO&I<ҟWlņÅĘx”Hų\ĸΤ8Ī4ŗÁĖ,û˛>œ`L*Í}ė/ÍąØz&=¯~a\žņŽĸˆÆ#/2ôäŠå9!cÕ4´įėÂtÂJɜ4VūÆĨ\õ 6š sÍŪJ…‚ˆ9‚‡üą ĸÜŧŠ‚™<šôĮaĄ‹ËWíĪ×ėXJ)Ņŧ %6\cŖÃtŗÎ™ę}Øy+­NėWūøĢ°Ņ1ũëO;‚%ØËĪčęËM6Ũ2րÉ-I°ŋB é xÂa† oÛgÉĢūQltĻ &c}œāŽđ_‚W&M;FĩŖĐ\÷Đĩ™f QŌļ ~ūm.n #‘TLąÜļŲę Œ+,7ēvûuaumíŒFM-¤™,`ũ°¸›b=ém1"#Fy´Ü/]ve…ÕęIk:WQFÍm0ožõ‚*č] úk@59-{axj‘g Wĩs<W!oœ+x'Øņy‘G™"”.œ`Ļ`GŸĪŪϊqŧ:Ģ)7 Š–ŊŸĄ=ķäé08‡\ž_zžrjyõÜ 7‰WyõBË)•­O#ia…ǍŠ<ųôžZŠšB˜préÂđaü¯Å%üq€™ Ëķđw“Wĩikū1Č8Ēp˜%QË{”āUV×:‚ŧ },;ŪGrŅA˝(•̐ķ4œČŅĸAã\īt<[`Į#˛Ā]-fĸģč9îy$$ˆ<¨§;¤‚„"ąKt8[4އcÉã\ĸ%áL IU÷ęu„“ Ä|<ß/|ø¸ā$‰ícŲ’^ŧJBĸôlWĄæĪr‹\ī´#XTą•˜ŋ=ūn‡;МHn'Ŋĩ)8 1´ˇ$Ũé"THĪšģW%p ÔS"#GÃ1 åiūsŖųŪČNfPrēëā94fŽzŲ‰#" š°_¸í’[SĮÄs¯mPRƒčū[Ąãz RF/‡5”#Ŋ˜Æļ9NŽ”s‰C˛p• ãgō>ã}Tˆ<w7@Mb)¯üū‰BdP/É$‹q^ŒņtxM‚Ntĸ.‚™Ģ÷ !Jīƒ;áEÂaYyč‚GhĒŦB‘I–o'û‚ÕKfT‹ŒV·seĨ˙uÖZ$ŅŽšŖcåRqVāaÉ%ȌËIĐßr†asÖöčÕŊ >Š‚å_zxōÜŋÁãZ*<–*šŠ4C?Ę!Hֈ]Yär'6ôâm5G˖āQ›œėßũ6ÎķyĨ&á€g”’ģ'?æoĖ#¨˙ŠčÃ| q…oŲČ×Ļ:ÅĢ|ˊčĀbūzœĄ“ čl_‡gJ0ö$§ũh&ĢYŨųĨ1ƒ<^_¸šĸ4/s…ßYŅÛãÍiōM›HEĸg1I‚š×7Zú_o C´cĒ•ˆŨfĻ׈đ¸Š{›AÍ š L%Ĩ„“ø*~t~-z&ü2—ƉÆEŦŅ۟ucz0H‡„žß;Øá2¤įf‘†ôãV9JĶ)ØmÅ3H\Q˙iÎ~‡•Ū5M]Hí°ąÍĘŖ.TčŧLļČq´`ęūØH=^įÕą}õss´sæ’ž{’E"B/tP!‹9ūoZ=-ä#:¯“jvo!ėÛžĻĻ&ĐxŠĸÜPjZ6Ų%ļ`­Kh¸žM:1“Öåáã*—ûåđElĒJxûŸg,Ō}Ri # WĖ"BX˛¸úOj\…-@0PfĸínQN{(ēc<ƒÁĐ:"¨_3#.x\Ŋ§K*Lč!qˆ,¸‹L G™âzPD2áĐã­"…`ácåa:ÄA†\sŖŲÜž"žR¸üŅDv_>é÷!G ß0ģū:Ür*yÄ"‹!y„U$˜&PüËąŽb=0!nÜĨbēvÕA!‡>€›ÄØÍ¤@páZY‚úôķÃŌ¤ÅSAĐĮĶķ,•{Ņ ]žp2­M?$(îˆ<ˆ'ģÆ!~‘ Z°‘qđx„Ū`‡Ā7ĄõSb[AĄˆķ‚Gˆ;¸ƒZ=§<ˆ5KÂģH€‡L8ŋôÃ!“…$ZP„PĒõp‘Ģ e(fŖ–Åđv¨1-?čjššÕË>āŗ&Š+P„PƒHp„ĸŊĖY°Hˆŧ;@…p’œ…š<@úûÁIˆPpn‚ã‰Nxƒ7ˆƒIpū2Į…H°!As& ĨDR5!.ía’Hšˆ‹Č4īĶ Ķģ18˛Yȃ>˜LxJEāĻ(Œʑ‡J°ŋ<Ȱ„ͤkëĒČH¨…QšŅ–‘ …<ȃ;¨7+ɁČ@lĢ4T„V˜ÉÆqI8 ƒ=4/6 ‰;ÆM‚PhܛD(ĖēEĢģŠ,ōIœā›û1ˆ=8(ģpœĀÅDŗ˙‰p€Äō␇c,€–Ô铀CœŅzH Ę=RÂĘLˆyP„A‚r@č:ūĮÉ=ĀH(„ĮĄĶ\„A žHhMy€@°DD€‡ē­˙3/Įá„W…T KčPĀĀEȝJŸrS)0ŽË>'YŽzj.NC3ƒxL8ËZčJ­xĀ„A@…WŠ„Ũ<@>žTpE€Y@…Ü„ĮąƒHÚ[x„Ā„Q˜ƒĮY„GØĪT°Äō\„J`(LPH€„;úŦ…H ĪLØÅg°P„÷‰„ø$&h1Šō ú‚ąˆ 1{9KŗTĖGxžL ú‹OLāOú´M@€‡APĶ\=Lp„g Ī\đ„]”S:x#ŠŖ=T PX„ĀkŅIėT@€„Į™ĶG°„;Ȅ5ēOĻú?'LFU1ŌtN[Ā$u„<¨CRč㠇Z€„Ü‹­T*Ķâ˛ųé áX=I•Ô)ŗ%@™6|N퐰ô8ąįdSTH…Â=DŅâÔB;ĻŸĖ@˜¨E|WÁÃD„úūÜŅ„˃1ĸ7"y@I¤WqŊTûÄģAˆbũŊL„ŸŦDNxĀšLÅJ* Å*a‡¸ŅPĖGāRh„bÅŊA˜D@@ĪH¸ƒQPXķŦ…U¨ĪĮ…>H…\ ×Sčķ‘@øô,Ī?ˆIˆFÜSÎĖALĀ„:Õâ1Ō"Äd(|}ĶߓSGĀW]QĮŅÂZĸ•„ßQK1¤Ö‘Ž 5C<6iÔ%#܀ĭˆP€H7vŗŽņ3Xy(€ŋø+§´Šœ€(;ÄÔĮ’#¸ĸ¨’Ėtã2΀V7ų”~‹ą ؁3ĒŖjÃū$­PaÅA>¨D>°Äg°Ķ$Ĩ΃}TPÕK>¨ëĸƒsŗÄNP„ÜƒĀ­ŊJGĐAÜ+Ž…>˜G°ƒ]…g˜SKŦOX¸C´đ āa”pP91›CABĮHû…:ŧĨöS]Ük]WĄ×å¤OLMÔGHIHˆĪLp„ß9ĻLŨEWIU| [€‰MÉE„HĐßKˇNČY‡ÚTI(̧ƒ >"†Šŗ'šŦŗēÆÁēm‘ SxÜ÷Ą€š¨ƒrĘĄ‡ĮŨ=ˆJ7fĐvXÜĐũÂ4Ņę/7„Ёāƒ$õ¸Hƒ?MU€„Qˆƒx€„EØGĀūŲHāƒQøSøƒƒēŌQˆŲ8°…EȃLX…H8LxƒE([`ÍH¨ƒYČ?PF…K˜H`MP<Ā: … â ė!†Î ĩN1c’†ԃÛĮ҃t[aPÍMFđ>¸„:X…QƒLĀUČß6Ŋ8Đ;ĐU°UĐäQH„pˆ‡Q¨Í9ČM=ȄWˆY8V8 ĶUȄ<؄9…Tčy„LĀ„8ˆ„HPDđ„<ßsĸTŧPŽeļË$d1Û>æ/ėeC–ÉģY>Đ<(P€ƒ9^M¨ƒÛԄLHSˆF¸=(,]ãRĀSū…A°…p°[Sh(z‡A¸yzy^ãU(7håKČd_ū…„ädM­Ōƒ9Đ9¸<€Whpˆ„>įR`ÍJāHЃH¨„áËAO€Ų: Ū;¸:Pøƒž9ŽxĐ–H"Ž]9=ąĸ„9đ›>éCA0ĄyĐr…„C¸hW†„QžåLX„]c•Hé7ĩ/îß>°ÕŸž…RЃVÆdsé+éK¸gK˜gqÖFk9îƒKČM˜ƒRØ8(…QÖ7đƒE°WČ1–‡„ŽUU¸ƒM¸äHˆGX„DėûAœpÎģVūí¸3ҏõ0íØE‚zŸQ(„V ‡M†9ˆMčx^=Mđâ:(…+u„Ūd([ȅQāKƒVˆ„9ˆ<ˆh9…įĻgÂÖMpi€•â6ĀL¸ä2NfP€å>fŋ„7pl;ĐįH°ƒīöb:H…Jë@ŧf†5Õ ëë“KË´wãf‚1GĐd΃”–ƒMæƒRhyp<ønōĖl,>īdžŌYCđhÄū6ę–WĀí6 kRØmM¸W¨8ˆ„C€zƒŽ3¨BPĮņį˙Nhz ‡ęĻ„qNg—įR¨Wđ8¨Ŧmfō˟ŨJoŒÎŽGYūzĄ:įâī@h[@hW ‡„—z¨ōosázHč@†ŋōyØō/o„Ļ2\Î 4!폨*\.‡¨r.¨oÛhʇƒJč:§‡tû6o+:HĢ~›HĪCĐzßũÎyāƒÛŠ(Oøt^nåänM(>đ’öįDĀ9ˆc…^MXz0„šîp0[åb77Āž‰)“NęD.ëÄN+yrō=yˆ~îg.ŋ9đ<?0h&V{z€FČĩįE‡­îƒR‡Ōdbp‡{ÆíDhū[hS†ĒE@pyPGЃ: æpČ_QØgb{WĀÔ\ ‡>p8x-:Ļ \¸oû˛fyäéYe ’ŖAĻā5ŧg(Qūj /^.xŋT‹Ž ˇw˙ūíķįīŸNžčŽ 'ķčĘ_+Y.ĩ%/œōf­šc\$HŽđČÃŗJĪ8m"]˛8h”c‰#ŪŠTpŊĀŽ0QėÃÎEåŌč5­T€<1ÉSK°ŦĨÛ šQnŪ0O°Į@8ÄŗW.Ŋd /Ĝq P<ū5ˇĶ;˙ čĢ#ůJŧņN-ƒ’7U•˛J"ô4x ”‰dļŠß$}ˆ’"ap É<ƒ8õĘSŪ H Ŗāƒ<Ū2˛ADâ[ôƒŠzã°~)Ĩ8TXô–“ĩ r0kĶŠOöqa…_L1ŌJēã4Ū`ĸ´“Z‘>lÂŽ€DxÜx€Å ôY€ŽU3>h¯qQ”<˛•‰°Æ üČfÄsŸúČcƒá%ž˛—UpįH(‰‰č~qS1§ƒfä >”!Ņu'DáJA@[üōČ\$ūP “€Â›(`XÃHÜq‹ˆ! @äâ´ū[Ęà q‡Ŋ¨"#‘ā–%ü§Š>ôôxÜa ŧĸ¯ČH“ =˛dļ€ƒ+äFY  ~āņŸ' a h9âŗˆ„#ü@Ā’U7:aKž¤"˛Bė%uČâwŧ(X™<“9ė°^Žvę*Ö`•gĨāŅPôBđ¨T8F%zŦŠ$s„ .bb˜øƒ÷‘‰Z VŠōžˆJ0ôĢ-ú@Lب›ÖŲ#h— 8"ârEČ‘ˋŠë/#ÅÛ!æ8ģŪv ›(éŨl”Ė1žĒ9ūJĀØą5•’ˇWå‡80Žy˜ë”ņ(€Sč€Y̝Į¯Ōqôęv ˆū|Õ€yäĘĶĄ]`ôÂZ<Ŗ š•zÁąģz˜×\â ĀDPPųkVŽČŽjE§I)*a]‰Q ęd9Īą‚tÆ•āB‚aC‰ ę×躊‘xÅ ádCH”â>}8ĖÁ#ž#īuÆ]æl<ãYĶÉÆ[mėšn§nGÉ(äū08ŧŌqh"3ˆM3ˆEh‹ōô!‘ÃŪđŒQ‚iĩˆƒ÷š—’bCĖÃ1YdëxĐÄmbˆUŧárx…LÉĩÁrЏf‰ų:ŒBåĻ7Ūwˆ§Đãé‡,ä.‡ÅŸÄ‹ŋÔdRr”Ü$'Ԍ35‡ŌĒlëôˇ+<Ž/ éS†X})r/ŅÛģMāi‚cŗÕ!/}€|F‘ ŗÁ–XDÍ=ęõ÷Aį3›Ŧ‚iBWÁ œIhUĨäÂ^DÅāÛ”Ė+ +˜Ûø•‚ ¤‹)¨Å×Ĩ”×0 vJqGrhOū8Į„ Ø)V3ņFdB8ØÂwôœ؁´"pŪ+Ŧ`‹øÕ(¸HƒĀ‡xÛ,`^ė‘É-õY$(B Lß`1i@ą Xēüšúŧė¤ †‹ū8dØŽ €E…<ė‡š8€ą@RRŸņBŽÄku†Œ‚,îÉšŪD˛ĸĐÃ(´^´BÆО-p]ĘũåÂČlČ Â-ŊRæÕŪüA×a^’"āB FEØö\‡Jđ$›Ži‘œ&´XŖ5ĒĻlT =Ŧ×mĒĪ8čĻŗė&ņ|‹f`Më¸ÔŠ‘ š}Đ;„Đ•É-L×/ĐT\įˇd§¸Œƒ{ņZ†Mé¯ôÚļ!SÃgqŦrLtü‚ŒéK’v‘<Ä’S~Ö¨kļæ|Úg}Ōįœ>Å>ĩŠâfnžŠƒŽ(Ĩ&íoŪNēpg8\į–v‡¤ÂJ0`21Ÿ›EôŠ5•PqŽívȃ,äė–JmvFiļ>Kj “‚čņtjo:ūhĨ‚Š<˜)„’‹oJĒ{ލŨâfÔZė^DĐįŦDN=ƒĢNŦqfuÚHXÕ‚y‹=)Ģ°Đ 2ŒÃ¨Oąņ|.ĩĐJ­ŒC=ƒ @7][JLEĪL%Į^‚eo\ãÜ žÛŽė.āKīKîJËēčŽđöî4›´¸#° ‹´Ëī K°-¯ŦHo‚ŲX‰ÍDqX?é€ čNøCĮMÁĮša*ČCųÂÃē īPī°đ.ō./ņīŽŧËüBoņ&/ōNãņænūūnüÂīíŪn-j“ĩ¨ŧJO÷ž]fÆĄõ´QģjuāoķîŠS°?īņJËú oû^.ūūūoņōnîîīũŽËķĀéj0î./ûúî ŸŽŽä‹ņ!_ģŌ„Mā„œ}í/Ō™ŽŧQĘ ßŽķ 1õ~î_đ¯ōFođö/ŋ¯Û/đv°O1'qëî­ĖĘíΊ=zQNĩkŸ’`ՔQMĨ`v­`Ž[ãKúNīcđķōī˙ŌąK°īē°˙*ņĶ1 ķîî˛/ß =x“ŗ‰Ė!É­ pođížnûĘ _n{0&1›0?ō@ “r(cō°HōģPō­ōúĖJ ‡˛°Ä0žėEųž¯§ôK#ąÄ.•ĘŠ|o E0B'ūÂū^@°Û)›šK=`˜€ Dĩ€-$‹—ŠÃ+Ô ą 8Đ/ˇn ĘBą˜Ģ@Ø}mãŦtŽšĀKŊtŖ´PXxl¯ƒdLoRŠ=Ãŋ\ÜOŧXŒ)L3}Ęėp&˛ đ°üú¯%ã‹;/ƒpÃoÃņîâ˛ųōčt ›ÁĄÕôD‘î0’ūd 9…Äž.žH/{0Īqëąqgđg´˙jtÛĘ(cXv𨠉éŧZę8.wZ‹)GËė:įĮŊÕĻQ‚ļåõ]īĩØË č…Ēžĩ]÷íÅ]Īĩf§¨ Ę$ -_ÍjŲ vęÄsŦ‚jžâĩk;6c3vÆölĮvp¸5n—*]īõėäŠ e6fįgf?LŽÕļŧ~“ Š0VØĸD’ú0ŽÜH7¤ļÁĩ\Ã5p3`pãõc{7dŋļ÷0ā^“ˇxˇõĨžDz“ ŒžēŠĩõéŸ.§Ā jĄ6ō yOq_x÷7o|wáfˇČõRԚ-f_Šf6'xvģõf¯ˇ ~ölK÷Qöf&†įČėū÷ÔÂ*Pl|Ĩ¨U(ĶS$ę,ä99E.H^+8…äąĖx„æSŧQ°íČí¤ˆ{Īvœm[cíRÛBv‰ëØ^”Ü×ef×ģV0{4^ žšąĄŠ8(K–Ë(´R 80fƒÜƒo"9” cōš+ zQË–Ģš—RX2xkƒS´í¤œŠØö¨bëŲēŽúRävŠ6øėē¨įˆú¯×Zo.ūĪeuЄ]ž|@ĸ,X2đrą1.ī<˛)ōōę ņú&X-$îę’qfBSwæ+–áFPLlG#­;<€ÃK([oģ7Ŋˇ;[ˇģë°{Mäû7Å.ø;ŋĶXw6ą@ƒöÆ 65e øz•ģ í|)öJ¨Ú7aŋ7Ršûē÷˜S´BU@ ŧˉžƒ|ŋĮČ7Ķŧ˙ģËs7^ƒMQ‹]€RSi+'ÚeÍfŽÎėBpÖ~ĶĮûģ’¯üžģNĘįÔvxMvT‡ĶtŧĀ#}ÔŗüÔũę´‚Ķ´Âžąu]~ŠvôÆT뎯ķKöÔ¤ ˇ™ķņ„÷äQ˜ū…ûÖãö{֖\ĖSŊë;Ôŗüŋ[ũŋŠĀgWĘs‡Ę{üŅ|Õ~Ū‹=ĸYb} ¨ ĮƔ Lj¯Y­Q8wL׆3ū7-ŋŧŪoĮЇžÔ“>՛>ßį}á§~é=M”-ށc†ŖĐrã¤"Ī!~_GĻä”ĶüÔPÍ˛ūå.7kČNMėļՒØ>•­cKhļĩ-čl8jWķįY÷4LĻ\‹>ą´Lrģ Į’ĘŖĘ0˙"Ģŗk0G§˛2oą1úĘôjqûCō kr”˛°1&SōôŽ3(P āÁ  XÄJ4HĐ`yđ8ÂûåūŪ3ŽŋH Gėģ}˙ŪíķĮŌ•pŋp}ÜØ+Wސåõ‚'¯ÖF‘šD…g žNĸJ&MúŒ)RļjŲÚ(õč/ĨP“ūÂēÔéWޏžÉãZTŪÔZđÖjũIR¤É%ßŪũûˇ¯Ĩŋ—vīĸ;B,Įš#Avėš1(Gފu2æ(*W¤§’ÅE—بNÁNåĖÕķÖ¨Am!…'Ģ#ax¸:ú|F,Ę>vSį"Ų‹uãŸđčŲZe¨mūXxÛĩŠwotß~õŨŠŲ×īWquŗúEʏĪūŧūķ<*é$*Tbé}øZÁíōŽ%Ŋö9B˜ĀT žT8Ēåŧ÷üĢOŋ<„ī'ų>d?ûR1ÄųBĸ ¨ Km<ÂĄÂ›ētĮõYŠŽwŧ)#œuģCÃūûŠ,žR|’Ŋ÷TtīD­DņJáØKėĘúdAŦēL*ž^Î;‹ ēūaĮŽŊdį¯ĀVKrF *Ģ–ū8 ėÃUôŗËęøü¯Oûâbq>ĄäƒrĘęĒnLâjŒ¤NĒ‚Íģ{GH1Âņ‰N$Īüi-yP[‘'BS5Š>@ģ4ôUúbMQŽ4¤ Ā\;˛Gīb'&9SC˛ÎŖ62őâōūäŠkļˇgŠ[ÅŦŪlD[ yc<äҤâJĶCžâœŖÖ–pōLÖ;úĀã'ĢÂąEÚtåeRæcGH“'°yåņ$ŗVĄ'[-ËĘE¸õØâHÃÂt"‰(yāē1ĮWōGG•āl×ú.ꗴx§õNí-ÍRųh-[ŧzĖØĻŦ*‘JļRAėžƒĨmV¸ŪfqΕå2Œwŋ›EÜȸW„ŗÎJyæ¤2ŦKAđŦ˜Š&Ąæä(Ŋĩ84+Ö˛A ĒT%åD´Đ)•”¯–õ"ūˆá’Dē‘._]zIGŲ¤9ŌÔZyxl=Ĩ4ûU@íŌÕ@ŠM,Ɛ/ô)abcū§Š m+)ŠŌJ.¸\âūÉŗ›­ĸVāĢHŖGžV`ŪŠ(íØ| Â5ƒeŧtˇr#bīK­ņ.w/lxā˙ŊU /”Ú$b¤¸ÚĨĨŋkAô™­ÂaScT&SŏläŊßMOeL-=#°xXíķ/đ8ō ŒõŽ}zžęĒX™pwJTēړaÕaÉOV˛ōÚĸRsĀÅ!xljŠĸ§ Œi}u‚QUėķŸÄc$F1 ¸Ņ7Ŋ ¨/qÉōø˜ pEKkÃÍSà ˛/LōVøØÃų4i€äƒŸ#8™­T’[acžQŠ\œd ™JwX™PL{YūLMÜzĸņ™o€9œO‹ØCÅąˆÅ ­ôē0+€6J“¯ØÁŽđ0Ž!+‘-2qyĀaô˜Å(‘ ßĖâKԊ„"FYlĸyČÄ(ėz,ĸĢčC" ö Mįƒ¤-<҇Q,B™đÄ"䑉>ȃ}Hë<ņSÄŖ}đÄ Pg Gˆ”‹€$đ zėuŖĀ&D’ ‡uĪ#›˜[Bĸû5h/lÚ:¨¸‚„CÛÉzVA‹‡‡Cŋ…Å~qĒ…m<ŅĐ{Äf–Áš'꩔pōŒxPZŦsÎĐ#ļŽ¤īáWš,#A1%Đãū[°Vc“Šådœlé]ytEF2ŽPœ ũøōcĀ&ī‹>Œ\EãÅšĒé.yqS AöĩbÕĶ#D9)ųŽ7Ŗ5ΨJ_| {*?üÔ"}ÚģPė.§ÂšœGiÁAęųÖ2¸ZLl-æ”Ņz,7†­đč…ײķŧŊtGC*Ō/ȓĢŨÁL¤lĢ%5?ģĘÕ'SHnã3ųĩ¯rÕĢX%E×Áę•5oéÔFQiŠųs„Ū!! YH€ë]NGĒ•’xEwMŦ+¨ō*ZPt@MĖĢOĖ—Āū¯tÍ+aK{NÛúŽFŋĀ›Ū$ËŖ!Ȋkm+āHX–´,Iū^][؎āĸĩ4qmc`+ÚÃļmm]+XėŽdŗ•j IdV’pjtlZ<âA”3Ųfˇkj“ÆØņ79q/t2įz´ÂפD—­RpkįĒ×îŽöŽĻĩëq›kāÃ*XļÎåŽvģk`˙*uąŒuʀ,E M/Rûž9˛‡Aћ;Žhš+ÚššļÂŦîfkāSØÁ20` œŨÕĖ–,ēÃjÚĸŪ¨ÁCsäKÕĒS=yl˜„i PØuÅ"0!;ŦTĻ)6!É;`b•pĘ@Áæ;8"n¨E™1QLŒ"āƒ#ō°L@Ԑx„ū@A‡T`B˜ Ķ,‡E bj‘āDl1Š;āË|ČD%-‡U`bh!āą‡NČcŋđ”`uŌ^eŒŠŗ‹Įėûd[—Œ4ũl]“ŦąD­âs¸¨§iVĄ€Y˜„Ÿŗx”-œg$Æ;#Œ,žZā$¨Û*“ŌÆ_[@ԊQīęÄ×J5ĪjÍZ°¤ë5îĻ#c '[ŗãíVJĮŲĨĢ9“HW–ļËm°u›ˆģüO¤đ Å3Sˇ‘ž”SÜ9aß>†ŲŊÆ;Ūp‰mD[oœTjĀf^ƒüāĐŌøäÎ5šsö ųÎŽ•‹ÂhŗVÜ1l=Ŧ)•9qū!l…×ûŠ:wXbĶ™”VpΜFŠÜķ´ŖYßąšsRŦ`ĮģÂĪŌpęSĪpb?›aŠ}ėoÕúƒdįHŠŊÕßÚtŊËÚ¤ĒžēîÂ.v¯÷ęÖá/ŪĮ>÷ģ¤ā¤{āįäšm#S-QģĻÔ?9Ņoą‘üšģ^ųē_žî—į0æ)īwģ_ē$Š -2wžĢfŋlŧčÄÖKĩ2ĀzžXû:jnzĀë.̎į{éGnûŋįũķŌÍ<į'?yĢK~÷V-[ŒĪ9ēq—5Pd‡‚đ÷nČų€7§¯ąž|āgßûÄšįßųžK>ĄÕũÔãK;`é>ų­S-@Ņū†6`â'ƒxÃÜ yŧÁė@ølĄ2A2*ūoūāDaūHú`˙Ü@ú Ëāø@0!úāāËd2 äa—Ψ¸(žÂ¨ˆŒl6"'ž¸ąÃÉ š)ú¸ŒÅv 5¨ūfPĖAA`JídŠcŪĄnõĒ ˜l$9iF•a‡•Wų]Ųy-ždŦŪȑû8—9Z)Y— 9.°Â*čĄjō&ŠgĻÔ˛`õŽķ˜ö8$Ų!92xY–Eb’‡‚šĨYƒŲa§?ž$…Kå—cš(zš•!yŒw"›™Œay‰"…ŋD‡QņÔr/~xĩ8ˆlģ]؜ Ų¨¸ßųš‹U[íÄŲ•wY–×›W9šuų Ų™ĸ%ē)ØXĄq9”AŽ%ŗ%ōôÖáŽA Ɓ9ōžšÍ™›Ũv.ZŖĩų&ãŲÂgPūųĸ'Z ˇŲĸū¯Ųɰ"Œ!ã)´øôADYH¤€SmíĻ:‡Ŋ\Á9žC wt˜ÄĢ×0DsTqŗúĒÁÁ ~´7 E ÍZĖ%~ąÚ9×8~ĢŸã­‹CHŸ…hœƒ9Zuč%‹Hąą"tj¨wGōš;*NĒįo=h!æĄt4 ÅÁCįAâPę!ëA~တÁCÁÁ `œâĄZ[ŗÕpčáĩÅĄ4 ĀZÔCÅÄĄ8[ŗ‡#éáb[~›EĩË%ļ†-´*Tđ­j$ę6¯VŒēĨ!ēē›Û¸bāŽâxaUvęœ#úŸeÚū§ˇ;.`ÚX‡™aŒA%°Á!ŲüĸúųÄŦ¨ũģ 9’)ē‘oųš :§9Ā3ē Å锁ˆdŖŒĄB,)ÂÃ!”A8Ä/9ÄĨĩÃ1šÃá8<ÅUüÃAÜÃ;ÆĻrŦØD’™Č>ĄÅIœÄEŧĮG\ȃÄœjˆÜŏá9vá>\Z=ÜȅœÃ•!ʋÜÅIŧÅ;ŧēãXĐáÆ˙ÁžsŌ.n<”ąÁ.JÃWœÃąŧĘ×üĘĨÜͧŧÍÃaÅ?ŧΟačÉEÜĘûŧÄáœĪ˙ÜĪĘCŠ?ŽĀ\/*S`+tÉtœĮãū<Đ+ũČ)ŨŌa<Ķ­É3ČÆwÃuĄHQ|ĐĢÔO}Ę7=ÎS͟ü’_<ÉÍQČa ŦA"ķų‡Ų0ÜĐ_]Ę]}Ķ…ÕYĪ<ËW\,‰ÎíĐŲüŲß\Õå<ÚŠ=Ä_üÃ?\ƅÆmœGØÁ4€”a–ƒĐįÚ§]ЁŨځũTÚÔU:ÛSœĘ;}ÎÕÜØņũŪĢŨÍwĒ „^ĸ„:…át뛊ex  ! áĪ÷|b*žá ãįW2b~žãūá äã"â/>ã#"â#"ã/ž:>æ~~/ŪEĢ ŠéX ģū÷§%¸I{ĨēCpĻĩÁaD[ŗâ|9ģĩ=”ŗ "dÄPāąkTH‰TŗÅA´§ž‘Aĩ)"vŗåˇ[ģ4"ˆÔ9ØWjæA}‡´Y hnâÖčC# ˛øÆB”aÆAč}Õ ]ß=ņũŧđC|ÅãÆ7ŧĐUœßéŧō˙ÛÆĮÁߊ€nYĸnų&O¤×3ÜЋŨW=õ#ČK|ŪK=ÅWŸØƒŨØa]ZŸAÉɝŦAėˆ €ÁšA„&œšŠ“Ÿ˜ßų—Ÿ‚!ŽŸ„Ąų•ŋø“ŋøO™Ny…AšÁ€Ą¸aūvšŽ.Øa´ø!ú­˙ų¯?ūįßøåŸūíųĄ?ų…aúą?û‚1f3h° Âƒ $6Ė1‰ÆŒ ;ÃnŸ9˙Ūũû2¤HūJú{įņ4vT†‘#×P`L†4g:¤y3!A™…ۉsĻÍĄA‹ lĸÅÜØũÛ÷Î$Į‘T?úĶ7õģwÜVD”L˜Qĸ9ɚ[čÎfb™ųdÖėlY´së’MÛė °fäŒUŲÆÛÕŠ(ßąãÖذfHé.” ŲqPĩ‹%ÖVōŲČvĮÂW 0e͌ĢŅÔ_?~ũú•üwŽŨļÍjėŒ›ŗnƒÂā2 ›ūp AÉÁsį‰<¸Lfä‚á#JvŪĘ<Ã/ģöėŋļsĪŽ ”!Éf |đÕUcMtÜVË wĩŲR¯ !pQŽ įzKĩۂĶũvá Ë{-ļôAÅ6(Ųė/ÎÖĖĐ LÅԆ>øÜž3l÷ĘÕ ąq&œ‘“üųæ­wū-ŌØ"M¯ŊøZUkĒŊÆÎaąļœ˙:ņp]îĶ`1ˇC õĘÅO<Ä+‹.üĪ×sŒ†{äÎtÕ]Įčv8~§]-"žgË+ōĀO.ãW^.ĩ”׊<Ģd÷á‡â§ž ¨#2ú Ô ü¤b<ũkP+Ėã@ũÕ"ļ€Ÿ<ō§žÁį}đŠül•ČŊūˆŠT4’“<åû@h”(īœī;ÂĪ,āÁ¤RüéO(Œ¤$ Ú8ĀÎħ(qķ‡+Š8€)5I€’AyX U"bŸÎDDˆ>ŦGčÁ%z˜"‰?ŦĮ8ę€üĐō08ĐCķ=D"Æ&å¨ü‹ K —†‚ŲũĖxŽ›˜ē8Ö1ĶiĖČBšĮ°ę5˛‘#ÁĩN .1ˆa Öčˆ;J‚•Čydr•ģ\æ§IØm[ĄSÚš&…§E dc¤,ρ[š@X úŅŦm ÷ Į=ĐŖŪąãė@G5¯iÍlbŗ èūf3Ē™ÍVŗ…Ņė] ›ųĖÃčĢOŲ×TĖygĻS›ôÄĻ=ë‰Ī{ę͚װ€7Á9Îpæs û,(ŒöAMj6åų6ČVTJįîčH`˜YP‚j4Ŗg6šakžėŨ¨IKĘLf^#šŗâˆŲúҐôË$”ę]JįYԜžt§ûô¨=¯1v\CÕŠQyŠÔeZ“šŌ\&SŲą—ŠÄųø‡5ļĐfuĢH5jB:Tkj€¤]-+W9ZÎs:͚ÛĀ]EqÆÂv’´Š>5Ģ]ΚÍoĸÃKč2ņ XŠķĢ„&Qŋņ¨Ŗ#(ņāxėŅ|åĢ…ū‡Ės!õ<ÃŲŲ#ĸæ—Ŗ÷iG´%|Ÿh‹ūØ1nŦ4šMf2“ãēä"ˇ%ęāČLK⚨ęcĖų0˛•Īœå4;YÍUFs•“’ÂČ0Jns–Ũ\į<ŸųĖTÍG?ŒĖ¯ŪIã*‘YL§ÚbŠ*Ö0ßøąžŲŒįG¯ŲΔΈSā;‡… "]ÂÕ8Ō…1ô…_†c˜Gaˆwch†^H†bh†h˜(ūixs8ō!Åõ!$b"AĮ"ânė]5˛…ww>g#ōæÁYÃÅ?Ū!?îĄîaw!4ލđđëîŒČˆōƒ–8?˜‰ØZņ1YbˆqŽr‡‘H0ĶN“Rxl7h‹ŗ˜~Kč Ũg„ˇØ‹!ą\áqį{'qžč„šxü—|˘ŒMȌ+fŒAŒEøO€Bĩrž~S!HÍ÷Á‡‹)$Ę8…ßĐ´X|ĶxŽ‚Įį€ėG‹fĶ€ā˜ķˆŽĘŒÛ×}ėø€ŋ(.Xŋ—ĒÆ~`ShŽ€ĶH…VЎ¸īøū‹ÍEéjŧĮŒŌ‘€ķ÷Đx‘ƒ‘ã(Ԑ‰‘Ë’HÆy.V)y’I’-ųÂč OP“Bˆ%ų‚Ũ}&ŽAUh[uwKІ3”tMé†p¸†S ‡Pi•gȆnø†[y> –(œåsI™ xø{C×B}ȔX؆Ûá?"ÔsūYšpYđpG†˜ˆwŲ–xiˆķŗ>uhBˆ˜r‰–yi~X"—Š’˜|HųÆ\؀> ”į—‹íH…ŧ(’•‘Kx4å‘Ŋ’3c‘8éũøĻŲ’4(ŽĶ—Â(”ūb(D´(.&_&„¨J˜9›˛ūéŽÂ9”éį VXˇy„ÁɜÃ)å˜–yh_šöHœ>yŲɜ H…ë¸b1XœÎ)žáéÆ÷’0É~×ŋŲã‰ÍIžīéžūG…WXōŸÚ9Ÿđé“ã8Q/˛›ÂŲžšŸšŸü9…”ŲW ’øé úy ZxYaīGfŖBņø ü Ą*ž&ØXWĀJĸúŒÜˆĸōhФT¨W˜…ŌU•ZŲ†Yy•4Z†9jŖTŠŖ=ęŖIg#b[Æ%ČE–ÎĮjĪ]Kyq]˜˜ĒB“5{„!¤”Ú!ˆYzsÛ!ˆWēĨŠÉĨa:ZgØĨ‰ŠwéŠ66ūĒσ`ÆĄoęŽÉG+Ū ĸÚĄj~í™B9 zjĸJœÜŲy§pZĸŌ'yˆ¨ôč/ ÚR¸8‹ZšÕįėāƒå˜ž#qždĶX“ēš~qzh~:ĄäМĘ"ü"‰šŠũ9ĒT1Œé§Žj›ÚĒļZĩĸ›ģÚĒŊgŠŖ žŊ}Ģ†Ģ ų‰‚ÂęĒ1UŦ°6žŠH:›ŗŦ™ÚŦšzĢ0ø~'Ņ j­Ųú­(6Šz€ĐGĢũ€ŠÂz­š™­sęŠÔ¸Ŧ階đY“5éjF6…Ūđĸ8RĻåÃŖQ‰•gČŖ;J° °8:Ŗ2š…="Šh (B|Ÿ‰d-ôūBá¤7â¤ë?­[b:]Á•°qHYR™ŖLj>3dq‰ÉGÉåGiī$šģŖŦë:QÃxt:¯ėŽÕˇ‘ˍj0%›ĒŽāš‹â˜šŪYĢƊ­ōڐãZ€ãęŸĢ*ĩ%ņWā82 Ēy(6)ĶįîįS+ļcKļe{ŗúIˀhļmģĒū›RØĒÚĒžˇĩn‹ˇyûļzŗŪYŽz ¸eûŒņxĒ4Ŗ›PQ)č ŠË¸ šųŪđ-帕¸Y}ˆûÎĘŽ–ëšz‹|'ø*ōšĨkļHúšãhÍwŽ1kē¯ËĒ H…“ ­÷ģxģļ[ģļÔxJūÖĸúĒ N鯋#%ԅYˆbšw+YߥĨXĘŧ%ŊĶëĨÍKŊÉûą_Ų(uh¤)˛ƒ›Ģihš…Âûs%k#V•ké•]ų¤;ŖP°íģ–cXĻ&˛˛ö˜lûdŋW̎{(ˆŽČęŋy‹ĄšēBœû‘Üļacƒ*… ŧĀ'/õŦųÖ"ƒĄWąbXņĩųļįeĮ˜‡•˛ģ†×ŗīôÁUÅŗ.õ\ĀĖy/ÜÂ1ŧÁ3\ÔA‘ ­á~°čÂ5,U¨ÄųV˜~4ĩ"JŦ†7UEÜÂ6ŦÁ,ÄQĖbP,ÃS‡Č¤čĖܑ”Ë Í‚ŧXúĖW*ÍŲlŊԜŌÛÍÛáÍ6§áÜĨÖ ˆw9BzGAĮ ųņ‡hyą_ĒΠˊ÷ŒĪd˜Ŋō›–ģžhȊ`ē•ĘËž}Ôw”b€ũ€¸ HSNĘŋ<ūÄ0UĀšœ'ą ˤüЍÉEfŽ^fîæŸM ĖĻ|ČmČIĖy[üÁ¨æÅˇĖŅ0]Ë=ËBʇ¯šĖÉ@xe•ˇBė`Žc{/W|P,qī1zú;ÍĚ[yIfxRíÔQũdŪ€|,ԖgÁOMÕ+ÄĶP=Õ­ĻÄF ˅K3@Ŧa­<LüÖĄ׹čÕdÍb˙ōNQfm Öuí×Vũ×c=ŌU x ‰Ö3ƒ›ágLÍ{ûëÖOÍ×r ŲsíØp=Ų—Ũ"Uĩ \ŦÁU-؀ ڟ-ڞ]ÕX†Đ▂YaeŽQMÚ}Ú¯-Ö˛ÍBŧ×Öĸ+ūā –Ę֔ŲtũØÁmŲÂŊĶ (…Vf ø(ąO´Ö_=Û°=ÚÔíŲ–ZU˛ņU<“ŌíŨŅ ŪŽmŨÕ?xx.Ē Ø–1*Љ’”å[ŊĪßĖ+ßælßõßôÍ!)Û! ËŊâŊŌįĐ aiâÛĖKŊöŊĨ^‰āķ­Ī_J˛ ^ŖčĶ•~όɞT0ga­QoLĩ1‚ŲÃMâžŊÕ˙°Ø˙B‘áÛã=Ũ/ŽiÖØyÆ ÉX‘JāXŨ/ūŨâ ÕŒÔņĮûPØ<žã-Žãą™ĄFÔ×÷RodqõÖ> Ԁ§šlÂÔŨđ­AÍģšÛ×q å‚ æū•­š`NTĐŌKÚONæaîÔc^ÄŧÃŊęyũéælŲnūåbÎįvm6ԑÕB~âŽ-ÕņWčÔmč’-ֆŨ\ãέ ĩ_ xē;æyŪæ—né™^é•NÔĩŊ~üÁ] Õx>ęĨmę°MęŠ~eíDÕP9TŅčN<ąĀ}苎čˇnëšūÕ-Zåƒ!åĒžįoŪįÁNėeŪį|}Ží‘‚šļčzŨ¸^ëŅŽčŌNëĶÎÕ8ĖÛ.BÁ‰^ėznėÂî.ūÕōxPNŪÉáp"ęžîëîîéīí~"ķžîėī÷ŽīųŽīņ~"Ę`ī˙žī/đßî_īĪPīĪ U°ūÛāČáÉÆāīīnīOđī đķžîĮđ˙Îņ!¯ī!Oīę~đėÎņüNōëÎ ÆpĐî"Î.ÕâĮí›>ėßnÂ=^ŅØËxnķáŽķÆ.ØĪÚØæ×‘“Ū×>ķŪÎô—îãZÕZę@ßôš>ė_ŧäŠ ë2ÅŠ?=+Čč{ũSœÖ‡mJ;ĒJøg˜ŗh¯}mO€n/÷%}(Ą„<÷yˇy¯Äyī÷lŧ÷gÛ}c÷Oį"Ifoøh›&˜Pą‹/ųcĪõ‡Ö|”/ų~¯Á˙ĸ™<œų3ëŦRŅ/,d ß`ļ1ˇ!ĒĪúˇŅúĢßúŽ/ûŗOûĩūya ÁûļĪûŊĪû1û°ŋûĢŋú‹gā8įˇXđĮ V` ģīûÄoûĐīûŠ_ũaÁ` ŠüÃ/ûÔīúŌ/ũąoũÖ/ü1a TĐ;ĩũ˛Z}…˙ĒSĀũŊŸOö˜¯}úøđ˙ņOāīž9y÷OŸ?‚ >„QâDŠ žsō-Ą?†˙:ūKčŅâH’%Kdą‘áGYš„SæLšßlĸ˛æNž=}ū¸ō"ȃ7EšTiЖ;&lĸ1äRĒU­ŽdhaŠWyräXđÚ;nb– 9S…Ę*kÛļe ÷íܸqßڝ›Wī^žeŒ”ū!ĸ‹†2T¤v;…ībÆ{Ų╠×.d*gĖ  rMd×°˙ž´âöņčĩ#SžÛØąj*eʈ)ĸË Ē!ŖN-:ōnˇ§á*ŽœJ•%J¸ąÛ÷nĄ×‰]]fõ†ųtę6qęŦ^ũo —$ø2ûOƒ-° ä<^ũUŽ×އŸ¤ķ‚ŅCŠ—Ÿ_?øŽÉ3Ũ/@ũ˛ÚF:ú„hŸĻĐc§AvŽšĻvĐĄpB Ņąà 7ĖÃ ?1D?ÜCk2+QCGdąÅ -ė°Â=„‘cd§ĄĖÉĮv¸yg›ãYĐm†šĨuhč“Y6:hĸMv9iĻWÆĻ ‡ČúYhz‰nšY°Į–šė››F:9š•>[ iŪIC#xK ;įĄq>:Įŧ™žģæoW[ĄqbŠjwÜųšõ0…”MN+fî_ôŪō‚4-Uc‘îíÔ 6ßéččđę´|qŖ"-=uô éû@į\õN;{ĪĖe'øÜPo\ĀĖW2‡#}ōŅG`ÉáĨšĨä§=¤æzžéW‰œŦoŠųEŠ?ˇŪCq6~éđÁ˙7¤Ē=îęâ­ö8úūėĄ_tęøŖwßæ÷ÁWüĻ+ļ9}nãŊ—Úô˛%@æŦ)ÂS–?Ūq5SÁį#éČ7ėƒģė(prŌĄ Žū훐Ža¨{`š2š‹(pNAÜswĀ‚ėÎ)ąSĄ^Â}`Dn1dYčÔ;8 ę9aņĮÕÔĄ9"ˆ>F´XuôđĨ(;bĨˆĩ%VҊîˆâËäá™kŠņŖ"ÅXšĘëO ĮˆD+†Qs™Kß:†V5F1+.Ä!{<‚Æđcš>ėh0Ė#P^rBA&’`&ėéČ7u„#īˆ ē(YŠâ$’ė ˙ąŽÎ¤p Ļdū"AP™—„%le˛T9ËSÚä3Nā†+]r1ĸį•ŧ”e-™ō(_ę)AœĮBxl‘P°Ŧ“&û8ĖX‚ä× 0Ĩ™J˛ QaSA2ŗÉ¯mޞ—Öį.[w쁠ĪwĪ 7>šI¤˜ “°ķ#<2Žēƒ%9ōGŲN äj hC:Jt  ¨A#*QŠJjÍė)ē3z*E”dIH™:Ę(ĄœjY!mäHí´‘â53žƒT)‚\ęÄ ´´Q e-š9žæÔ§=ęO…ÔÖ¤•ĄjR‰ĒTĻ.•tĮãŠS›:UŠV=dĘÃĒJUŽjNYûđ‡ūã#Í≔YՌéLVŌnäō"UáMôQŽ­ÃemŸ@įPAŖ í+E%šPŠôjŠlD[PÂ6´zūHG]A§Qô‰.­j=ęÁØÁ‘|Lô˛û!—Jōq“°üõŗņaĨJÂĘëiõ´ųŲŦđZˇ9B‘Ļįˆ‚âCŪæÖˇé­@ŠÜߐ¸Įā?Q—Õ†7ŦÅ ŽqĨËÛūŒÄ‡ĸôŸLž‹Üčv7ˇÕåîo-hCį`—ƒĶ…nz‰ģ[õb \\í°ōŗ’IõŖGúz-L,–›HŠŗž•õōŅq‰ žcˆ×ęX‚ļS°Õk@!:Å:x‡ÕëDū%üŧÃf<<éåWģ/T õØĄŽMŌÄVWVT’ŽpCę0í‹ÕS*~úƒG ҚŽķŗÅu|ôuą|ē"VĻ hjā“WF˛ Ey€PĻ2–ĄVåŋYĪqP¤e)yËdžō”Ī|*ĻÅĖĖē skŋ–-Mhi6s™ÅĖå5į9ÍQ>ú&(4YÍzÎōĄņŧgž`“ĩCÎ ¸ęx‡f„\’ĩ†EÅ,NŠęn’ôčbâŧļw ÖÁšp†€L8ą‰Ŗ¨â*\ĐŊŠ8ĄŽõ+A°‘ ņč a7ÍiÚĨŽË^?KūåûNj”<„vRR;Ļ s¤jÔÎvv”9S|‡T ŧōQ‰ĢåDûŲĐîæ3ĸûŧg‹~ŖM{.Ī<īvīšĐUV^ĀŠœĶėÚ/€4ÃؘŸīE÷ÛákļžøWŗéĒųáōÆxÃŗÅ°¸xk,Į.9ÜyXōė Ūä(õ?ĸ.°ĒÂ Š°ˆbŊā¯u(Ŧ={PÔÖ¸–°~´ōáZŲ5đÉ'ō0}ŽŽØ–ēOhgMÖ*Ė9ÎúRĐԙ¯KJŖag;ž#$ ’Ņ_Myŗē ^Ũw¸Ô5Ž ļ;÷ãÖũˇÃ]Öŧģ„ĐĀĨģGėÎū]öŽwO‡‡ŗx܄ņžˇ{ČŨøķō]Ŧ™ēĄ9xĪûķÂíģH8˙\Æą3;éŠ)—%:Tĸ=(žŪŲÕ[ž´/$ųņÍ` –ø#ūŦץķ‚Îz ŗ.:ô#JëX˙cø>'ūņ™ī|ÍšįqRëÃõėļ#QęNôSå%“ōYÚ&‘Ōz@Jōüa‚ގmëJžˆ¸û)Ú)‰áę›Ēd=ÕÛŠŨÚ)œŗo˜'~áŠ% \Ā:i@KŠŧCŊŠ*Öc˛Ú” DÁ AÃ;ĀX˛)ÔĀÁ͉¸Đ$Ą€3 $@8SŧÜū@l%ĀŖ"Éų?Ģx Š€üBŋôČ …)öÝw ŋLKeōˆuđ9ë ž.ôÂ_ķÂ14Åņĩ.äšø>_cžÄÃ0üÂîûBU%xk”š?ëãÄĘ?!Ko¸PˇŌ?Gqá† w°ŦDT$ū‰€Â$}’D¤0 ÉÃ1ˆŗ›jĨ1E|1ˆ'p“"\Öy&˜ęL’Tô 62Aõhļ0 kđD5:šôaˆo‚„0‹jš¨`‡—›˜”å8;ķ éû‡x>‰J0ilF:ôŸËÆâ1}˜5č=6ÔÄ9/ +0ūŧÃ;¤ÃCąoø™Ę‰pÔĀMÃ:ÜjwĖXĖēx.npĮ\ŠÄ}ė ­ęŠk¸‚o@Dė ™ O4>‰ģŌĮ šST"ø@Åĩ”@,—ÖÁĒ/ÚąøáHT¤hâIqČD”Ļ^LƒŖ8 z2 Â–đ˜!Bļ°XˆpD6?Tˆ[˜nlÆQ€°ĘBsdF7Ĩž\‰ž$fDʡ€äƨšļĸŽá6´‰5 :ĀK [IJ|° {5°Tļęƒ0†ē[ë S1)žå{́bâ[€Ģņ>ŽdžäĢįķˆp €u,ēgœĘQ’M…p‡gCëcF}(Ęu0FĢė>nĐ5˜Ŧ-\‡Āžķyĩ!",hčģ˛@ŧģÉ´ÜÂÂ%ęԇŊ2ēâ΅R&:? C+“@—ƒq„ųÉP[Ėų€§‹P—‡lĪ&áōËų<1_JΊČĪÜO DüĖŧģÂČT7ū¤'>áŠøÜK”¸“l”wøūé‹jŖI1ėá 1К„¸J̆i¨Ų,ÃáWË0r¨!".œtËĢųîÖ2ôȔRŠ‚ē=ąË1eTÔ;;u{úųÔV÷Œ%ī€Ķoūu˜9ETr=*ƒ¸ĶęͰƒ39ŠŠ¨kWJ*)ô8WtĐ™×VԔQYReMyhøĖv"›ÂŌu Ō­%cMj%Ä*žG}ĢsĀvø†+XođĐ—ŊiŗžL-:>$€EvØQ¨Ôáã[ kĶMô˜5cDà —cĶ9ŦĐÍč°ØXŨ ‰-:vZ“Éh0ÆŖųTÉÅ\'š-ÅOJœœ6aStĩVÚĨy1Ûr5{[ũëˆ!Z:ÚWŠKĩū:;^ĒÛ¸’<ĮŲGEÍV$¤-āA3 fą(•KÜū ūëé¯h@Æ\ē ÄEUIa–Æ5\ÅušÄu\Į]ĐØЁŠ\Z ņÅõWu˜ÍŠcĖYØ\ĘŲņčÕÆz‡ßė=vā9hØĐđk€€ÁCb‰ßäŨ:|‡HtˆY娍ZM5-į°GÂ3“ëœĩ“÷Ŧ6ŲÛŋÔ&…Wī!ēŦStM°Öá-< ņ…ļŽcÄé_ģ&ĸX_|ũ†”ĐW™œnĐ†ĪØo؆5Ų6`o°†Eā.` Z“–`Vā &ā5` ^` â>ājā`– Ūmđm°đ聸jčŲūŲjY„ôC°攭učÍāG˜ĢĘkß íɤüB†°F7„9%.-së#ĨŪkFÅ9JsRsÜ• %˜bC›"¸%ĸõQ?:\ôuĨŧŒĪ˛ecˆ@Û=RÛ8N_PŲßo ëųŧd‘ßMSМõ!fZ6dqã<ļĖE-ĪÔy‡¸-ā5p°'p‚-°+ d+¸‚dJū€+ČäNŽdPƒMæä¸d'e'hNÎäQNåJneMždMVƒNåXŽä-øNւ¨Āøč؁x'°‚x/+Pƒ-@6A6ueōÆNķIūĀÉF[žF{MŽČɤŦbsnMĒÄBøJg†(“§snMsļgw°Đ(ÂņÃ%­Ö¨Ō˜îõ%ģ$ :Q@;N“9Η?VČō­Ą:FhJÛĪĩåw˛6x9SüĮ|D”}ĘļĜ›m¸‚ˇÕą|†Ū<ų&Íeé–v闆é˜^'—– `amdÔ\ r‚šÅMŖÍķ‚Õôˆš5(p čK(Ö\^Uâ2äB¨b—pžŲ\>_…ŪŠ}Ãđ؇ĸS&ąB“R™ lČ(.’=c}›':?Ŧ¨ĒÛ56 eS¨¨C6ԈnĨ7…hž.kŋĩĀ8e-ûm öÜKūĄđ9ĘßķĐ1BE”!éCF•ōÚŽüíœo@°č†î5ČĨ~¨“ĄĄĀˇ:XdÄNaûJŠ*ĮJ%ĀcKōži嗀¨ cŦîôÎ9$ˆ)>ļâqĩIĖÍJ‹*-Ŧ>:.H•”áÔ'•*eV ` ›Û‰ĀúílÕȅĪ6BžūßZ’˜Éū˲žWr RuîûE͇ô=Åh”NXŌëíߕɄņV0‚ Ŗč7pã†0 ƒnĢw˜†Чe •„ŧJökHÜjøą&”M¨† ŗDކÆNĄÚļŦ,ŨnˍÂÃ}P0ës]ˇÁūkʨclđQėųŒ”Č%.* w°9īæ Ģ‰ėēR}0ĐâV@ąoD–‡žōėũmr!CŦ›Š„ī6eÎw@i"äpç‹ė†VdēĻu‚VauøČQĶøŒøųvū,’u„Ļõ‰öŪÆ<M Ą8%t+āŸņVų BÛŧÄø}Ė×cwųŋ.¯J鑍|ø‡ ˇąžŪ#o˜+p؂-pæ'pf5ā+å_fe+p}pO–ä+0åPf d\ÎdJž‚%øØˇ}QÆ}ä÷dJVƒSĻ~~'Xƒ]Ve5°5 ūJļũ5čũā×å%h' ūä˙åL&~gŽe÷ˇ-¨dKîåđėböœļ/¨i6€pō 'jŽxąōîÆ6\ĮP"Ċ/Nt¸Ž"Ǝ)‚Œčq$ɒũų{øÎ›Â)MŒ)s&͚6-Ļ\ČPß;+ŪūtŪ *t(Ņĸ/žÛÖ˛áËĸNŸB­I‘›7īšēü4*׎^˛c¨îoܚ6Ũúu-۔9Ž\Ęv.]īž9AĘk]ēīÆ|{ˇĪáÛž7QĻdĮmĄŋ~˙Ē.”xÔ_ŌŪž}Ģvyķ7mß.oûü9tč͞ˇq.-z[iĐ EoŪLÚjÕĩŊŅ~í÷7ԜeÝöîΏ#7ŽZ›Ž6zô°ĄcÚȏ÷ŪÖí…Z’2–ėŽĩâ° ŋ;¯ž"úu:ҧ'/âú“{UĒDÉTëˇ&âĻe˜€ŌD™ņE ‚ ’´OJxũĮ „†ųCÕÜėwԄļåūŌ;-üD\ãqXâ~'Ūˇ&˛Ķ[w5Á;-FõŽ4(IÄXC:ŌXV(ÅĨ“[ãÅØ;G"™¤’K2Ų¤“O*Š•“R.I%”W6i%“Ą]ņÂ@ŧyķ‚‘LzĶÂ;î­3íũÃNŽ AŖ|‘e¤;”ĩ –`ņ­Ö:k@įwa…E€>ėĐ9ĸy!-´Ī;č™gŪwŨQJ_|;Zš!b^ú’~–?íé)Ļ0qÔQĒ˙p´ĒIĢļ*R1æĢmŪ™ÕŦģŽĨNJ‹ ŠOaŧ[’[AˆgąËŽdO!ŪĮ)ŗ u§°ná´ÔjøÎū¨ŗ­MˆIô-§ ļūČ_Ašš'˛â–xäbL¤QMoG˛¤nCúhŒ5įI$ˇf´Ž4{5gÁ‰ēĮĐĸ Y'CL4é?č)œ'‰ FŅ; °3ãxƒĘ¸čÅ#â—ōĨ§ĸlŸ~/Ū‡˛[‰y(Ö?S4$‘¯‚įĒFˇnD°Đ0)œjÆā-ģP?ũđ$ŖKüÂĩIĸú#,\úJ-5bI)ÄŖ~ÚfŨã×-Ëa…˜ÆūäŖ,ÚbTÕ8jüöE}–s”ƒį{Õēųęúâ7rŲ=WļmŪÅ fH}cæNã唯DaĖęĀ÷™€}q{ßQüzPÖwq~rįH´æčüãŽ>šūKC‘ëë°f"ŸÜ3\đ}ؙ⇔^j“¸é:lߜÔ GŦrIû,4Dą}ŗõ%áü‘ĪbØ˜Kĩ‡ ē…ŖŊü¨ūHÔ×čëŖ€&-ü-ĒũŽĐfuūũAmå(gBÉXŽņ?égÉ$˜GLĻ]wL~ÍČ?ėßÉnésd™ÜÜ%9ĮiÎrR ‹˜Ō P`‰(ƒíŠīXc'šĮÆ‡Ä VR#%Ø7—ØĒvŪú+wåĻŦpQҞdAŲr¤m\aOLVC(%˛š¯ĸ5c(AÉ iô)<H×1EAzË[%Ë"ū)'$¤ŋ)¤]\eHgBAĢĨġŠåHÂ’ƒQŗ›Å\ŸúPDŽJX Ŋī@ã; €;’¸ž¸ˆU‹&pš<ŦɘÅt‰ųŽ™•ęRœĻŌ[šéÖļĻ2|›z_‰t#aqY™â9ęŲŘTŽÉ'=I’ĀÎ*@UËĸSS^š¯}eķëc„¨ÁM6Œ•UБȖŧÍΤZ{ÁãdŲ́lžz“ßAk,dŠ U'ą,ČYŪG• =m'ÉŽozƒ\l&gMķÜ,‰:qéĐŗ5ŊįV§;Oķz26y>¸Ķœy–ø¨5IWs6ō܈ūĻĢ~EĖš+ëäáÎÖŪ06%ũ@Ė|“ˇ´ĨEō.@8“>fÅ8!×k%Ų1‡ö3 ŲŽŸvŖę€ŧ¤ŅÍ=L˜-oã'†Xc ŸĨl…š‚/ÂéŦÆĶ_`Dl’‘†åā|‡5ȰŖ–šXxGšĀ…YëÉ$ŧŖ¤”…1ƒ^Ē’|ĩ+Åô‹qŗ\’’ŧQQ~wiÉ“r…’šÖĩ.reE/”ĪĄ4öĻwôu!C.|Ėã-‘• ,NƒÔ–Oö^öŽ÷͇“ī\éŒ$#ß×VŪúrÕ?ĘĩŒĮė10DrĮ&ė>ذQägĸ  ņ\ƒ ß 0‘ ČP~c íŦôZ.ū›N×e!x)1Šv{Ú#AMqšuxTâZ7UÍÔâúKˆLKÁ:š.¨Ė-hĘjĩ+=…4aŋZŌ(vūc0vRĻu*eßĮŲ-{z9öŲ÷8Ú/‘6\ÃģŪšCR1eLĢu.ō#‘Ŗ^ā2’0ŨŒi[Žsŧ},́Gú†¨ũ’œ‘WËiĸö˛'Gۅ„Á2Žt‘–đ7fģ@ôgÃŧ̎8 0[Ąø\ >4̤{3Iöj”nŦZzŋJ¨ú#ë•ĪQMøF•aūW1îĶ6OĻGĒĮž (+ŨVŽ÷m&¨ukČ0G ­tÍäđi…ƒ\IĐÍūԌPļ1û÷D^RÆĒkŊ‹`?‘^H„ĄąTĀ öZœ‘ČMÄ[ĸJ"âmē”l乛Ã!›VČÉķ=Ÿˆ>xÉģ‘83ŧĸĶÜ xaĄ%ūĀģb ‰ģs#ē°cŠ“K8Ąe‚ŊÂŪ­äË§WöŊ"ī<´ŒŊ‹ĻAžú˜\ÅQˆ:PÍoNäJéZį¯Cānŋ˙= Ã4‡üĻ˞)Üđ5¨Cŧ2¤ {ĸÅöÛŪžfä'ÎŦú‹ÕNå—ũ—ĨĐúÜ7˛°ž…S3f•Œ×OĄķÜNˇ„ĢzīŸ‘:´¯ũđoŋũY9÷Ņ’Áčēé7|AtÜ tÃ6,ÆåũÃ5ūđ¨|Q8ƒ0Á…ÂÔGĖΙÜĸĄNīLÜM×FœN^-îü]Å0đtOåt‹čOėP@\íy…:TGБP( čŠJ̏ŠëŨÄJčŪËíž홆Ĩ ņĄĨ¸Ö7ÕÎËĄre@H!Rđ]äĀKŽMŌĨ–Ō­\° ;íšr͘`Iēá†JŊĨ"ÉG% ĸ(ęá”$ÉbpÃ6āøtä€X°ŦÄÔ!ÍŲ¸ŽsQMž„Kę¤ÎtYyYā%šWī'ÚĸŨJęD„v}„yqø *]xœČŨĪ´ŅXzeÄEūÍ4áFMĐ; ÁōŧY.–Dõ‰ ß뉇ŗ 0æĮc´„;0aÔpĄžiŗ`Í)=Đi7D”2V × ą­Ä X´Ā8–#9šc:ĸã:žc;Žã;Âc<Ęã<ÎãXÁlAXÁ°=úc9~€¨ÁŒ# ŦôŖ?*äB2ä9:A ˆã đc´€ütüЀĖ@ XÁ8ÁxAB<ä(‘¨VI„uũ̈`AC%Ėu5›8ŪÉ@qâĸ1 AÜ­bĸ !gųß"mÜ)ŽEHėāPzH åŨ°JÆėā EäÄTË(#LŒJ›8–qQVbūcPD` ÔũšZhaRčXfE™ø\k•…ßčŲW‹ņ ›Bˆ!‘aĒ!]ŖŽ$EY`Į`fl€Éa"Gb*æb2fbjÃ`>fc2ĻohFbRÃqø†djæf.&qđjāĀ Ú€ Ü@ tà tÃnŦm\°`ß0‘ČÂA^YbáUĸDDUáĩÎŲΚPDęä&|0žq-QÉJyœŖAOø+ŠÄ%į>ųāH$įau…"qĐ3˛å^„‹ŧX ˛iawbJ„cųĘöĨUZaĨ9†[váĪÅ%ÛNŪ4ZŖ€)ķ%N]ôiV‘<‰–ÜY–üčū!čFÉ]%Ô*h„2čƒÉ]…P.¨„fh‚rčÖaīí€ØĀlƒŧ”…5,ŽcņĮĖÆŪ Y^IƒÉpžÁE„>I^Đā¨H<Øéé5XÁH¯(‹ø€ČÆ=[<Ü­¸â>IžĸÁ‡JSēHīYؑįIčj‘Û\éE¤RŽÍ1Ú×ėåî]|Ú'đ5g|1E é°đT^BrÚ{ɔ7|š†œĐĶų_˛ IŸ꟮•Ųđ_˙ôiģ„éY­ŸĄIøņ‹:ˆĄ[LN[Ŋ•Ų°ĸ˛Đ‹]ËËäÃ;ŧj–¨ø8A‰–C´{HÍ=M˜ęD’ÎâĢZ\C,iūoÆęĪøĶ%Z†ZŲef5„ŗIsFܚ¨ īšWœ­}W™Œœ!+VÎÉŗ.š™9^•9kũœÍ˛'Ķu)F zy žeˇ:Äĩ„Đ-V(Dĩ'‘ĨK|ömĄ°:ÔTŖĶég6ncˇzcˆą'šzĢ}ÜÅdQ†š‘˜ŸĖ Įˈ×mŸîG^ŠaŸ>ŽÃn)ēÆŽĶIŦŽ„ßŽÆŠŦĄ’Ŧ[ŒŦɒ,’\ ä´Íۑšd ×Ûą€Ē˛ƒé¸„BQFXp’ŸŒ™ĩŲ•eĔKŠm îÔlŗęÕAŠŗ-D_Y›Qkp›`XLĸX­_Ąe§äūŅ2Oj[ŧ—lũHĤũUģžšüƒÚ^Ō ­å&ŒÜëejkÁ)fÉéôu+âÖ~xcŲb’V+ļžÃĖrCųYĀZúävÄų´Ô咏­KōŧE|Ŋƒ Ė€”å‰Aā;äNĀŽĮ˜ƒSÁEŸd1U"Tę܎į$Ņb[Ÿü â5DîpŽ›ä&Á0ŪÅ/6LWîxÁŽ æU€ũäÄÁ`åÖĒ[ŽåČ|QĪ: ‚Ė—›n–Ú ĀŽE|K>´ fPZĒëõUá•î1ĻéũpĄÕ,!ßūØ5žČōŠmĨņ”ŋnųĘDNėzū‰hCyĖR(Ա텴)Ų¯ōÎ>L°BđKđ3ŦHhđ|°üĖ_ ˙P4ÍN đ ī Ģ0\āŦ’Ũ?|ƒāĀ”Ļgt寤Á7Ā–¨\Ëė 6KWÍ Û4¸|+(•?,€¯ôŌĩ¨Ã€K †QéJņúŠ ‹ûƒL 0P eą0!0mŌ{ņq ąë9 Ģ?”ƒ×ŲoĘ‘ˆÅVæī7ÖWŲ•¯?ĐņŠ>Ž[„¯ŒEˆm˙Ôī]_oĐéî1Žü>‚¯[ÍĘŨ֒đ•b!“1]á2˛V".˙č čđūÂr,Ëō,Ķ2– bR䀸ô€xÁe¤”Vp@hČKŲø}Ę+ųą1Réƒ:@ŦÉ €•¯0ņ3/ŦqSsŖ„RMq?ŗ@Ēoj{q8gą>3Ŗ„ųXņŽą5ß1īņÎ ŪTķŧL\E!§2S¸ŸŲ ę‘2iÅIfYēRá^ręÜĩ/ũ6§D#ūļ“pÅUŽík—ö+6ūk@ â’ÚDI 耐D8Á8ŧ´ÄtLŋŖM#NË4<ętOķôOß4Pį´PītPõP5C*ĩRÛôKôx8öŖä2üĀÄū@iրD*Ḱ䔪 ŠĀ,MŤTînå õŽÃŒÎĸEEđ„NžCœIáĐĸą; Į6=^ÃIōžĩ A܃ĄYôΨGČW!—]>8†ēėŠdS#WĪϜH?Ô87¤Á6•š˜›ļSR8NV*ŦĨ$÷HŪn°AV|âëßž )픨EŨCkvn%Žô}à dChôf÷ewpür+wr3÷r;wsC÷sKwtS÷tĮqwd‡ ĸ†XF ¤Ļq?Ļp´Ā78@ĀNۜŅ:Rl¯ņž56ėfŨė„Û4ۜĢ’Ž õÆ^ūO ”0/_ûĻJä€Đ2Dąƒč}OJį€YeŲĩ6vjãҎôIû3qtˇÖ,Œt*cí¨6­hWØļĖgĖm.*Ë]ÄxkyV Åw"-Yžæ˜nĢ'™’OšH…gaë7”Ťs-;ų“Cy-[ žsė€ŧ0WÃXG-“K7ā‘ŌʝCĐŅsn^EđčDH„šÅԜ9˛šœģäfgDœCǰĩIo›Ä qŖáúž–‰tŽ(NŋՕH›Čúūø&7Ô8_WŒÄÎ&kœlëø‚€ržĐv™ĸvĮįdīv‘ŠĸôŊÃūxô*[Ŗ°›&%Pø™E¯Ûriáģˆ˛0Xčē™ÛÅŠĶą}à ÔĀâ˜`†(5-ĘĄ­J5 õęķãDÄ´ MũeēÚL”z\Jĉ?„ÅII'ČúNbpCˆ Ū'Ū5ēøû¸‡ą‡l,Ã÷­1˛ō}ÃíŠī"’÷Dģo΁%_ô‡õmá;Ëz§{ē¸JŨFk#k›ØGwî(ûģ—Ļēf ´ ۈ[ŠģOŽ}|ä†üț|Š<]ĻíĻũŅÕŗŗ‘%Ѕ Í{r”ũúxđzēÉ[%AێØÚ^X°ĶGĐOŌë|˜Ų­oŲ× É×Ė€tĐū€eø0c\kEŊ´éQ<0vV‰}ũ%áģ°¤§kZ›™j–-ĸ§ÃO !CļiKŌā'žĘÆw§āúœŠgŧ—Žōzū}˛mŒ!g%,-ēŌü‡Ė<ũŠO°a:EyäKūä3Éâ”Į7Ā€Eâ@txÁŊ ɘ ŊH~Ĩ‹ūElĘ7_ž4Ŋ}M͌/UNB•~ŨŠ)ĩ~vöíāîo‘Ŗo)Ū÷=€l|%÷v˛ÂŲą*õJkō3˙ō;ô_ëķOt]ÍūQˆ”}ĨÄ6ŦÁ´@xA9’ŋLĶtM“cM—cL'äCÚt?Æt ¨˙NˇŋL¯ŋũĶNËAâŋûū§?@XqbÅ -,x0!AƒNBØb ĆV´‚ŅbE'N^„Ø„Ė‹<|øøŅF[”Œ1xÅɇ'V”<šöî_OŸ?:”hQŖG‘&Uē”čģwߜđd:•jUĢWą&uęä›ÔŦ_Á†eʓ§ŋf{ĒëįOŨģk?Ҋ•;—.Pŗk˙Ŋc§W]>qëļZ6Ÿ:}yĪLˇŦâwŪŦŧC‹–,d¯‹1gÎęīiäÄ>ÍžÛæYsiͧοĩâíōįwĢyîŨŗ5jÛ¨'ö‡×Š×ŋ¯Ŋuí99ī†nې'üÛˇåÎĄ?—útëÕą_žģvîŨūÁ_ožŧysm9~āčÃƗn3ē•÷ļų7mj„ßÖŋŋé͍vų PŸzãĘĢËrPÁĄĘęiŗōÁ‡3ÄŦpŗŋhsęŸ~ôyĐœ’f õ.Á…’Ė1ËRK,nHCQÆÁ,3+4YœQGÛ8ƒÍŽĐ|„‹6¸ū*ŌČ#‘LRÉ%™lŌÉ'ĄŒ2I jĶ˛}úųĮ ÖtJvÖĐĻ+vöĘ̎3õ:s¯ŪÖtĒÍ4ŲTSÎ8étÍ;á´Ī=ųėĶO?ķƚolĀá XÛf/ŧônÎæ›+ ŨŅŌŦœúfŒ*/íĢŊ ęDOm“ĘÆŧØyđ/nØņ‰ūSR?,ōŸJ×Q‡2X­‚tDTMÕR ]}ĒɆōąq%•ŗo†mąXҐMVZĒ€ä’HÕ¸”­XQĨėÖÛoÁ 7Ę!]%ĐČ!Íjĸ̏z3ËÖ ąō0ŸæN[É´=+_Zĩ´|ŨŲWā öwÛVãÚ'á…}R¸a†{r8b_…úKŸŋÖZö ‚KÕŠXãæ§ˇ˛vړ{Ú *Qn9¨wBÕeƒõ  gVåĐx˛•䜍z‡ kxÂ&/‘?;ÕSŠüÆ3â^Œh …ezÛc_ēåĐļlÄ gĢí˛ą ,ģÜŗÉM›BĩÉF{íˇÛfÛlšŨŽģ)¸†ū™KĨwûį…nxrįܡ-°Ã…œMņm7<ņÆ_ÜqÉ#‡üņkãfá<俊mzûĮVļūųæ“ĩ^ZĶŦSīÔŦŊÔeŊõĀHėMšŧŦÃíŲ5ÛŦo€āɜ4y'0‰GSƙoXÍ°ÆƒķĘąx—}:ŽĐF“}zO{Dũ3§ŗĨđÆį†ģ|ģŅ?_ũē×§Û}ķŨf÷eÄnÎ7#™¸Ũ)Ž|rēãŋ¯(Fbū Zæõē°Ąęh˙8Ė;ķšoôäbÎøË:˜ēíéhY˙‘ÜgĘåGqÚaR”æ&T­î„ŊsÖīŌĀuüŖU&lŲyŌ/™-ÍDMkūÔōâ4ļ1ĪģQh¤GDæaËkÕōƒ¨Ô>øŊ/}ėŗ"ĨXÅ÷‘o(hŠaĖļÕ=аL|å+ãõ$?øąqh#N‹uŖ¸ąņjķK͉öw cĨMoōŠlú¨D™EĐ"V 'HūøŖ coĨHŦČĪ?C”ä`‚čÁmĪ~2U˛Hä*Ë$ĐXIŧäb–õC!ō”Üëäĩ›ޕˇŠ_פ毓FĄØŨ|™HMĨJODĄV‚F›˜õkŒ`ŦåiTČQÆQmĪ4>ÜQČÕõ@â2E°‘cķî˜Đ7FņŠŠSZ:ĮHĸ‘;ÕCŠÅaf”2`” cPͨŠŪ¸Â˙Dš™ŊC ې†SJžŒæ3Ļ_Šd9i…ü|eĄ¤=I(SÖÔ*ÕkLØ˛GÔAž4ŋķŅ:yĒTÚ˙ą ē8ŽBą|õjDŠ‰Æ†î,ieÅhB§E…~5…2 TĢ*Õ:Ė)ؕ\1“Āu°C]˙đ:ņĒFšâ)€)į9ۘΧ––Ž[ŅĶžu´+x“°ŽĘŪŠV:ÔĘj†Ÿ×bjb7+æ… vy‡ö–Qv6ĨˆÃū.ŠÖŠíĐre+XgûĪ֚5ļĩÖ÷á°…ļ¨~åWĨÎĻZâVÅ$sĘ_īˇŲ{(ŠËEĘMŖZŧΞļSî$Đ4[T™yZWTUs+ÉËŲíb(–˙Č*wĶĢ”[zo8Ā™ #ÁŲąI4ĸąeíūˍļŪö´Ū€ ėßå1f3S HßĨ4×LŦR#B%œ”Ã4÷Q<."å*Ö@ 1à ú†9×öK—ŊF8Á­-ķÆDUēčhã-q՚G͖x€ĘôŪ×~ĖãIæe &§Æ@QgSî§H=rĘĀYD›”ËEeĐByln=Ō@é+ä.žîųZ2†ÅūÜE?č^ôSņ3ũ'^ĘÕ°+ÃéôÖ[Me=‚ulšĪŌ™Ŗ>Ģē€Kg›ZēÅFž†NYJK%\â÷Ž‘ĖPŲčx=.ymM6S—6­é,3yԗV¨“šĮL›‰+‰š˜„kdGĮņg˛qGrŅã2Ŋ-U´ŠáˇŲ¸îËŦ›yŠ—ēwŠn•Č)€’ŧ‡´f2ķŪ)ËwĘöũn#āˆ¸ģi3¯­4į¯)+] 4Øm¸ŌØNˇÆēūŽwė5ŧnąÆ‡^@c—ÛSËķœãĒUÎŗNå& }meÛß[4­ë[ĘC[ĐO ų¯S™Ŗâqš+Ü<´‘§Âzö:*Ūĸ§ŋ-ęF{…9uõŦŖeë—éē€&”aãȏČk¸Üŧ^,Æ?ŧNŽ\OÛ,*ĶÔõūfkNˆ–ŗą}“ĶđŊøRÍĻ <#+OēãĮ/ŒžÎwŪEmûsĩ™˜ĢÄGšéŅ]OⅡ•CVĸķë÷ᎍhÚaŧt3"hPöŽĩę_˙Z×Þ÷´įåíMÔ\ė>ö˛ÕīûüS؊øŗgäņ˙ûū"éž÷ΧtéÖ:’īžCîÎÍAz0¸—Ô{×õ EŽœ;^ŽĶĩ,æ­Ëō įėå'ķi#ƒæ.oō¤Ę¨>{đĪķÂf¸|nņ€NđŌlž8… Ŧ†šC/.ČŪÎBUŽĪõ,ĻŌĖáH.Ļö6ėāb÷d›XFäa+d“掚1D[¯¯īEpĪÍAÃķĸ„ãœ:G 2nįúŽtČ ëčG÷íxü*~6˰PČę ÅĪ~Ļt„ūō)ž<‡ĨŠÚh ‰Pë‹Ė˜Ôp•ŠŦ˜œ†ÜžĸĒÁ  HØ!?,mÉî-›Žd‡¤"ß h|"ūIŽč'qpÍâL…ŽęÚŅ'ąõņØqqČŊtČ,¸a &ČķŧޏĄ ė&ķŧĸ؁ ¸Áhô‹¸”φv,ÃôOĻ˙Ļå˙fÎĪf1Ãnîŧ í ƒiķÚëŊl Њžå*`sļÔ`5ēâbž‚Í)ŦÁ¯DN4H¤!‡üęŨœb'öJOÜägeV¸á7°1bē[…ä΄×äMŧ‘'D†Ųņ˛ąš‘Mä1IĪ-FîÕEF/ŽĒ7Xe!ßA dMãD*zMÉvnßŦt N˜bĘŠ$īÄk˙VŦ ;oFĀō  FČPŠūpLŦ OÕ,<‹ iōķĀ­JöĸĨf ž‚ō8ŪÁ–Q4'8 Č)¨aLĘŖ+„˛ģbĸ’ũņģâ)ā$(%ƒ•’ãšR/žrĨR4ĒrMˆF4˛rL2Rčž’)˛<Č2(§ō,ą+3N6‡ēĄƒ>ʃ¨a ÂL×:ĮPā"qį\Ŧ-Pkģ)´Ēí ­7č@ą‰^2 dNˆp&ąPĐPØŌP ŨŸŠq–Ž‘Į†Ž˜ŪĄf€jRŪ! DĀ r( š Fäš@ X@t4ŗÔR4… ’Ā.Į€ Ōē‚$LR ÆĀ6­ū Är zķ7›` ĸb†ÆĀ8‘s ”“9:“ ĻķĒķ:";ˇŗ;9ã;ÃķÆķ8ŸÂ<—S(›ķ9Ŗ“=;ė=ąs ´sÍĶ ~˛ČāŽŽ@ Hâ 0Ž3)ŗ¤ļiĘB ĢAR“ą8´xüĮ,ļÁ "pĚ 'n­…ŪáĨĀ.Ũ‚mGŦæū6IŽÆP×Ėđˆ,3'yŽķ-Īxt´l2(žaē<ÕE(ŗr 5$¸B'CØčœ°lM8m:MC8ŽÉžTJ%‡üČ|2-t˛ô@p†K§ôKɆKÍd/Ō6CįI3ÖŧA ŪaE{(D ŅR¨ Ũ ŋÄí— XČūâ‘H‡ˆļ†Z/FwDí)vĐ~qTŽG5 ĘA5“ąJDnæRš`SŦ‘› †)ĖÁĻĸ#I[lq`Ļ-¨($ĻĖ8đb.Í=ONIc2bL E¨´*ŗūxŠ_üÁ/đ´•,üÔī@h¯X6VPīē ÄīŲlô4‰ĢōđŠƒÔGī'ģŪâĒ'¸Q %*™ DŒ+b2Q)ūČN—"öŦ($.5ĖLÔŪʛ č“8å^ ČUZpDnGQANW=Íũ„Ž ä“Zķ’Ččšūĸ-Ū oĨU Ã/X”‚¤ŽąL˛B52U4]“4sĖ4u4-UŅ0õÎūruS…âfŒ.+Ũ¤_pOĻPŋ´a…Ė&Õ5С¯ Ћxĸ0>­ž|ņŌT„‘ŌĪDÄEĻ\tÖ3ßÉZÅ%qԈžPd)ÕERHsRH# 4Ža 4N$mĄŨX%ņNļCM a…ŽÕPĮ  jŲVC%lūŌҝfč„Ō¤_ÜĄSōCVdy[ĢĐŧ$U$ģ.ˆ% ļÛ^SíÚÎDægjĨc/35žŅĶLã2%2dji‡ļ!î,ØgîĩîŒĨg^”“†Ļgȕļ¸į3gėZßvœb˛„¸•&ļŸĀVx‰l'+†ĨÖ%û|ūúĖķ¤"ũū!wXVū "‰žlį&ŽSzˇuâĸLŌĪÉĀULW¤zcPI9éxĻi —j¨u÷Gˇ˛ °d{öqŸ%eW“ŅĘvelëë8’ė.Æ An=8õ zÍÄΡ@"ė‰l:‡…nŒJ„&UŠ{D3orÛ ÃÂ0ōHlÚ´6ŗęW 7¯x…Ql'’‰ÎĘ#ÉË+¤÷2Â÷ØHæČā3/_ÄŌõ—†€“ÜØã2ɃOi?q.3ujēRW*S†%4ƒ7Ŋ"u•W{ŽŊ$ˇåæ6€Ķ~ۊqJ2žfyĶvíĖåAŽ‚…ņւKe6Ąw_AňuĢ í(z<ūčđzÂ΄vv:ÉVŖ˜ŲH˜ÄÄp…;´Q-kģöC\Ãöx‡”J ʎ”¸…ŌX;÷ūĒ*i3ōh4ŗÕđքæn‡‚ #ƒŽÅŦƒœÂ•ģ ÉnŖy„ĪŦ˜‘CŒdņi‹ˇ‹/U–ü÷ +ˇ XŖŒ÷ ĐxßĀNw^ą-_ß ~ŗltYŽōe¯„øo—ëI䊺Õ,XDp×G0–ūĻ•„YŌFĨ­Ø.ë uˆ×đĮē˜RÅvŒ°ä„띠Ąâ¤nc‡CęŪAš-lũŽRėv›ų¸ęēĸė8ךj-‚ōgųŧaÆ@贖ų×Dø Ũ9w“ŋ‰qūĩؗĢŲ[И™]ļŧ‚ÄŞZíĐíčcšM:ĨHĮ)¸ÁÅĄĨꀤRl%Ŋš¨žy,K6zĐ2ĩ$cãˇņⷄ[RĨ˰Qe’œaú’]ƒ’W\'RŒäGøū9}§ĐC@Ymíc 6„&Ip/ĸiöYåû˛•ęÆYĢé qžúãO22†ŋzúĐt÷yëĮĢ˜‘Ɲm.rW6¤m.Ļ_&“÷EĩЉ‹Ēŗįuŗ1…ŗ?û*@( ņN{ŖšĢ<;tAģĩøĩG•][´¯Ŧzí"K Õ×Pҁū‚JI™ÎôŒD†í° UŖuƎ͙K0ö†û Å0ūž/sžu’ÃõkÅú…-Y€i#“ŅĨĩ›ŲĘ`[­ČĨU ´Ļ_HÆÅF†Böü°á^dÃëtčŧiŒĸŽØĄ´—Ėŋķ"šŪá˛GMˇ(‘ČÁ)JÁJĪ<ŧá&t64öđwĸKėPŠÃęŒeE40‹_æ„Xn]nԌ˛-äc;œŒ[‰˛øą_|qų÷‹9Ü5Š*†É8%!ÜÁÂu `cĨâ0œ0žÁq`ũÍhŌØīá|ÂhĀCž|ŋŗVܖ˛'üCà *uĖQ™Ė=ÛĖÅ;ĀŧĖM2N„dv"Šĩ9W‹•†šCoų4‘Æū9Äy,SJœ¨e¤sCÅ=–ĪZ„wqԑˇ˛ ˜YĐ)sģųy™˙Ʉ,‰u.ËkÖČ{B´1mĪÛŋ āüûŧ)ÄÔą!BË‡œËũʞ܁Îû¯Āŋû;jßÁŋŖ.ÃÁŦžęąŪ¯ āú>wūHâĨ´g(Ô 5BŊšJ;ßĪĸÖkŨVÉ>ß!žâ#ūœíī(ß4Ū3@7ë˙ę?đ đ ŋđm¤°“@ ĄU.Z]uĨũĄ¸! ļ!īöا įŖŽˇYOÛ1šįK#PMļdôšąĻ—E{b<įV_Š$š‡ú÷Ĩ5•Ũs)ČāHÁĐjyxŸšvŸčJĄøĐÛF>īũaëŖOŌūāŖOāG$„á§Ü,ĘŪˇĨÎų˙AĘŪ,Āû“†ß=äīŪ>ˤ5øuĄÔø}ŋ÷ŋũå˙ũŨ?ūé?ø­ŧüĒ3Î/'÷ œl{ĮîŸÁū*\ȰĄÃ‡#JœHqbBƒīf4øm›“CŠI˛¤Iƒū6žûöņ¤Ë—.ß9ų–QŸÃŒa괘ķßģ•Vpĸôé“[НH“*=š˛Å;9/žķvtŠÕĢX‘Juâ $ʄīŦt]Ø3ĢŲŗhúÜį“Ģ׃)­ĐLxĒŨ…^ķjÜ{Po_žíË€˙ÖÄöĪ@âëŪ˜œx€;ļŌØ`âūwë+>Œø_i•Ļü'˛âĐ—öš:á5Nˆžø¯īŪĀy ÷œøpÁƓ#_ū7Ŗ_¨DëãæÅÆēĐĶjß~Ō[‚ßČl[-ŧ,÷ķ.ÍËr7ú÷fqŽlbĐ|ôīÆĐDØSũũŠ8•5UP6ŠĨUîũ§āR)}sTvjŊŗMU Vh!Y>‰õtŽÅÖP×](bZRĩĩCqycāWŲíĻÜoĮÁøbq˙°ĨXb˙°Ŗ;́´;öÄcŠe¤X‘ąáČZ`EÚ¸Ö?Œå(Ŗl IįN܌’y.2Gã”`~)fŒcÎH&™oũôĶ]ëI¨Æ6üąč߈ūtîDĐL ÖŠ§p_Ĩ垀BTÖ7ôA¨N?]ƒ:`ŅučM†ú4ĄPuEžf*aPŽ 5 Ļ™†Ú]Xc)ŠŠĒęH`}įVCū°ŗEWįøä܇}gЍO"ôŽ5‚U#FŪ ļĪS‘÷NšÖ7,Qû¤ÔÛ¯¨A Ōą(6 Ō¯aû¤Jēb¤+ˇĐ–ĨJęäƒ7ßđ§tÅn¤(‘›Ģ´5^įmž)Ëė°Čîģ}yk_lIîŧa›ĐžėH…kŧ#›īA C•O?ūŧûuėpƒĐģ9ÆęÍ í*™Đ:ū­\¯ųĖ2—T3ÍJâ Ņ7SķūŽ@´ã?,}#rĒĢ¡%\ŒūÃÍO '-"vž~œQĶR“´f?H¨#^' ‚uöi֙6čԊNŠöہĨ!Y uØ,ˆCÁu‰2•Ę7tUÔ|æm8\(šĒ8†Œnۜ‚.ŽøäŽ—d^IFæO9+īá ŗŨ_⍋NēäĻ—^9åŦ¯ē]°§ô‚ Ū|cÍFė,+áßHŖ}QšÃ6Cëü,47Ÿ¤IŧĘlüŽ7.īô8?_%ŽÕß8¸@„ë}žW)æ×)íũvtĩHÆJž˙7ė”ĶĮ8BhūÔÂbôÍÚe;gÔũîÃĪūŸ (€Ŧū×ÜL%7ŋ….iûž÷Ž5lCd‘ļîşhu^Ņĸ‹M 3„”đ$3aúBˆz^#YœRøBĒĨc7Œ!m¨Bwŧ+Z>œá a˜Ã8í!7ō‡:"Ã#œĖ 4ô T\¨Ã*ÎPˆĖâAHD^‘„ŽŠ"éBÅ"‚Q-)Dámõ›|ã =° ž°oäî)+ųĨx„HUÉ&<I ›Ÿ¯}>ƒžĐ°´AúŦf×sˆ#˙!=%aƒjØĪŌ ˆ•=LSĮ;Õ:Nž%!ô#AŌåGNâ$ę°I€’6K-oÎ9 )Ô pSÜ%ū ¸ĄēÍíC•ž0GġW1$w-¨*ÕDÍjZ효ĖĻ6ˇÉÍnzķ›āôfîŽņ´Ÿ4q%4Z8×ÉÎvēķëLįJlĀā`4@™6žq  ØQ•ß  ;Ôņd"r"=KĖ!ƒļŽJ Ō •l"­‡#ä’ 9¤ņYHJú„':Ũ2M˛-d|øÖĩFŠ6ŠéũĐEøi° ,ĩÜžž2ļáícb)~n),°čR¨IKQ13ä@e"ujlĒ­ļ18ái¸‚œā„1pÕ VĢXĮJÖ˛šõŦhMkZ[VļZÁ­pmĢZįŠÖ¸žUŽwÍkYūˇđģĒáj`Ģšā„xÁ[ũęVéĘØÆ:öąėcÁúÖlõ=øÁė؃Đ ZHÃV°+< dpÂfÕŊ…(Æĸ6s­Đ4*´Ė…äH…¤Îf4EŌvg9{ȝŠē§ĻĮW9ē)””eÜŦÜåi‰ÁZ0ŗö4–ŅFlR3ÔOXļĩš§l Ĩ@ä6đFUt#Ú1"ķ*¨™!U;žQƒntĨ#Ío~ŊÁßūú÷ŋ°€LāŖŋF°‚ Ė`'¸vū}đƒŧ ūRÃŋu<°6ēąßO¸Á ąˆGLâ3¸Ãü=pfqĐ|ę 5ĐÆ6*ūŧĪŽ°ëdŪ€.pa{[Eēfļ‰bfSŧ›ÍFĄų­G hų  ­: ;2Wuî[_@Öf&ā‹ĐÕüQ¤ežƒ ˇƒRQúä(ME (”P§û咈BR9jëg…˜XŪ3zZÕŠ&pŪč'7mÅhu:įŅ†´Ŗ#MéI[úŅØ´•5+-éNO͜ÛÔt5# ęr~úÖhO69ÍęKˇē͝ŽĩĢg kZËĶĸž'@+MkđŽ&FCĀ„Í?ú0Œ‚,dĶāVfˆ‰ ‘IRšØā0Đk@GMĶی*D3OžYŠH8RāFnGūgA3#5õ‰5Æ#w‹$/uBFĖĄJ3'ácÉōœtĘĖžüä–&5āwí­“^Ö˛m g8/Ņûnģ=+™—¸VĖæg¸Øä 4!hîĻ5”îļšl&xÉķvō•Ģ<åR –ZbžFŌü†1Wy ëâÁŖäæ1$čŧFޘm!bÖJʗÎrˇü†MgúËŖNõŠ[åUĮēÎąõ -Ô +OËžŠ”‘‚ ,pę`3äyÉ'2Ɠ‚VšŌh/Lƒ2ŽSÜč4ŅãM^†|¤Īėđ0Ō{b2m(’ uû5Ž8Š„6ßøåG2ŪēĨa Rj÷Ēd˛ūōZOØÕČUî‰~ķ ųT§"¤gØÃĐīĻx)mB“Ū=)šyáxŸ•Öˇ„øH5FäR­Đä Ū(Čg”tšƒHßRj¤4€øŊû>1ĖôÎ÷ƒ€úL0B™ÕLĻ4’ôu~ļæe†)sg€t†ÛšS~”ąwã—#pƒ2Ef‹Ān—qö–”ĸí|œį¸fļ@ė5yÔ? ˇ,¸4‚h9âe:Āt‚īĄTéeqȔ?ȂZϧ2:‚Aƒ–Ķ)Q^<˜¨R"Ļá˜4đĩ’™a†QwN(}N˜#ūuw.|gnBãFÂw›Ņ„‰ņĨAeÜļ+’1…Ūˇ؀mø+ pZČ:âlNh…ŠW €‡‰Á5Q†Ë#> *Rf h{m–K„ą÷ ÖÁ3˜5čƒÅ(Š×Ô?EąˆŒØˆNŅf´Į‰˜¸÷gL…4ŖØpQ• CxqD˜Š$Á7Ž‹`æá}ü;ÉÆ(ú . Ā(ā ūPņ~˜ls€ūp€æā‹īÂ2Ü¸ŒĀŨXĀ(JÔ1،Ë  D ŨØ1Æ栍“Ņ1ŅʍúĐZūŒ ˜„Lr]ĐHÃŗ‚´Øˆ-Ņ^ģ'‘Ų%‚âU |S{ p'ä%Š™ē×'0øN’‘cƒņ…ƒ]Ąƒõ†’Á7Ûp)0Š5Ė÷HPoōčvŽį¨ ā‹Ę¨āČEɏų;ĐØ“Dų.vąĐ¸”LšKų.ų”åø.SŲ”Í,ō8•ú•9‰ę˛ŽKéÜvy˙pvC“šÃ +ōz{–ˆ&X“øˆ›dJ“89ã*o–‰?Å 4ɗ1)ŗgT ИZ6’q"™‘™žwƒ}‘ƒŽˆIAø˜š|~“û( xâëū§[Ųˇ+û7†Ž9dŽÁvghĸ1›į‚n“Q‡ÜfQī'—Ŋyŧrm@0˛ų„ŦiÅā„üwP“!3ØöčĻ˙€ÛâæČ1ĒÁ œS•é^DØSxÉ{+ņ‡x>”)5—ˆ‚‘fŖ‘!Š6ƒ @š&Ⴁ^xs’öŲLR%š:ã„2 šĄŠ{8Œ¤ō—Q$Cc$Gấ ãĒfÖ4ī ’į„7’ąĸ@ōl‘$Øpëā~54ĨfŠ% õËɁQ Ē”;ã—}4>ūXô3­Dy4ɗ+á—ģGS7i0•x(§Ōū̧‰s֙wV¤gcŸ=XhK•žZ—š’™Ų’›9|Z*gŗøĨÂåN”R°…QH\ís#2ÕH‘´dJ šŽą[,Kf)13ā û¤&•fÃ&žÚúʈĸjžüų¯Ļ*‚ĢĨúãĢLjĢqōŠ‚õšą‘C™Æä!&i¯ĄĘqbĘĢŕ´ČW Z„ŋ÷Š! īŗFOf{ļh›ļ›å´ 7°0  K 崋K¤Ŋ! M’ü ‰Â°Šķ({6k xg+â˜]‹’Û'ë´â*˙yŠ#˜+g;ĢĻ­Ø!ãŨaaĄ;ēĸū[ē¤{ēĻ›ē¨ģēĒÛēŦûēŽģ)&`ļ<°9Đb6p +2§:˛ŽJ„YZ“åŲ¯?‹žA{ˇB´ŸI‚ŋ;ŧ5ųĒx&)†ą´'%šŸTK‹ūYądÚ:‹‹ˆfŗˇ ‹^9ŅPDŖ5@„%V”VīģXî;Vņ[ŋô{ŋķ›ŋđ‹ŋûĢŋōÛŋüŋlŋūKĀVđnuĀ/°Ā(p#Đœ…>ø´íbp'(ƒxAžŖHŽhŧĮĢ7€Û́2¸†Y)ŦHʘ•ĸ¸kP{Ч'ŦaęŊcšÖĢą/,‘ŠŌeZĐ ĻĻļB<ÄDœMōdMß Á>Đb40ū5đu"Ē—ákJ i@ĮGŧŖzžŪ“žS|J9@Gģ°Ņ›‚ŖĒ/“2œŸRĢŊ—Ëq“ģšJÃã[ŊŠ)™,Ãok@ íb§Îë­$Č0äŠB} ­\Ķ:Čã*ČĐĘĮâĮ6ȇÜȄüȆĖČ@“ȐlɗwSC§ß qD´#ŗ5P ēŊY†/zKĮ,ØˇYĒk¸Û'ļäS(ü?VĘ]XššgÜgMu*ÉÛËĢx‹Ã ‹šŦLŧļ;ė8`#ĐLŅlŌ\Í;RÁ2øđcĀö#ĐĸdЍl^ōŧ<ŠÅ+¤fĻÅÔÅfÁŧpÆĐ “ŌûūK|Æ´Q{7ˇšÃ*iÃU f${đ,\ÍyY6ÆĄ}˛/Š’š1q1h4îŲs/ôs9CĐzíž"=]Ōm !ŌŊŌ3Įs.1* Ōŧ(¤)P‡Z  ƒÃ"!lo™aĪēA(ĪĘRī PQf-ĸÅÂSlËrf°VĘÂE%Æú,ąüœÆūŠĢ—ųŸ‘ß;.; ŧžš&xņv }Ö/i&im˛;8#Fb:oNeÖhĐõÖĐgĸ×à Ņo}×ņŅÄAģ(™°Šė…]Ģ8BK|ˆFČ×4¸ÔëŖDOe;âRL}!ōĖ]%XΌūKƊcÆWM1œŊ˙|Ėnœ ÜpŦ<)rš$Ĩ9’‹OŅMÍKZÛ!/:¸&ˆÛ÷yÍxŨ×Ö +c\bžĻr,šIÃŪņ{ž$Üw#‡}Ø|Ųq)L+Ę9â˛Ô=Ŋ & ÕēË‰¸ŋ”ΐ{ŊĀüËú\Ã7qšäņ9Œ uŖÜ+×]P:Žōß÷­ž¸āũŊßČũtŪ7ĩr*<5āĸā čøm:ú}á^¤•§áž8^ā.áčU ˛Ģŋz*~–á”fŅĸDJ´XKí Kæ(Tō2Ŗá)*Í)ŸÍŪxĪė•ĪWŨ¸ØkĢ ĐūēúŸąRÜFBū$ZĮßŪáŽØ:(á.ˇá#ŪåŠÃå ŽåŽå7ŌåwÜb^å^Î:-ˇå•S@qŽ:u>9ü=æw>į]ÎÜ Įj:E‹Ŋr@ŲáģhÎh(azAN×~§…ūG->´q—ãm!…iŪū“Ė­LTÚĨ!Yũ¸NÛÕģذ]ą#ԄCŨĘ +%b?!ÜnįԁApļĢ¸Î<‚ذĶI7ŗŽēŽ5ŧNëĮžöŖėĄscâĸūŊ\m+xōĘÄ7ŨAéÜāģ3néžģi>R9Zõ}ÛaC˘čãĪ ä<+ÚCÎé~ūÚHÎÎJn"Ā÷€Ŧī:`pŨÂķ$øŌ1רŋÂs´ ŅFũ.xQ­3§/ũ!ƒ$cČŌÂ\ÚŌå"|“É"ƒĩ!ļĪ!­ ŖæĐjŠëC8-ˇRÖŨBƒáŅŽëx­ō5{d”pũ°_!K;×ōÃ'ØcŅĮ‚âŋš#_kĖ9ë9"éBÅ7cfˆ‰fW#×"õ(Í?‡)īxĨ‚éîĒÍĨéEęm<ąģW@c3 M ī ‚×sÃCF˙ATķg ŠĖáÎ &ŨAv‹÷üR0ČeâŽC-FØ1ņyŸ'Š˙0ooDS6'ø4Ÿ,9Áō0ū?÷€ŌE„ųģø•ë+røÅbų‰ŗjÔ/›/-ÅÂ6%>ÚĪ]žI¸918ƒjdāƒ|KQ8âôīņ˙îÃWέîėÉîũbÕĄ=‹ĶKÚĄ>íK…ÚÃ.Į68šˆé .PŲĀa$XļŸf+ƒSk•ūR;­&~đš–//Õoŗv,Î1ríĘūPžō/E˙?Á˙œûŪũ{÷N`Áė,čĪCƒ $Čnā;nߜP„øoĄE† /&œč°ãC‹SLÉĐ%B‘,ŧØP"B}÷AŒYķĨH—-/|grâ?”Iœéķ›ozD*ĐITĒYĩnåÚÕūëW°aŎ%[6lR'ß8j]kÖí[¸qÅNe[ÔcÆ1måîåÛ×/Õļɰ[įOŸŪŋ‰˙žƒuįB¤Š%ƒ-J×ã;oV¤z”Hđ)âÉĄE‹ÆŦųag‰™AfŨÚ5Xī ļ5:[ĢåךuK–¸ķ]ZÄëŪm™Ņ†Ü‚IÃaâčj'!ÃíŨ7&d’`ü& ™m›D/8†Cšu9laņOãjÂ3&?ŊúõėÛ3z_žüˇ1”@OŊ->p>ųüCē1¨ŗ;í¸ãožņ,īŧôŪY¯Ŋ÷ƈo‚ÆÛčoZX"ŒŪÉN‰w #ģĄŗ1 C,đ@ˇū°ŽžŧBũēûn>ÕPĀ ×3°ÃdĐAü"ÜoH'¯ p@ od2A„Q­_ŠŽĶd‹ ˇŨŌTŦĮHjâ…Ö”37Ž Ōhĩ9ķ ÍĘÍôÜM6ĩNƒ,2?á2 °ëZx''B/R­PHG‹íE 匠m4‹tSN#3“ļ‡žrŒĒÎ,íôÔĐĻēč*иŲB›føBĩ,Úæ›k J‘›ŒŦKq›Süƚ‚Âۑ×o2ņŸŒŧķ°oljŠduí•ģƒ5’Øąå#o–mÎIĨ}‡Úc¯ũUÛë¸5ÖÚdŋ—Äg¯3ŨoÔâ&›5ÂÕ5ßdtŖëūžUöŽmœe§ÜiĢ ˜ģ`ŲļXo} ÷.zļˇátĢ]ˇām)ŪÕâyføÜj1RW-`¯s F/ũMTkŪË"‹ŌZØfž9ĶĢNoœčyhļļēnŖF‰æëĶô)ÕTĨ :°Īí #MŖÖ:ĢDí"“ Gˇ읨lËĒ6ŦÎ{íŗōUŽ Á،œ ÃëpélF:÷o‚¤!É"Ág˛nĄs˙Ž k˙[9Äw đwĮšō—ŋHĄÅßi\8‹ŧŠËsÃũæ|ĸĪ÷(Wå„ķFĮ˜Lŋ›ĖUG8‚Zũ˛vÜüī,˙ģđ‹4¯ČqÆ˙}ôūšJĮürä R>ņÎ}÷ü2ëgJiokŽĪŌ2Íf{í˜ "ãÁi>Íĩėō é÷Q•ęčÜŠŋ,ĻísėŠ]F5ŒRØ˛ļŋšMJSS“HĻđ„ĀúIÄ|œ •mÚT*÷A°güZ¸"œ-„G8ų"Câ<’“ôœ02‚zŒ;ŗ‡¤Đ0‚Ō_ĶĻæ´ÎČ0'‚zČcLCÅqÆi‘Š!Šbāčp…‘ņá ID¤ ņ!EŧĄQHåiPĒ2–)LĶž¨CžĐ!A" ŗÄzą^ŧ‰(Fē”Q‰al"#ãÆ)ÂņˆVœ#ųbËøC ŗÉ mļv4a ę0äūnžv›‚„­‘zHfž”B’iųĀ`&í‡Iļådˆŧđ5\A W¨@đĮ§û¸ė#™īš€RL_ĀÛÜŪėČŋČ7*ÖūŅ~‰CC4×čõú"˙,\ī>W§/ūÃ;zšÛŅoĩÂžĀ¸ąLčÅ“m˜úīw Fīđ†ŋs–p“ã?Øč" S‹ŧ;Ŧkŧ:?Ö̉;ąģŸú×ĶžÜËǧģĪ+%ûģ;Eķš…ū¸D@¯Ā¸čS=÷CAøË%{›ģ3‰4đsAë/™;AŨ+jŲ)˜•°<lŗpnHƒmÕ{ģ>Ģˍŧ‰ų‰Ÿƒƒ S› ü“ŊĢ/A ŋ!ô-ĘŽ˛ĶÁ/$õ+ ’4¨)Cވ?Ŗ;ĩą@6늨P4##ÃÚ{k¸õĘ'v臡›Ã'ûđą%tē´ģb‰ŧ÷‹ @cÄ*ŗ”[Cž ;Y ”@ņÛ¯¯ņBA4”Ë°Š› JüÄ6s=Ģ‹Ų[=<”ŧøŠĀx3EĀā‘°>N3¨ÃČ6YÜ l`‡'ā•ÚëŗœBŧëŗ6¯b   ,œ“ōūÃÁ.,Ŋ/<4ƒ‹ĀVBL=öSÃfÔ=ĩR0ļ€ÃCŧFÃSnȋ]¤šŒ0%pęƒÂ™t”‚ģxëÆ˙B4Œ@Į(ԊcÂWjžÍ’AŠē…džKž‡cÃ\%ŠĶÄx„$RD›{ČS|ų 9V<¤ô¨0{˛ €';@‘ĖŠÛH-ƒ"-K!Ŋ*IŽœ1Şˇ‰!’Ė  1”Dŋn"ŋĘØŗ-ÜÅyô räŽŦ#•÷’ūS¨Øh5ãžĸ臂ō!¤JÖpļŠ’Ē8Ô*1AŠ$‹l|´4lģRüD7”A™s;ŠÜ ‘¨Iß ĸɎē„Kģ¤ ūŊJÉģLŧd˚ÜČŽÔ “4ŖoÂv0€—Zˆ’„š´É(#-ęÃn˛Į ŒAĮŖLîB ¤pĮ:T1œАĀĻ›ŧ%Z,Î ĸŠIKIéĀ0Lœ8ЛÝ8|ĐšˆPËtô8QĖ´œ=ųTK-;RsŦŋ ĸŋtË*˜QdL­øPæ„Q%Q¸4ΕQHMRũK…§I‹€ô€ôÂpQHuLūی°ŠŌbÆ ŒūHŗ›­û>a][Ûä]cUPŠ”Ûõ ËēuրEœ;­7H–ũĶPņ•āŪ_”Ā`žaĀt, Â8L ĪpŽ—Ķ2Fú+nānb~b)&Ųé:đã4‰âŪb'æb-îb0>ĸE1“Jz›b0ūb5†â".f‘—‚°œŒh‚ÛEÁë`‘hAeáęÍŨCSûŠ6ŊŅû^™‰Č¯Ô㇠YÄđnPƒ¨Hi˜‰`Ę@ũi!,ŠĮāäËĐ)ŠédPöäPūdQ>e ë 4ƒ1‰āČ ã4r›Š8ŅĖČ0Äl=ĸc˛Re%Kn˜Os›X;`’Ėd\ūKeVNæ]Væ#SegfæU^finfh~æiŽfjžfkÎfjÆRÖ炍ė2G˰„ ‹Yΰ|"KgSgwngxFŠužįw–įzfg{Žg|ŪgzÖį~nC‚X^%嘤ˆ¨Ąƒî˛USh„^čHkhˆfh‰~č‰NhŠžh‹Îh‡ÖčˆĻætžŽ Z‚°†ķũBüųā~ĢŊ]›­ ´+&áFlÛ=VD>9e֎иKŪ‚Pož‰jĸ.jŖ>j¤NjĨ^jĻfœĻ~j¤jkX‰ĻžoІTjnČdžj°kąk˛ko¨Ą.kĩ^kļnkˇęūV3‚ykēŽkģ֕‚°o؁¸č—[‘éM š,ŗÛũa=5ėëmÕĻ—Ô.íÕNí֎í×víŌĻ•mH˜„™mÖÖmŲŪíĀŪ†jāíŲí|Ámoč nŅÖí„)@ĶŪmÚîíį–îáîčžnėžnë†ííŽîâ&mč€iíîĻîë6oŲFoīVočfoíÎnÕNoÕėnĀņ&mávīøîn×Öīöæī÷VīŅļmŲ†ȁĀČЁn¨KÚGĒÁc•žOŽē?ū žĘAf<­$;ŊiœVä€â㠏GŧåšЁP2h2p'h‚&˜qw+°'h×qįqˇōīqĮq īņ!7r ÷q$?ō_ō/ō)˙q(ōŋ>+P*÷ņ!ķ*ßq'ˇ‚$¯ō!ŋ‚p5°0ķ+—r'įņWh+°‚ŋņ>Ÿō&ōâSs5r%'ō&Įņ0sD7r,/s,grG_ô —ķ/Wô1ōFGķLt@ŸôNg'¸‚%0s/5—ņˆō¯t"×ņU‡ō3÷ô9/ķYˇtXˇuFwt2—õ]ķXˇrWūįõ`ōavH/ō˙--°s7souJ?tIįtHˇôDô_‡uPĪöMspŋvqgôØā5Øčđđˇˆđ!Léu^i˛jiĖ^My4áûĘ`ķâDVl ÅËŽė~/G¤Į­ā/Іšn ˆ¸k‹kZŦ•‹ˇ–‰jáņ/ĐjŸˆ¯Ūx“?ų§fˆ´&ęŠGy—yē^ųŖ€yšŋxmЁāāĐ膘›Uŧã<^xųēp÷‹…ÛpK3xäcPCļiWx ĨÁNḃŊÃ`@9˛Õ@Œ¯÷аŸD˛¯ĐÅWnŧūIŒoûŽ(Ē ŧÂQ{KĩWØ~{ŗ/û–ë{Ā˙{Ágšŗ‘ā°‹øĪâûÁgûĀ'|ČwüÆ?]ʡaģ@ŗÃ2]Ö]ÉüÎ˙üĘß{¸÷ûȡĀ$" @p؁úNHD@|Gß=ĻÛ>æÎĮÁ˛EȤJ‰C áņ¨$qãEVÍģŲħh"Æ]=ĻįW~îMâčo~č_~ô‰°ą{æ¯~Ų~ë§ūīī^î˙é˙Z>ũC4ī/˙õßūöīūņ7ö˙÷?˙?ĩ4Đtúß˙đ¯ųˆ˙ųh° AƒëĒãvåŎˆī&~sō.!ƌ7rėūčņ#Ȑ"5žûÆââE‚#W˛lųņo)œéō&Nūj,Ųâ>Qzŗb3'Ō¤J—ôyĄĐwی2­jõ*ք5cŨųī×ûhūK 5+Ú´jU–-ëäÛQ0e"4ģö.^Ŧ(ß9d—2nŪĀ‚Eî›XėŨB”mŊnė˜#ߋŌÚN,Ëø1æũ•Zy§?ž3“F[rôĖŗĨ­ÎŊ8V(ŲÕÍĒ~WôiԲܨĘîŊÔéf˛ļyû.Ž9t؃[ej5îHā„Rh`…úÆÍ;H|ķ~)&!†%’xâ…(ƧŌ;ėDÃA^Õ÷/ eԈĒÕčRkÍļŖN<ŨhTvu•uIjXOAUĶT?*9ĨKËuUXĖŊÆ"lTzš‘‘ĶU§UkĒ÷%šÖĨŽiē9_ߐßvRžŠdbīŒ1ŅB”Ũ™—?}6cgHū)ÛY§ČÖĄ$…ĩåYm:G[BÃáÆ%_WØŲhfRn–r:ęA=*WVrą‘úetnÁ•Ņu@5‡hĩÚz+Žšęē+¯Ŋúú+°ÁōÚԐOҤ°É*ūģ,ŗÍ:ģ“:;ąŗÍ1 ĩŲŗŲjģ-ˇÁ:ÃÎܰsĻWŨš{nŗ1úĶ>ũpxŠTšŽ*[}Ņ)é¨Ļ —ĻŒ=}ķS‘u:oiLūÄ(‹Qܨ•Zaųčž/ė\˜ÔĢ‘Ŗģ1Įī_Oû¤Į%›ŧą>ųœ6ŽJ Ņt2Ė17mAWl͞ËČĘŧŗŗ˙,”O?AÆĸ7/l:1V‰â¨žöéAJRĘ’´RļÛŅH¯ܓC Ŧ5š5Yė0Ēcv 6­Šyqk[^jbŠq[8w†pĶmwŨ%}Z֖wĢX÷ßx ø‰}rãÍītāārîxã~CaYëūĀ´âQWFøäKūųã>/d97õ%qhĻ(zM;=ÆĢĘeMąe50e_̍ŪN §đîŦęäWį&qđ™U;FúÚÕ<ôœƒyčÕS_ŠJÜØĮ–õŌwīų÷͟xøĨo&öŪ_¯>ûā˙į;/xbĨ­ī~ûâĮÍāSAÛž}ōŽR›o4aQŽ;Ô;¤ą“ÄXĢuRģĖPf5”8dvü ›¸TŨ]0meģŌĩĶADņÍ-fãW ŌˇÚĨį<ú_Jĸ XNPÔ¸čD§úŦ'ûpˆ"(žÍÄrBĪčŽ8ūˆpēaŒ&B'hi,}ęūbzDøŧ0|^ŧßô6c-\i&q9Ęķ—Füyn'ÃŗÁ¸Æ.ʑQŠËGA8d'Ž)P;üŌĸˇ! 42ĖŲķ’Ô¯ũÄjšK]“捕x‘LÛŊ’%×D뀗ĖJÅNؓF‹Ĩy:’8uôŠ3˙@Đ*•hŽ`C įÔčŽ8DŅad!°„ĨB”XVî˜Ą™:”h!?Wä%+•øÉ¤ˆņ6—Zä4ņš‘lEŲ\BčÔ}„Æ›ßĉbB´ė mė(G]öÁ˜DŌhj=ŠZnøÉs&8ŒÚā>ųyœž*“ŒÚŪōŖ2‰%6L-ūmųJiúr•ĪLˆ øØKiÂ2—ąæ. âL%ēķŅĘG2ÛÂJyT‹= éA5ŨÍ3Ļ tcĒ‚´(›î‹ë€Ö;ŽÁS¤“•?…āÂRĸh†ž;ÂfīI”€U$LĸĘeP÷ĐĒ 0“ĶR'š*Ā:-# U• I“uŖÁ´h0/JŌšNTšASw9Ă ¯C9‡ĩi– `ƒîė ˜ŠLA´æŠ[œž›UeŒųú‘ĖÍäX’UĶ­˛TOū) Š ~ūˆŧ´ÕŸ˜ÂÚgWb)PĒąMA_–ÛŗŨV) åPH 5s–fˆ‹í!H)ūj€—&V•šÔe,]ÚŌčētŖŅõŠËđà‚¤4ą>[ßÚۍˆĒ ãEŠŠI\‚ʧŲ3ßyVĢ>ą#ĸëuš_č䎑•˛FöôÚŪ¸w$ÛÆW.˙"¤V ¯ŦĮ#­‚ÕD…:Š.ũMkf†Ø'sĸ‡+ąŖâUå‡˙1bđÆ2‰Š•æEČIËʰØVdY.—kŨ'ˆĻæqũrēZžfn(÷†ˆŌˇŪ:ŠĻĩ,ŨVŅô2X㘁/ZÕŗ…'úŒōgšæP9'u)Ģn Zæ–üvĄÂu¨s< ¯ÃÃI4ņw“bGŗOxÆå?  ūĘļ†x‚Ž.GF  ,ÄīÃd´XK ļxE1)’:ÚŽ$As–šβĖōÖ CO~|P4ž™Œ‘öŽ$‡Ō\äQ—ˇĶMiRF`_¤a§ÚdCLl„ŌÍÎ2˜×â˛Xˆ‡Öâž÷Œm „ÄÔfņŠCwÅ dŠpŲ"ų4ķ˜ĖYũƒߨS„4”’ĖŠt ”õėÔļĢųö˛gĢA]ûۏ VsĮ™]Âéœ&g…s’ °ârÃÕÎܖf‡ķüō w›æ/ßŗēŋÛíūį[Åږ8ƒ€ƒŗCÜ;ŋ9Īõ­`ŋxŖ€!˙ȖüŌ„oxöŗ:2#ëlíl&Ų^Q­•Ö`NųЉr îĻēuQO2R•öĶ9blŨ"j{ŗ+\dŪŽ=/Ŗ3Ÿƒit-æ\Ũ+īöšŗŨ/¤LE:ŸÍaA÷\Ũ‹ČHīoōÜ–Ģ‚-§ja8îqGa¤NõôКëTë÷xíå΋ĢãDęĒz$ãÔ|Iq´øká_v­×Ļ/öĮ…Üz_ˇV'oę”Öáx–×Uæųfëā_.:ŖĪYt‡ÎeˆĄárŖ_¯:~šX9ô4°CúxĮr¯/îŅūiŅ æĐžØyߐ‡fĘīˆF–-ߥQ]TDJüĐyÖ͔Qøîå^XԔLÅ\˜]•īD…%Ÿfė–ĩÔ]Xy ô‘œŗíÄô^¨œ@˜˜ËšTĩMŪDáÜáųœâ}žŲā*­Üß1ŸmXĖ•…8Ā?@[ ąŌų/Y2 KxL`@‘\ˆš) ž—?˜Ã튌7‘īI‡Ŧ…ĩ:ÆŪđyYų›§dOp! "ŸōÍoŨ!‹H¨™)•’ útE—*Šĩ”/9×D…”‰=“ļõáMâfyðC?ŒÜiíĐEbūvÆ5ÄØņx JƒüTĨŦápH…} `ė•N­°CŅg%•ĐÅēŒ‡*6†īUĘm¤Į›Á ØÛ â˛éa—”]ĮåY"ß%ÉXđ•ÉUŸšØKéÕ="Ea0í™76â}DbxC 4Đ:DZ^„}! 5#Jôblq†_pˆ) =ĸM\ȈkÅŪ7TÃĢũƒjÁ‡ƒČZ.Ū‘<`=ÕŧáÕßy‰YSa ĒÉڐ Čedē ÛH#ôáI,EL%—K”Ÿ1×ãŲ•GiŖ6ŌUJ$7DI>€BØËŧF1—‚šL‹¤–ÉŨá™L70ūFCŠUwėDĄđ,ŪÖ;¨ĀhC5|CéĐĸŅŦ L™œN×lĨŲŠڕ Fūdī[‚y$ŗ1˜bKÄČÍHœQúČG°ĸ)…N\FĒldF|ƒüˆ`Ļ`&aĻa&bJ‘` RPĻ ŊKd(Ļ`Bæ IfeFc Ō=^f`˛ÃģdfIÔĸˆ„"ev& qfbĻĻjŽ&kļĻkĻĻ IÄkÎ&mÖĻmŪæjj&_ĀE`Únū&p'k~ÃōĻp'rį7čė€x6DD7ŅēŒØôHžIØ5]ŧd\Õá0ĒĨc}\ 0Ghu‰éåŲ¸Ļ \úūÄQz¸'Z-ĘNŲ„,l¨VwČ'g” ”\y tƒ7lÁzƒ7|Ã6'q6č‚zÃá8(„į„.h…Jh„2¨ƒj(…vč…rh„†h†–(qF¨‡*č‡Fh†’h‡b艞čá h‡Öhn聞¨‚VĨ‚*h āčŒÂ(ŽB(nh‹)ˆ"éˆ*Š…2iŠŠh“Žh” é”B铊”^éFĂrč7hC7DįŠ*(–RŠ–.i–ē(ššŠšVi™Zi›žŠ›&iš:iˆÚ(ƒzC6hƒ‚^¨œūiœĒj*›ęĄJŠUF(5th7ühĸF*œ"ę¤jĨJę›f*ūJę‹ö€|*؀Ü@7Ė\CæËØ %yėã]l‘%EöV1RŌ’gGÄ Gž§kØJ}Îe …Ä|Ŧˆ|ļ„\ë„üذZ†ŒPXķ°€ĀĀ8ÁX´€8AļZĢĩj+ˇzkˇrëļ~̏‚븆+šĻ+ēŽëšļĢšžkšÆĢēēĢŧ˛+ŧÎ+ŧn\¨ÁxÁ ŧ@ˇ:ļb+žÖ+ŊŦÂÚ+ÂŪ+Ã.lÂ>ŦÄFlÄRk\ˆĀ|@ĩjĢšRŦÂlÎ,ĆŦɒėĞlɯ̐ĩ~ĀÔĀx+͊ĢČŽ,ÎĻ,ĘŪŦÎ*ŦĮf+ÁjëxūÁHĀ|@ ĖĀÎĒlĪ6-Ī>-ĶB­ŧ΀§ō|Ē ä€˜ęQö<…]XČëM R‰ĘéÆŦ2؁Im!#1‚ Œä~[—Q’а-ŪÆ†#ĩI˛ļĖ~ļįßNc~ūáęÄûŊC 0YŦ7¨æ4HrFŽäNnbz&íՇqRŽænnä2Ļ7°@irŽčŽîmâ‡T€LŽęnn‚pÃģ\QdîęÎŽrŌ€ô€sŪ@7ŧ‡HÃMēęsp“9ąíC–m0ĘĒÛ”ĸå1âĒÜą%Ä`]ŨēĨõŽÖ°ē ļĮõrīõŪĨ|á ÷Z‹÷’o ˛§ēˆ¯ß–“&ūĨ Ĩ\ÁŠ2Z烌œŧđ îÄ9đ%Ž~ĄØĀcņTŪ"DJŲīōöŅ;| lí D§7hÃP]¤ 0§´Æ;đ$Ŧmí´]>Å!xîxôjN~ĐąĒáúš¯~Ú-ÎŦo÷v¯ųŽĒŒ¯ Įđ ˇ0}Ū°[îD$ŽũĖä?PĮĄD5ē†bF[(1/q?ąGqOąX@13qKq_ąoąc1wqˇ…9Š:ŧƒ6 J„ČN˜aĨũŧq9Â1zÄą×1ĶąĪ1Ëąßņ˙q÷1 ō c‘œĖÄûÁÉ r ˛#ō#72$W2ū%_ō$g˛$„4ŧCĎPfđvЉŊŒ˛)ˇ)oQ)Ŗō)¯˛+Ģ2,§˛,ˇr,Ķō,ˇ…+‰_q60č1e˜Ą(31œ1ķ1 ŗ23332?ķ2;s4's3Å |ŠRŨpXCåØ_îÍzFđfÅvęš0’p™ÕĒÛŨj ;ß ÷HÕŅS ¯° Ķŗ8_˜zé­=×ŗ™ĖJā–?īķ=īe™JŽĖ7䲰zCۈCĪFCCôCw„ī ņėDRtDkôDCÆF{tG“dšW”ÍJ´H‡4I¨tKs,}ƒ`ŽK´MsôMƒtN¯´Y1Ë|ūéEīôK uOŗtQ5úö‚Zee`ƒ5ܯ{……éßwŒ3tœ°í—ÉáÚ.:—đ™U–ØT‡} .]’…¤ÜĸŸ˜G…4IÄQ8Ž[›\ˇjP ›yø7LpæäAüĶ3ū-ō:AŅ"“wY¸7P˜÷$ĸ÷Š7r÷P{ËJ|—÷Z͡wá7{¸xŋˇ~g‡_PXŗwaö‚ÃOƒ§–c+N„öX ę-ø…[x…3ø`ãG‡w–ÖQ¸„Û†ox†öƒ§ø‡‹¸ˆ[ļ)ē6âwgwļh‡ö`ã$ËäBj6j‡7ÛøjãøŽį8?ļ‘QšŽãx’õÉāJ†ėl§Uo Ũšŗō&ãYfÕķļŗŧ37T&J”y°žôˆ([›ų˛ĸšX–5} G›ĩ}šņ%/žÃ<Z‹\]‚i: úŸēÜ!KI ܅9–Ąį*Ąû9¤;zūŖ:Ŗķ–• O:ŖG:ĨsúĻKēŸ×7<Áęųŗ§/ÉŖƒēĒwúĒoú6ÜŅdúŠo°ĻŖz­Ķ:8 ShpܡNĖD•?D‹e8c=•­}đwÛŌ–z9™ŧŗ$~Đ z(ņP† Q Ņ—rB"ņˇËšÛ•ãˇũLÄXŒ{—û_œûHáņē˛ģƒˆũ¤^*ûĖéyÉE‘Œ¯ĢKšXoų< #<ų2ŧÂ?ŧÃG|ÃO<ÄSŧÄW<ÆīNāQd¨‹Ø^ŧÅ/|ČgüČ_ŧɗ<ʓŧĘËp‚Āzï|Ɵ<ĖĪŧĖ×|ĖßŧĘ…ŗūŧö:<ÎÛ<Í˙ŧĐįŧÁ‹Ö°ī„m†Œ=ĶŊĶũĶC<Ø „U2D•OŠâôĐŧ†MIŽiœ€}uzđī¤mūÂ-–T@DĐI>¤ƒÖ3%üø;…*–ų:*2¯```å#ĸ!úLo{|FđŊ9R×ūŨkQŪ ŅŪ–ī•ÃD < Š‘H–KŸ´@Ûŗß ôŪŽđįtčīčwžÕ˜>št~ŸüįAxåķp~=ŸžęW¯į§>í_ËíëūęãūėûžíƒūÂi ÷>ī‹>đãžđÛžņ/ōëžķŋō“~ā\W0đ˙>ö×ūî?˙ęwŋôŸžįC$ƒūŧũ=×ūķo?ôSŋúįžöƒôīķé4Đ m|‹€¸”CĐ S°%đZ„?˙Ūũ3øî[‹‚˙ ,øŽ›•‚)V´xcF9vôødH„ 2lHЛĐ+YļtųfL‹ūŪYņ6‘ĸ@‚VļŊ{Į›Árõų[GP ĀuFõ5„öO]RƒOŖ6”Ēîß:}‡EęīéҤI—ju Uę?Ē%¯fŨú¯ëAa­Ž-Û,ZjŅÖˆU+WŖrķŠ=˜o ˇ+=OdXķĻAv+âÄI™âe͕9gî|đ3fОI6-õæŌŠCĢ>ũđ×uī¤9Öé“õjך_ˇöū­ûwoāÅįũķ7'ƒķvžzķčğKˇNŨō;'‘'^6>ũûõđØÅWŸčĐ';Qk_|üņķáĶ?ī˜âŅ|ęã–ųĀŽÚ¯Š…L AŽ ´(9‰z %•œÂ ;ĸé•ö:ém$´ÄEtÉ!›ŧģm1Ÿ‚č vĖ1JŊš,jĒĄĨڇ¨ĸú)Ęgû¯ŦËąx|Ē"J GôŅ‘GM Ō+'*˛Ą#gtĖFš|ԟ’’"*‡ŧŌ0iÂæž9ąĄwZˆ,7Ë>ŗĶ4<‹Ķ“ĪāúĖĶĪŌūÜSPŠØyČ̇ˆ"¨ģ@}”ūPHõ<ŽPH)•T><ģKÎ æ.­oĐI] 5ĶJEÔų˛ÛÎSÔN5UXKÅTUY-=ˆ›‚ÖA ŗT_%Î×XiÕVbG;,vž‘Yiŗ‘ ÉŦjvÂw6<(Ĩ…đ{("ī¨ũ܌´–Cŗ Ũt¤ÉęJ"oŧų€Œ\'ęg/¯ÅŦƊØ"Ë Ŗē“–&ī´Õ×Ķ~sōk0!vĖ?ĪB˜_üĢa[„Ø`ŸŽRv :s*ņρöąŖžHe‹g¨åũ…™f–k~ŲæœqŪų"­â†ŋ2Š™č›gÖųhžWVÚ夝^úéĻĄ†Ú'nžxįdŠŖ–ūyj­šöēh¤ģūšė°™.ÛhŸœxgŗˇv{l¸Á6:nē›6é'˙Áf_¯Ņ{nĀ˙>[îÁß.ĄCÄ*bu›ÍuŠhĪ‹ŲņŽõ)!r{čÜĘ=C…dvČCo??uÛõw o–đf›o>ØÂMØYü7ˆTLī§"ßšFÅÉ֙Œ[˙ ú†v°˛FÅĻ€fÎŪā{Ÿ øô˛"ž {qE^ų˜÷Éų\)‹ž÷äŠūzĘtīŽî—oū ÷=tDž˛iQĻėÁÆúī˙$,‰Åč?€,ā˙(@>ЁlāGæi ?&q  (ÁRaūI˜Ašp„(,!¸„Œá>Ŗƒā Y¨BÖ‡ ŧĄs8ÃöЃ¤ÉÚp˛Â îЇFL"DĘŦKlōÉ@”ÄDō‹KtâŗØÄ.Zė2­ķ `\•ēŊƒ ĖÛ[öPV@3jÄZ*Cˆ†ļ•ŊŊ0IW6Ž<ū1]a•ģŌ‚nč°#Hėz’|cšâÆĄtg¯ī)ëßZ&Û'Éöu9Ū¨øâ   $vžŦÚú.™IMļO“š„Č'{r(Q’ōĻä*eųŧJú¤•œ„e'gųĻZ&g”īØJ.OéØíÎßxwfr҈l€ÔĻūōĸwTƒ qâß6É)“ĒÁ°œé PÁˆ¨N<:dKū(AĀi:wž“Š@AÖrO—ŧ# ,ú%o˜Îˍ €Äëœ?Չ! ip‘wdčDYÂ.‘Ąė^  t …o… VhÂ;đÅ/ĀđPaC•˛4WL CŒI†0Œ´}c˜iÕÔĀ‚1@åMØÂH2Ķ0Äī*ei‡^Ē;™Ō´C6Åé7t:Rˆôô§X*Q×aT¤*Õ'ÛhjLgZĶ›¯Ē<õ)Pˇj­Ž6Ļ˙¸Š.j kÆĖžehQ◹ceS¯ętá7–ƒŗŧļœ‚dÛŅ‹ØuÆI‰ņĢcOūˇ ƒ|C Ü8 ´(ģí°MZ‚ûãää×ū=$CílåZ.‡,tĩą%Ų‰Zˇ‚nŧĀ WxĶ›îŖ"ĐФWž)Čž`è^šC3?˜ …û+æ׸š;r+ŖÜ814­jÔp™“;OŊƒē™ą.Múöv]‹&ĶäcvcëOuHĸíU'šüÁŽlAžōMėl椞‹FŋēV„T`!,đåbk͗ÅНˇÉLļǍ>ØØqĄĶÖÂā[` 'ÖÁŦ{äēáJ'Œôˇ ŪČÉ’ĩ•8ÄÅ 1 Ž^ō–ŠR„Æ.ą1‚?k )ŊCŊĶę.`?üš/ĩENgSfCūazXÉāŌ‡;ļb˙ē ĘQÖˆĘ D`-Ŗ+Áũ°ƒ]ŒŦųîoÂt,DâûåfíŅ¯mŗ›ˇ9[Bžcۈæ;ĸyTÆ˛k*WÖēü‘ŦšĮ!A4ށģ’},ú1î¤#Ŋšƒ Ŋ@ž‰ŪL#h:SëŊūôéS_o¨aCĩįĸ†oDÃĖĢæĻŊ,k%¸UžFlM á‰Jø˛ Š0įælëuÍҞ*ąÉiQÚ>Ō 7Q–o/’ef ˜ ƒ āB€Ü“´¤øÚč‚'DŽ`ípOˆÅqúÆŧrļs[(ŨÃŖ)Pßm9Ã^ļØõū'a\d2÷‘ȰO›ŊūrëģZĨ ļüˆpÔŲYğßO‚"G‡ƒbsōĪc\hĸąōâÎŽ¨C.ō‰qē.9‰æ1ŌĐzåH‘Y‡cū\‹Fåz ņØĘIÚĘ8ŲŌ ¯yK4,Cš=;GŲ;”ĀļbņWH_Mæô æ „¸į šĨūŸ#$É]¯Đ`ĒfĖ Xė-ÁËlÄ×nŸĮĸ#ĪwÚ+ÃīŗûÛ lÃnŦ#œ_°‹Žāl6w×áwĄĶ=DŅöČR/e¤6G<7§Uu‚4I}Ĩiæ!–­ ?"qŠaÆū/ dbH/+đ„üŽũ„äˆ! Ë×ėßîæĖb[ÔlÜēĨ á,đ ‰Ng ųΌ˛0a FH.Q +‘d[k >Ā Öā^ \Ā Æ Â@|úÆ9ą÷JđûÄ'Ā Ōl‰0Ū 6ėėrŅØčĢ2ĐĐi/×n w𞀠ė$âcĪ‘-…OßĐø0ŠŽ'ŋ`u˜Ī˙Ŗ{†#"0]fcäå¨Át ´Á”d fŖŽBՇqâČ }Q/ te5€ŅÖ`/énöøPû:ëe(6O˙ęˆÜĒ1æūūĪĩ1 ÷–.ČžÆ ßŒ ŋQ ÕĸųâDx$c•ââq}\˛e,2íŪ+7Ō"ÖҏAŦvc#KīœŌ`Ú#4†N3#'ˇīynĩtĐĢ3į’÷ČčšR'SæŸmį ¨Q'Ī@ČQ6v I2@b'j Ū„ Š!Qęp#i+īr6 {~Ä&Å.Q4ĪÆ’ōâøŽØūŌáö°ßą ė*ņH" Ž" ą ¯ō˛+lņ0ęŧFĪŨŽé@‹\FōđĨ9ņ$ėî?‹Đvs ‚æÉē˛$äûœ¯0C kûđæšb´Œ6”‚ē,$Álā–m˙ŪO1žäL:Ëī­Â'4īĀēŪaā<[’2¤…cƒš ũūáuFąU Â, RZ KfƒUŗ",X5´ÖHZŪ!ہ.bsŅācR0ã6ہW6ÃNI‹ rú"ë |Œ;´t6Œō6ˆč> îNp@”Qö8”Gœ´Č†g(ķ"ķ\öī:Å! 'ÕfŧķƒôÁÔá ũ!¨Ė`Qˆ5+"ĐH3#€UūĀHYÕ¨°˛Âęk žŠÔŽ´Wy´ ĢôŠ´Wö(Š´  HyTd->ŊDfŸ‚BvdyŽ,+L5%˙E*„–-hSEÖ!h‚‚qÂhķ;cC),¨ˆĐˇâÂöâDWN*´O›đÜö”2lD8¯áų,+6Ձ?:ԟ&â Û-QĒ*Œ4rBĨ1Õļ“_SĻ‚ˆôA€*a "VŧÂ=ŸPHˇJĪOÎs VöJûĮqˇq¯Tc„=3×r—s/V°Á(Xĩ)ÜGÎJ ĻŦBŠ!a‚=PJEs1FˆĻc åđ"ūL!ä[uRšÖ#[)›ļu\ÂHm'=/O×īg—qŠ(kGí1&ĮIļtˤÁ0‚WbõįQ}(sDī+#÷5o9Ŧ#“P "ÉdcƒGĨ%u BJš+JĸbˇFbdbcĢT6ļ(@öā$*vrķ×oÁbS÷u˙a€]Ö`#g)VNˇ!,8€ū6aOWJ9˜U—‚`Ģ´,ˆ1";Ė” ÖAhS,¨Mį7r$Ŗo4MÃĒÜbėwīQmxë1—Ķ„~Â0€ĻlũŠ€¤P• 9r5´ čUnƒ3•RĢIRĪbŌW'¸"ÃEÆ BÜūS W-°"×! UØ*8rÎŗqߨÔÁq­„sSö)ļG*(7ƒ¨rKĸ‚ä$đøg™}„ƒĪŠĐ¸ÔŗŒ6Ÿęâ<„(J_ 83īれ'o%ĩwRx1ąscBŠ&P2ģ "*„4ĶH–]S´‰:Mk2ī•đÕđĒx[/-[g}[”b…Äd”=7ë K$#ae”"$öHļdV-`t€)Ŗ27dą&J1•!:6fßá€"*Öp”x€ôKŨácXvf6JÅ .v ˜ÕAĢ­W°öPļ⋭‹Ŋ2čã‚Ō ˁ Ŧá§ūbhzkÎ'`ë„•'Ή‡Ąų,œäÂ)}ĸ˙Ąą×ĀAiųūŪHŠ5'qčöų˛ķn‰P‹Ģ‰‹lDU¤/1-‡U­” u%Q†5G9wŦ{Øũúrú’”]ŸË3úFŨAŖ%ׁXoâŲ=č“fđ†Ú¤†BÆnc>™FrÔ8sĻ)ƒ° ‰ņõņú*­Q¯cČ HŦ$ĸÍ诠ūÄlmw|Q˗ũ|KÔĨgÚŲîėfs¨Č H×Z\Čd…õn‘Ņ,ģ;ŦīIIãęā•d-1ąK(s":ÖųŽŦEg×rđTĸŠâ­ĨŖg_l—4ū˛ĶU’WŠĘ[öúâŦī'*¸ĶîPh*XģŽ&ŗK@‹Åx{žģ\ôĘ*eX˜ōŠ9,‹Ī7Eoƒ4 ›Rj ŅŧIiâ°1°ÉĶĘ9Ō"ŠÅb–"‡æ$܁’š`;bG“"đÅÁ Õėēô“Sė$4‡™”aˆŧq˛‘cm’Ûkŋ ąÁŌ ėŽ\ũ°]øĒZįkā’Ė^‹›Ųō•Ã˛Ûxkú‘Ô`”ęëØĐ!xē("gÆŲ‚ÆnÄÆsÜ*0O#ËFxäÆŊD'ô8 ĩÔ¨(ĮKbí¨p§…¯JâE–"H°ĸp‘ü$ž<Ԝz0f!¨€vtū vl4~\1^ĐgÔgxIŧä’à ŒÃFY~ŠĢšŅĐč"O•÷D9؜zؚŌSP'<{ŽcņQE\_ģ;oŋÛ!^@gw&Ō+ŨŌ/Ķ3]Ķ'Ũ^‚fĶ)˜ĮĶ/’Ã'ĸá%?}ŌŲ!W2ij xāx€ļ ’ėEvži¸].iüÜ'zŠ}áЃ#ĮN é\LŪn™îLgZÃîûČ%%–Å.ÛËÁĸÕiįU'rÍøīŽ|QŧNŊķj`Z *Ā ÔĀ œĀ Ŧ ŦĀŨߝŪëŨŪīßë=ŪáũŨ÷}ßķāíŊDņ ´āրîŨßūûŪˇ ÖĀ Z` øßã]Ũˇ@ >ā ԀvŦ` X ã~Ū)ž ž@ Ŧ`fĀÜ}Ā~v€j ŧ`Z@ ŧĀ <Ā XĀ Ö€‚ĻU BLäÚͰuRBœ&u0X Į@æM"§{SMb.|B˙ÁCŗ‘ú۝Ö+͝ëšģ°õŅ҉˛Ár)ß>—ŪžîåÅîīīķ^īņ~îë~ī˙đížŋīûūív?đĩ!ˇņå%î÷>—2Iߞ‘äĨ˛!zĀz€Ŗf håĨæ’¨a J臾ĸžQČ7<>z–ūen#Yė(ħ*,ÅéhsëO/ŊÛˇ]Ûˇ]2ģ=하/sųãœkÁ’ŽžAŠČgԪ̏ŧ ûˇßģ(ô¤GûÃ6’ĮÔĢ'û5}’xįüĶÃ^JŊÔ'6ēwļ’j€nĀ &Ÿ^āú‡; ˇu˙Ôũ{įĪßŋƒī:|1ĸĉ+Zŧˆ1ŖÆūûļÍ Â‡9š<‰2Ĩʕ *d÷ŽŨŋ’ū˛ŧ‰3§ÎŒž{Į͟ž’;‹ÕiͿ˄Ŋ‰< 5ęNĸ ŊĩhČTĒVŽīŦxCØ/ëĖąJˇædĒôŨˇĢúZ.løÎiYŗtëōTûTŦΐsíūúũk´ëWˆh?|“éö_ۃ˙öšĨ:Ķ1Ķļ‡.Ũ§P!f‡˜!Ķô'9ōXĐb f&=ļķÂĐĄ-%xyôCĘBš.(ûņ[‡BrÃëEÛˇ†ßž}@˜0,ÁŸÛXČL.cĀÔĢSŨT$QëÜģ#oû“ØŨÛ웝;ÔLŦģĪģĮčą/ÚmWúžŋ˛Ē•oŠËãGęUCųø÷ŸEXmW^nÁÅM}>˜Ō;|eƘOrAˆĄ_5H˜Oûņ×Ö:īŦã’B°åS…ņĨSy).ER{E­ãt ũ””\™…ÅX\/ G”}yR|Ū8‘TbD.š‘?ũčķĶoū Éd•ū$%DĐ6ܰhå{Ōņ6’]BXžZM8&Jī81XV%ŲDāƒh9„×;‹­˜ •iūWĶZėņv_{zԚƒ]yÍH•e˙œ(ŖA&QM`J7^¤B–gYÁYæC›Æ8‘Ĩh‚Ú^BæådŠ>Ųr„Îę7Hę9k•LąSÍ7'všëåķ;Åm,`4"—˜Éâ÷Ķ7gÖø,E‚5䨨J™iž,ēĘÍSÕū§ÖU.xá¸ãnx(˜5ņÍ5X­ŗ;ë䱍j }ÚŌ‹ŅM„̤JšZc_üVTĒĶÍ‰Ž¸ÉũûĒKÚrŠ.ˇŲú“iŽūOԊ÷ą• Šã:ī\ĐqÉZ LŪ^âēL\ŌūIķ[ (°îĄ)Ē\wîæmÎÖõÉ* Ģlô†Î…ÖÅÉô)PŒÆÉô‰Á™ĒŋûZ›\cėuŲZW„0Ëîå`C<"´´Å]7}_ÃjŨę1Ũīy$â7d QÖzoeĸOJ éā,ŊQME+Ž\w§eôĩī8–÷ļCB|ŸßöØ āį7YdĨ;ú’ėBíS Ŋū3 ?æŦŗåo™GzņE”ŗxpāžo4WīÂM°îš Ŧvv-‹5šÜ=’:`im#f’ŅsGbLÛL{ũŪ ÃMÛHSj÷đi”„W™ū˜ÍÎâžņĶ6B }@Ķ)ôÖĘŗUŸëCļ4ūaH~ˆúÆ ´'(‰C܁š†8&kXŲGđŠĮw81‚ÃÖn"ˆÁ‡@p~ąāXŋĖŇ/ĪLše§s‰N€GŅāäHHCģŒčn€ķYŗ˜5m#&¤úaĨōV–oi†Fl\RžņžĻ­i8Š)ž÷¤:}ŽA3kâMĘ%Ģ­ĄÎ‹ÜņPģvxã[27~#/Ė}NŽE¤_K&Ȱ#nĻ|™CHĒ=Q> YĖíĐV›<ĩĖ…ja}¸FFŗe _ФV`Íop ’õŗ$N0‡)ʄ– Yū8æI“`ÅL Ņ ĨvŋNf(–ĘZÆ˜JŽ í~2cb.wB@wŊc ÚâoŪ†0t K0ĸŒ’(D“ąX†B˜;—昒™ĐčÆ3ÍĘ5ÉV7US7=ƒ‘B ™›k.Edˇē\Z$TŊ#ū)0š¤/į ŧd’ ČÂ'Tl8Å{ Đ>hų%ũ‰6ˆHk&č¤ŲOŽ1”ũK–ŗė– z:!T#ĨK‘…ē¸Ņ—]ĢCaĶ6ŧ1$P2< ÉeŌĶ›u’Č%Ciz`z›<‰BCŅ—;nJSsÎ4!5Ĩ)Q]’ĶJ3_­*Q…Zĸĸĩ7ĖôˆRĪÉÔüÔ%Ōį7’ū€#‡@ (Ū¸ÂoŖ+†mŲË$ĸÖĘ˜,ŽísIéIHbFĸĮäĖZ{’™(L­šú‰“ōŅqZŠIßvô÷8ēV ŒŪ H%6ąî ^™ Ö¸6.­"z‹ņ"6pƒIqā(Ř~ž6ĩîl cRËAĀĄ5& ™ml7xÛˇÔĩĻ-îBvëÚā6DļÅzÔXŠĮõØîÅAŌŊEXˊįŠË4'fUÉ( ôģÚú‰]­ˇQžÍ¤jfOŸ25q‹n9úÁ#Ķ0NWŖ,Fš8ŪT‚Ņš 0y¯3ŌjÁ=ĀA Öh +Xá ŅHC ” ūk¤! gzG5Č0&üÆ M ä74Œ&dxÃ6†ZЄQ:Á bĒ0ÎtbĢĨąZÆPâ§xÅū‰‹a,c7ÄÆ8Öp‘ŋÁã0ø˜Ä&FąŠs\äw9Æ%Uō?lLkü„ d@ÁԐ8á dhˆ/ā„[ĄŲ%/ĘüąŽ›ŗÎ†‰xüŀĘ3’_"Š:đĢ2ˆJŖoƒ ;Ô;)Î$ępaĻ–D˒ŗ2D&0qõŊb‚sŪžÖŅ;ô9\€îąčOų͇Žķ—äį0o ”ô‰Ŗåŧã‹ĸ.Ž9J‹knäŅŲŽBŦą%hœí~v‚Įø|`ķRąqT-Ũ~×bļ[‡DY­ßū¨ĩŌxĸe.ČâŌáūQŲΒ`ĸņk¨FĶ?Œ­Ę¨Ã ô˛CJį˛éŖôĨoŽm`“Ú’°ƒ^x^ˉP"ĨŦž ­\ëcŋAÚ¯Ãö§7MîÅĘzØøöo‘}ŊfZچHÃjcĮQ˙A>7- ķūRČôq†xĖGë Ü?ŸĪK×Ē9î…+§Č2Øåäėan͑…MŠBĢ[ßPé€âqß5`Ņ´?åW$œEjhĄ(¯õÆ7ë$ôâL™{­WôB_r÷(Ã'Š×8‚¯'‚į"¨kG‚ą‚`âBLā@°ĮL<˛vÜVæpūÖ0åe€1bAe`žÆđR„ŅƒQ5ąäķ>h6Õ0 ņ @ĐæĀ[ķVČr]į‚wÕņx Į"Ŗ4yžĻEzaYI8ršWOd0D ąoęqzŊÁ{ĪÄ{•qzúA&Ō!uXHy¸U¸qowø‡ļĄ‡›‘8Ėt"†4|hƒø(xhˆ{[Wâ‡UdˆĄĮ‡ŒÁdĀ@“2 ƒQX~Ēe,äį/jˆO}E_8xzgGǘ32¤s§(‹×ƒ3T˜Ö\ˇh?č‡BEä4h$*žķ_€˜rU€A¨K &L"ŒÎČGŧapä¤Ač>žˆPįT:Äȍž$ī°r$CūNáč2ŒsC€ļä1Ō¨49˜!œ“'ļeøŠÆhy‚BaF›Õ ø0ũčDļUrÉDÏizP’?šŽd¤‡PâæČ%ų,ÛĄŽø(YTIވi"Giĸq[´1ÉØ‘~B`ÍȐh›ōčŒ\ŗ"Ij/)O6Ŗ’˜Į‡ęQV•Տėņjā Ō@’ķäoAĶ“!uCä2]ąwP™&ôč'ö蒀öihxy:Y>1 #ũˇwņ˜Üg)’–^I)œ†‘ŠD!?q‹÷’wR/đR‰~ˇŠ^YéWŒŽ$)%’~~ǃ rŒ@ĄQ×Q’•jI`ū‰3Y–âˇ-ؒ–Ž Yũזâ‰@w1ßT~Šveƒod4A˛ėøgTų1™&WK’×”!å?āj˜I)I…’ų" ų^Œ–’‰›ŧ“†:Šũ]ûUšG"Rx^ŗœ?D€=ĸ™Šų ~Ų;QšD•žŠ,ũĨ˙.›‰‹,I€{‰›>ĄY&Į›^™˙‚“äI›DS/™p—„Ņ™oo [ DKM””li„t˛š4ų,Ž~Ō-‰'šhgM]9œ-Ą›ąši x–/$œéI4šĸŲ\ĘŠŸĸχŽ×0-Ņš´XBō 9éz“9(#5’Ķ8@ū&ų†š “˜ųļ˜D ĸö‰€›5LÚ .׎Į‡Ŧ÷—x{%؁Ļw—QZ‰'âĻĨT:ĨÅWĨ.˜‰“Ĩ˧Ĩ81˜îp™˜‰'ŠééĨp˜ŸmúK""õBœ˙iDܔŠ™wJŖ5ڞ0:#āɲ)¨ŠS›•%ĄzÂd#[~¨AįĀ"°‘Ĩ•8Ļ˙ĨĀ{úœzzĄĒŠĸęŠOú¤­§Ĩ™:Ē qĒ—z—§ZĻhˇ'qj‚—aA"§į*|JÁÅĐrŸŲĢƇ5¸;%*@-Cę”×ų‘€97Š—Ãˆqûs˜ãš†,É%"7Ą Âū›Tø_qĒØ€!3]jĨ˜ę‚xĒë Ģŧ¯á¤a¯ôR¯ü*ǰĢ\J˛ú¯šÚ¯ŸÚĒÛǎē‹ÅĄ9ŠĻŠ8FĮ:OYú``[…FąŠDzī€8›–tšĸŦč§K.ē'V)X‰žfX\Y˛jZĄEš 0¯3ëēę Ŧz—˙Н‘Ĩ›JĒ뇮áķJ°õē~&ˆĒKģ—J°A [0Ĩ°j´WjϚŸá*˜Åé•rhPÁ8QԘZ`u—ī7§å­mK Øy­ņ˜Û‚˛P›Ū˛­?*jAz:ŗŦEJRųœj‘ŗļQĩŽūęǰĄ¯!̰ŠųĘ{”ûŠúŠĩĐđ¸Œkz  –û¸‹ĩĨ‡š—ēKĨüĘ´Ÿû(–{zŖ‹Ē-ō0ię˜kÚEwëIĨŠۀŠ JpJQ Č 4w6m+Ŧi˛ņô§{⚇Ú"„j'†Jp‰ @3[ģ5 9Ģāžšŗ¨ @Ĩ˛¯äËšWû(M‹ēëPĢS‹´ä‹ē šîûŠ—8¯°Ņžķ+¯éĢŠ'ĒĢô& q-¸û›÷¸l‡g<4sGpŠeCÔPžÛŦ L'ÖKW2úž­YˇBI$yËŖâ™ĀRhž‚ųļũëY@ŲË|ę`īŠ~č¸ģŠūŦģŋōģí{š@Ŧ¯úųúšņK¯ģžä̝æŠU 7ÜšÛ¸8LĨ’ûz9A5‘'´;ļŠČωIŪ€#A–Aˆ*Ŗ­6ÎK+σŧĘx˛ķK‚Æ$ž-+Ŋž ĄJƒÁÆ)¸ĖÂŋĄŊ +— +M˙ § †¯Đ‰üį œ[ž-aČ Áƒ`"[§Ēæģ€ˆ‚LPdž\‡ĸ\ŋ„Ŧ°Č ¨ŗSēi:%É%2q^Kø;zŒJjéÜā [ĐO2DĩrlËI^  A=ZIMĐJzCqĖ4Ŧ9@åā¡ė8!!ˇÆ×;ŽÁūß0ųjūpēg†Lô¸C!¯…œĘ­œG<ōú¸ áÎä ĸœœŠ%ũlÉ:kūÄķ ĐcĄ¯´ĄÉ"õlē’ [Š7É=Ø8Įy\Z—ŒV%BT\Į¤A‹J Â3fųB¸¤*(ė8đĖp›@éa;¤čO#_H7HU,—Ąøa•‘w§'܍•‡Į#ėŒ˙hr—D=ĒrČ7DaH#Ŋ–!ĸŗ‰ i<ø8ÍĘāË|xčw‰¸°qˆØĨxfWíĒmᚥU›ą”%sŊĶYm/a0 4J˜!úe0ņC)1ÅŲū„-wŌ>Šž‹‚!Ũ%ƒųâ°™0đÉLf›1õRņĄœŖŲǎ= €’]9ŪĄBÂ5ë_ŽÆxÅ:{­5:'"IúËqCtČõ<.g/œ8š]Ŧ…›Ø€ËMsLGtˇũ 0}Ŋh\ 1ā„2ąŽ;„}( ŨšŊß']ņŲ˛us“Ôx5$2Ũ›‡ÂY96!ĒžíšĻI* ˜‰æp+"”ÖU’Ļǚ”vØēhÂõ/DãQYqdQÅîHā…YÍ ƒāJŠ#Úü˛4ÛÍÕŊ-N­1ĪSjŠn1ÖYšzI ‚„ˆN9Õc DKę ČÔ¯ėÖ˙ƒąĖƒÆ7rYé?‰ŖáßGŽ7Đ:Ô@l—Yíå`Nŗ7Ņe“X=ĖRœŖĄUŲ=C6ųw­ŪO|‘úd8=˛­U=´éäĸŖĘŗi ë%CŊûØæĄšĮîŌox#ŧõžūūÖpØÕg}ŅĀ[֗ר%7Įt0G}āžą]Į”sŽF}ge}âūā“sķ.9î^î‚îÔwī˙Ūīũžn5Đ<đĄ>Đf,‹"] ("ËŌ냃Ÿ QŌ6ÁŲ5Y'œbĀy%hŌĖĸÆåŋŋŲ#ņGÁŗBb&ˆŊŽë÷ņĶĮæߚ%,FŅŽŌlČßP7đqļfNĀjp[đW 3fôĀpN j f,°jĀW`ĀôPOõkö[oô?¯āô,`GŋfZīpôM˙ôXôMo`ôrõrĪE?cākāôgôNđVūĐôEô@pôW˙ķ4Æ÷4Ļö3&ų4Fc>g@Nqļ[°_@=ā8ā9`4đöŠßķc0AĪO‘]“”܃?I2?8ruģËˎ×(…ŗ|\m d@'¯882î;æ­š…ĻGPœėbxŧqū^wŧ nŸNŨ0ok´Fīæ k$´ļjŪ@ūJÄjÅáũō†ūéæũ ąūđ/˙ōfū´ūJd˙ ánđŸn'åūąíÛ6oß üĻÍ Ā‚ ~K8ĐB… 'l˜ŖAŽ!r[čÍ[7=pôБ˛Û ‘- zôfåģ˙üų̉gMžū=}ūTčPĸEEštč;›˙¸ŊôĻTĨU­^ŚU+Đwīž9ĄēUėX˛eą2ũú-ėÎaÍž…;ļĢžš ŖÆÅ›×ŦÛŽdØ­ķ§Ī­^ÂEĄzcēojÎÂxßŨôų.&Ķ8™z•ŲXķfĢ’eęlÛÔķ`ÎĨM—ĩląOČī´ė[ölÚĩm߯[÷nŪŊqˇõûŠW‚/tĐąxlŞŋq›Ķ2đЧ­_7úŽÛŨČØŊoËN{ŌāÍcßäÍķ퓲å)õō×ōîí+õzūũˇīŦ¨Ēũø ˛øŧjáēš m4ŦĘ)ëɲm2ƒ0CÍ$ūTͭ֜P1ÆĒͰğ.[lē瞿Š bGDŠ*¯œX H#Â‰&ņž‰JÅ#Ÿ4˟}fzDö*„ōēÁ„ô&ē,!”Š>ëûōÄ˙Ņgē|l?Ė(­-n0,3à AcĖÁ:÷*ĩÕ*ôĶĻ-식§°54ŅB-˛QE”QHu4ŌJ)%ą2›nRQ;ížÂ'nŧ™A-4on jl >ųĖōmŧ|V ;e‡É×´ÕÄËČøF{mŒ-K%Ŗ•Xđ$¤ī1e…ōo5á|ōÕŠ&[p§Ë&{ļ=f3{ÕB:ģŨ“Ã?ūyjíLã,‹Lh;ƒˇ*wƒZ Đ4›âæ)nl*GBoTP‹˛˙1腮†Ew@rīŗ YAÖÎŽĖRˆí[đŸuØ!īu.֋´›ēúf\7s–[w~6ZĻōQĶZ_7Œ[M/ãæŠyOųBg§ŗŒ[žĢmëL@‹>wDR¸iϟūÉ騥fj,§Æēj­k}gãķgQˇ`GÂËŪi΃o264–‡ö§Ŧ`n÷Âū‡§–ęmģQļÉIĩKÔīŋ ‹LÛYw>\,œŧIaˆ]CėĻ~Š4œĀ6k–)ÛÅôlŧ0f#wĩ-ŸC7Ņ\åū/1¯ļiūMŅåIöœl¯‰Ž2F'Û}oUąŌŅ>vÆ<§'Ī3–rö5qo^yyGQcž°vĻÖļaĄ)ņܖlíi3E;)ģÚąüī(û¸+nîõŅYõK^ÅŊÕÉ|ūĨX ÚdũĮēä(“?>Qî10ĢŽĖ"&ÎÁŠGsbÜ˙:ķ…ëZū“āw´å„¤ŅĖe’ÂŌ•ōV:Š&"¤×?D$ŋ)Ĩ…5iĄī¨˛.Bаo/´!QJØöā),ú Ü Ŗuxæ—͉đÂ×ĻļŅ,ƒ›Ų‰A>ģ'ę…my›É°$TÅbåI;!`}$ūE‹[kŠx1—ųŖTĶūZ *HimÚˇō­ŌNVÔŖiü´:‚umÕķãņŦfB)M]¤ņ\bfĮģäĩÅsĐkN%oGy°RķŽü3ÎŒĄĤF÷ŲXĻ>Ęfy’“2—ŲŸH4yÜ&gT‡Ė9ÁˆJÜ  Uô›@Ŗ&*%žpOŧųÝÖkËMV¸Ëڄ.î0Į;EZSíh>ŠĐ$åž÷„įíäiĐzBt•‹š{ú3šf2L› ģôŽ7nq|áDÍTū‡9”ŽÅ‚ņ”ÂĖØRĻtû ŖuEY%‹ĻŧšĘ7:ĻĀnUIZÎëæÔÎŨt?íĶ„zg:@BÕ,ƒDf´žÃĸ4€2ũŠNÔą~ 0gĩž;į ™ą–o4ĖĮ„Å)ȘƒŦ<1kØđĻ"ĩš'vuë:M)×MÍcw­I^ŅĘ×Ļ|ė”ˆ}ū×Ėõ&ęVŪŧņØx,IÚéRŲ.מÖĘĒJą tvÚ=&Šß`$ką";ä#oĄi1†Ŧ™.“dCÍ)5ĪMEWƒnēfœ´SUŲŪI‹xdŽl÷øA@̈́ƒCČāí¤3ĸ剓"šūŖÂS1Ēä {>^ž˙ė‰x›B^‡âd`éMėTŌ)˜ļŧ÷čMčxŲ¸Ü=JŊúmoņŲ5=Åk˙†œbâąö1ŅQŌEJÚĸĶ[ #”YM([‡¯ÂüņĢEiŗŊčŌt>CåŲUL;ãZ§šņÁ–SÁ)b>ŽQ\qŸFȒyŖ,Q 7ĸN]FĒEdŖ‹2O¯øÅŅ’žáŪĄ„ūÁĩ´‰B_‹Qz61]¸¨†\ĄÕ4´ÔļÔq  ʐ}ÛÍ8•Ķ.ĨnÂö‚’ô ÛđŠF`…}ũƒWƒZŦ‘†1$ûÕ Cĸĸ–&ŒA=ÚIƒ´Ŋ˛ėf+{ ˆJWœ°…&ė‹lāĀ´šílhk›ÚÖNrļÕÍlg[ãÛ᎚͍îywûŲŅžö;Ē}mnČ{Ûôö6¸c3îr;…ßÛhËœā´Ā l¸‚ j°…t+á ™ÆeŽxkĸpiÃĻ&yxEĩ î¤ŧ( rFÁˇq 4rÆ>š›ŦŨĻ!YŦ¨DäŌj|š_Ўc‚ŽÎs9:j‰æt.ŋ VÆ /ūd9pZ0ėDà O D<åíhėĪy °ĪŽņˆd=$ûL¸{e8I6ģÖķ%+’y…í’1§ßƎš‡]ī}§{Ū÷Žv­˙Ũíâü•įūސƒ¤%ß Æ7fĐ ‘XŪTSŲÜĐ1Œŗ“ŖÜå ūʕDĪZNÅ ĀFá/ĢøéC´Ã[lĩOŲ"ĻP˛PĢ?ĩH.l.Wéšŧ[´ĩc¨#Å2@Gæ7^Āyĩ$áq—]ä›Ųu0%Â'Ä"M˜ÂÎJcüŪĮo÷4“í ”Á04shČOķcÂéīš~ÛoŊ÷ÛP<âĪ'Ąŋķģ?đS?ųŋÖØģņūē'›;!ZŖæ[ma’H“ĀđĒ‹oā€HžŸ‘-‘bK1ĶĸíĐŊĶĸ ¯h‚š06rļė@‹Ā¤CžmĩŸę1 úŖã#šq:v0$ķ¸&ļ&4 ļšĸŨ!œ]Úž¸‘éˆÂTÂ#ü UˇĪÛŠ–ęŖüāA ‚Ž ‚:™Ž 9Ÿ|’ŊŲC9›ÉĻEÔŖô&[ÄŖ:]“žs!Ļ9ĸˇa4ĸŸ‘ <Š)ĢxÅZū”ŨŠ1[\ą]t›N DbŠV<ŊĀ‘8šQÄ"ÛCFލSņÄŋIĒÜĄDQa‚ĒĘĐ ;ķŦ{Œę‡Qz˜éäš"¤{*“ĒŌŲÁeD’\c —9ēî˜)w’dФ Įߓ) BœũYą}–E+0lÁ‘Ģ! ¤'^ú™[ŧ@’9ÁQ<Ūģ°´›†r#˜A1Ķ '˜–^˛-Zt*‡)¤'Zĩ8JĮ⃠[s.åK:vtÅ!Ë*‰,’ŗáĮ||—]ÉL9HėÉKĶČ<ÔČúh %Dlȕw°ŦM1H“l>ü BŖa$9*)5˜<š5ˇuxŖū"ĸ9MĘ­#Ú (S˜ĄHL´‰|P‡ĄJ͙ÁҘ|ÆŲ{ŖĒē 2Ô5¨0jô9žôIIÁɟėÉAqJ”;LSCcQB¯ņŋ2JŲĶË\J§~h2Ļ$.AtČË„Ē…3Ä×1&8§|‡-MԁŃÁ$—ސÃĘ"{ÄÄYJŽēÁŸ’ËZ{IŦ,™Ü-Ū‹ÅÖÆÂ$Ė5ĖÅ\Π4LäĄō ̓TLĐK †˙ķJŖd™ÕÄĖ#ŧŠVIΔs>äG ,DīŒ&ư vē tZLOƒŒŊY‡JtN[q°öG(>į2GæÃ0Ļ›ĒuÎqGš)ū˛šh•bęNÔĘI ĪÁ=é|P*ÂĮšd %ųĸ7˛LvF!|5õŦĨ%I–´´Ēf\šÔ–+a3éáÍŦ"1ŧQķx2°ôŖÃŠŧDūČD:">åZILKžä9ĮčÛ­3™§ņĨÅä‘Ũ•ˇYNR‚Ōœˆ Œ‰ōG^)J}îc}y%v™Q`ēŒ€zkƒD)ĶOŦĀm˜kÃAöä˛ėQĶø,MC‘ ` s 6J‚…<ö<ĪéO\Ú Ų)R鞌’‘§Ã ĒPÄĘ O§<žúĐÔŦā.$ÅÃwx‘!jBmĐāŦ$ÃÁŊ´ĐįĒ9ÂH¨qI!ū35ˑŽƒá†Aã†&ÅĘËž§č6DÁ¸Ę*M9ŗŅĘcZē1É"C3ĪuÉoHvøœ‰ŒŊBåQ2WãHKÄĨF‚„%™¯°*ŠKAĖÁlNLĨN蜗ędLÂ\WĖAŅ’PuŖÁÖæ)éŌÜkĶZŌ V*G'Ø Œwho1BŊO.j›ž ˛ųđ’Ļ;ĩŠ™#aĩŅȖʸKIķ 9ąˆ‹‘„EŽPUžŦądŲ~ĪáĐšå * ĄÉ k`ËWōIØ'ŠFđ1#…Į PvTj*ņŒØFĶw Õx؀LÖŖũ͊ũū@$€åQuŅ$¯ mÅ1âãš •´p­i=kYŌUdŌŠZÕ'ÕŌ'š[܏œĪēuÚĒÁÛVĨÛW›/u•‘9­žOĝH§5ZstTŦVēšíÃTošõ­žÍZŖØĄÍÖšĮ,éØ:ĸŖƒÎĐš’]Ža'Ú|GˆMY,\ ĨŌŧeUĪu[vŅ]ၨßŨ]ÔģM˜zUŲqB   $¸}¤ĸ}\§z:dôĄw¸€ ZÆlŲõĀ'˜Ļ&ZÔ9Ĩ#Ž%Ÿ…ų u)%ąr¤–ƒ‘mJ[ŸiÁo"ך€†ƒō[Ԋ#­Ô§ÅÅōmēÆ$ÅũŊūGÆ1ŖŲ‰’ōŽSEb%Ī;šÚzÜR Yv|ĢŊ™@æą&ËŋFyË úMÜÍQŅÍX,e˛5ēÔe ŊÖåJtĻ€3ūIĸ˙‚ŋų Æô]ØĐČ´ąÄ Č ÆačQ(ŒjtŋŠđ=ÚQTB¯F˛ŒZä¯Ū‹æ’1t-%õāū-VkäËčũĪn4h2nÉũ”@Ũé>úœ@õí–XmČ×­íÚÉ!ŨâÜÔAIn]”¤ŨWDü¨ĩ‰Pųk0 ÄE'Zƒ#ĖĐĨâÉ_Ũ!ŽDßÂ=ŸMI5æšÛGV>Ú:Fid\Kf LÎ?ū1Šį[a^‚͆5D2Ļ`´]FČB‘ĻÔÃQĄĪąÍ'â\ē Đm-=9vÕ-#ÁÍĻĩNŪōŪküMם“$k‚-P—(39¤ŗĀp.A`Tûë2{ĨŽņŖŽA=$ā(g+fxž÷]gvļIwn‹zŽgīY­īIg›´įŽP€įÜÃāše‰Å(Į5Z va~%0vn"`Nš¨í§Hq#cÂ=7Ųø]<î' ū’ķ [qTá—lDœøčČʝųe=ŸYɘlЁnÖģo¸Q÷ģ´#ģÄ;ŋŗCî"Ÿ•‘04ģ튤6Ÿ ŧĶ—Ã[åИŖ6ęūĸN歚jžsęžŪ* ^ģĄļj¤%ÄHJ­NJE&Oɕm¨nåx-‰A¤Ĩe4á1Ž^ ž^’æąaęŪĀüādĻ4¯ĄābVØ,­Aî°Đä‚ŪēáØ?Nä”’+U‚MÖûÖä†H X€$H°K‚& ĩ`í¯`‚0DÖæ€4Č@'˜ %ø€-îb‚fŖģÖNƒũ†$n˛km2¨¯ļ1îHwz°¸Šh‚ŪŽ†ŽļŲ~âŪîãNnÖÖŽæ>nŲîÚžíÜŪíŪūíīnÖ‚͆í&Tí -¨5h2ā€đū'p‚+ĐeŠĖ’Đ]G4qh#…h3Ų*†Äfæ"gY'ĒGÄ6f_Öéé<áaæR”ŽËk*Jãģ+\aÔŅ – y xŅi{…ŗ?įĀėŦŧaŗķÛq÷Íņ™°2Äg˙įĮĸ0ģgכvF‘qļWŠĐ˛Î‚ŧÕō(w ęX‡)‰ģۆĐiPĘ ÆCĪäŌ‡Sđ{* ¤{ę 0æÄes.2Ģw@‚öMéZ áøčëÆ.áĮŪgö_9ŨĻ}•ŅØĖí~áqņėđˆođeōģ:pû:%ÛąĢO›JT‡}Püĸw‚ iøOˇ ĮZ‡PūW‘T?ĨĻČt1œF1uP¯Q/uxBuUט{qŦxõMŋôOŒZĮ RW!\ˇ ģ˛ßĻ`K9Ņp™~‡kȗđĨŌ]ÜCsāäkYš`’Øģëæ[ŋ@íŪ—åh6hOÛVōņ–ÛŸ™7ÛŠ–Žö0[čØü(utĻ™ˆ°íв™Â]J“&DÂ$4‡ibJKĒ-IĨM1}()ŽtBƒ/ÂdWxžJ´”FUē‰ˆŸxĻT'иøIĪøÖØx‡÷Ÿt¨ĖB¨´-éo¸vZ­"õgö˜ÍvŦ|psŋĀîs –›W–ä‰b`@Œ°›ŨHŋt?Ņ?÷ëūX‰ėS*Ę>ē%Å#-øģ|‰mH¨ũY+öá<ŧ¯ŗŋO´— ´OĄąä˛ˇĪpōė+(ļ|PĨŊq#|č‡ļ¤øĻ€†ąBÂJ\yS7û\øĀ_ZJÜwđôI¨,TüÁ× ĮW‘ÃW>Șü4qŦ eīVœØüX÷|_Gü+ũÎ'0spüp††/dÁ)s@JųBØŠ—Žél“ž‡IÆũÜėížÔ+ķAī°õ;ŲxÄĶÄöđ>Ŋ¯f[1ixWKywŪËØ† ;22đ hY¨úû°‡ûĄIļYĩČĸXãˇņOēų{°Xŋš4Kō Á*”§ī›ūëĄV€ø÷N ´˙Ö­3˜ĐāĀ„ė BøŽāAl ^|8ãD…  <øī!Đ+^ )RcD‚SbÔįīŸ?l ßyŗōNæLš>wúëšągÉĸF"MĒt)ĶĻNŸBu:´¤ŋwVŧmŒĒu+׎^ŋn*p›NĒ`ĪĸMĢęBnŪPŧ#ús-ŨēvŊ’T÷N‹7nD‰fŊ+xpĶ™37â,Kx1c¯īž9‘hPnãĘ%ߍų˜fUËtƒĒøM§žÉ&qžø6† ˇoßļq“,[ā@ī˛ŪFŧ/÷ČÜīvßĻ-ŧļpvÁK Î0ø>Úȃ?žœöîĶՏĮ­ü9b˛ūĘ1ŠvbĐ"náûܑdxũáCw- ˛3~™äģ‡7/ç‘ĨũĐYãVCũ˜x#…Dā{#É} bDRtÍtDÜpsE\ū”ļÎL ež‘XbR›™Õ„f&˛Ø"ZûĖŠ.ŌXŖ?nmÁ D†XŖ•öN X™eŌG"%—’˙l#’Ovu˜hM䔂MÔ}!NuåQõŽw>…øĪk/\áÄkŪ´° īÄcÄöNc„‘ÛJqSjpđNBL8ĄFcŦæfI°öd$§wÖygžˇíŲ§@ēŽ,¤qhĸ덯hkī<iœ”ŪūfŠž|ú ¨ ˙4Q(yM´ EnÜ´%Ú3~,~Ž… •°OmvŦQĘÆQ^ez-‰…¨ƒŌbëY\ūƒrJ™­¸Z™ĶfA1;ŽēTUe‘ωĩŽ‚{cō^ÉĨ@ėe-ž_åCƒ7ĸ´ áöM qq&%jŪ8AÆÕlãÍ6šŨvÍmÛa.>ŲÔfŽ>îAŖžø ė4Y!,ļūėfnQúę/_~{™H—Āč~zš†K¤¯‡äCˆkā{Îĸ‚õmoŅIOÓ$í1Ü ƒq>Ԓôŧ#ÍQÉR¯€Íd…= qhRšˆ d…VIJū^H0¤†–~DŸĮTã Jhœā„+\Á Zđ‚ tEÁ¯Íˆ$ ááĮˇ#}°ãm1bņ…6øë8˙¸aĄTs!0}mt mœ@@…oŽIAI"(œÉäQP‰›@vžĩÉo")`7.h Är‘YbcųPHmC49Ō†¸ø%ųPˆ?úŅ2Ŧ“‡“‰>Ôņ!ž¸˛‡QĨ(ĪÆ¯Ãō Ĩė‡ iBKVŌo°œĄiūAËOŪR”¤4åMŒƒ1Ŗ¤z:$øip‘š4Ō mf+Œ=ÁÆ7÷NmLC+Ô"Ī ¤:blGîŒĘTūFŸ`hžiÉFĻšQ0v$A< Š-ͅÉ\›‹dd“hėĄ6Lˆ+é~9ŖDQG?(ĮŽCZËĸ3ąVüæ!s¤õ+œ?2ēŅŽž !˙°–ĩ`(Q“úĨ¤čJ/ÚRžíų€)I^;8•rˆrÔgæ$' @2ĩE=aOėĸ %ÉĖä~ÛąĒ‰œ‰7ŗ-•Ģ|ĮßTVąN@4ņ–r։ÖArd m§øŪA†ĨÍÔ Ķ,RŨ4¨0~:Œ‘‘Fˆœá“CĒD­"˜§&}ĐĪ$,YˆMtĪĐl‘&‘Ûa û@ˆÜDψ1dKÆˇm–3‰Ŧŗ4Âū1HĐ %}Ģ&‰ n Ą>AĨíŧäi‘A‰Œˇ4ÚJ˙a1˜UpÂ]ËmüĮ×åŪå6e….Rø‰ w 4zdˆČYŠ›› ČV$PÅ×;Tu‘u×EŊŒB‹­q¤b‹Đc4—ß\V%÷|Ēx#˛…&ŒÄŠĄI ›žėw˛ūųoƒÜXū´ä7’[ *‘olˇ×¤Ž:!ˆÃę-æ?ŽA8‰¸D Ņ+fʓbē832FIī‹™2ČŦčKÂ5Ømnؚ_Õ¸ēa˛Ģ8õ1Ūa†H+ėy!ÉšFž!ŅhMË#Íf+Ŗ­ryf“e­pyAX3…LŲÁūĮˆ§]Gō>§´f6sĨ‘Ž|‡ŠŪ įŽ<ČÅēŗVšÃŧo4ÁÎ|>ŠqT”žAožƒū’jŦÛ@Ģh•´Ēˇ°– ÍLŗrĢLfŒüĘČ–iŗŧ$ yĪā鲑hbf“@,.’Y4a¨éęĐú.#: Ysœë^F°ĘũõRfBÕFg“ØM‰ËnŒŖĻC“xš(ĘNdLėHyؐs×@Ԇ?$;y4yË´`ŋ“ÜPÃˑŅ^7PŨnQ‡Փfwßmī"ŊûšøŲōi"heۘ3YĀ×"iyų*˙.ø˙ęb†ģm_ĒYÖē!žo2|Ŗ 4Ö§œTí…ū‹ĩ*2bØš­ÚlüHN6ĻĶ*nˇÛ0÷.ÁÖĢĘÄ\ĩöNÁPNã×Ûą…ė9ã†CëqĐâi‰ ÍÅ/u+=*r–šõ(Ņ&'ūžēŽã†Ũ‹ëk-;× Ŗˇ]âV6ÃüįŽ”{Íä´šēŠIĻU ÜxÂÃuNĻ˙%=īQ؃>sš žŌ¤FdÎA3åĀ+Éa—ų ŗĩ-öbŋGÃŪxÃā~uĻsÆČ|!ųåÉe&­›ŗôbc‡Čl u‹Sh!šáVKņãīÅc#Ļ^ēe Ų¯%‡ĸAáļ)Üo ›@Fū0Ä_ŽÃP"MFÃ|-LĄÃĀ‘J#ŅAÄn ‰U.Z˛$¤JBœŋŒžŅá 97¤Á60Pž•EbÄk˜$ŸaeTZ›ZŌ YI߉š´ˆ$ōåŨ™eT%Ž)råä‘āĮŨŌc˛Ķˇ™ÜbōeDpƒŲ&×Å Ycų­˜@8ĮXŖSŠOĮH;æZc"eɕą!2âĐÚ}âXė%Ûy U e^؜IXļ"ÎÁÎtųfTrĻļÅ7Šˆ”ãxôÚ^ĨØGR[š]›ŋūņæ?XI@eÆ0ĸf­-!C ænææ!–o įq>•đÄqĸ;ąâwŌÚaŧfrĪ`˜tÖ`gH—¯Qߋ]dŖĩæäÚ&TÍŧâŒ[Ü9ؘÜf!Úį9ɜŋąDúæÁŲPĻį5ÆEičŠÉ'0Z œ(âdxčüd„ŠXŪdŠ1™LÄRk”„[ŊX ŠÍTˆ"Ém”ŌA™Šœ’y)5É\Ü$dĻ…šWJ^ĀXN mh ŪŌĮ„ę(Z%‡užbrL!‚ôhģhb ŨŽ’ęĪĮ”ƒ™GxéYÜ#Œ˜†DĄ˛éLX’UŠ•ūp”R:ŒL+%[7J†FųR> „3l靚’Ā„Îß=ę[ÅØœJ[¯aęā`•#qTDÖĨ%Nį?(ęČԇŸVępŅD=_ĒĒ…HzGš7”§žrIpœŌĄļĸĸb•‚ĸ ė@Š‘úÔÄĒ>æÛ|(ãĖ#ύ4æ†q~›wÎÛä>đį¯Ž"đ)ŌEEā¸DãŨIĸWÖĒ­ōiCāĻV¤‘ęŲ܆9čępbß,åíÁd}ˆ"l]RBœĮ9“[ŌĄP§]Ō`¤[A„lč˙¨ė\íŦeØ^‘Į49^2„ln, !Į’Öf!*ũƒåԗÑ dÃ}ÃĐDüÄėÍEBpxLh†eūˊ§4Apqepd×qí[8úe´î'‹Æ$‡ņŅmDßĻpHŒÁ@˜ƒÄÆc MŠŽŧ…lV^ҍ’0eO´œ[MŨV6ĮÛņ!ƚ[!F3N,ĸũÅc¤;X K¨'iŨH~,”A\äãcÖŠü –Ÿ‘ŊĻ̆iúÚVdZ=đ6íļ9RŒŧnėūō+ßŧÃpŒx}ŒdđÄndÚŽL¸CqĨMØi ™–¤mJlȒÎd¯6 LÕ9¤ÎîXL^Ø_ĸė7‚ÚŖŲŅ0 „4p ¤ąÉÕ,­ž.Y‹ÆÕŊ‚DHÕOBHԇ€ŧŽp {Č ûDBh”4°ƒ™išd<„ÚŽPĘūé~ÛėūĄ-0eî™\ËRQ*§gŪ]Ūû$œ7Dpî.¯å)ĘņM"ąĶڑÅ|ƒ¨ ˜ŒĐ@M¤Ú™ņؐv–ÄGÖžLÆÛŒŽËÄūÛPíû܈5ŧÉ%åMüđf‹Ö$Į"ĸÖéŖ)ū<ąĖę]š^ũ(đ¨$ŸĩЁ7–Đm,JņĩÁW#×Õ'Ī€ Äß4ô͘Ļ%‡Î ĪäÆCXR…‡!SO-ĮN.ŗÕ-›*õ˜j}$„ÍüÎ[C0sŗÎZ_;įcVÚĀŲėAFkˇM2Lzą%÷dÜ\€ŊÎĻIŽŠ°)ÕŪå{”2^†47ąúŧƒĖ€tƒ7TÃlÁ¯œD đlÁ@#YmÁŨŽ p„N ŠfT¤ 4AÉe ´5(twZÃ?´ ´Î°Á<fX4ĸÜF5ŧū€\?_ĖĀ lÁ¨ $ĸÁŪ)ė—†›NØŠ{î [Ũ˙2Ŗ7ËĸCā횊ŪMÜ yã}Z.F\ĸōļ­A7Ė@ Œ€7hƒÅ`Û0ŦŒkxÃ?FͰÃŜJX‹PõhĮh†ËĆéŦõĘāÄWG‡k`ĖXŋFn4ÍŅtYC6č@VoC5h54TTņ;wc5/ąībcöĐrÄßĸfą}ĢÅy¨§0Ŧûq2ĨTI>6<ģķŧÕÕėĩk€ĐëHĘŦtË~ĀÎ}\VBPDhmDŗņ×e=ÄũôÆkÃGl'ˆFœđŠÅ\÷pÍ:Vg”MŖ3†kTū.ĖN °ˆl3PK­†68y+ęúœrĪ‘X$ÄVÂ#Zmad õ¨F™ŒEĩâŧÃ|u¸L  ˆLššFUĮĢ ĩg{ÂĐÔŽˇĀA°Ä̉hĐoģ–Æũ Ō70áčM z7äėæa“ö5V3vO8oeŗ0%¯ŗęQ6qLŨįÚû„ØŊ”RE’rU>ĩ4§Į†G× tCˇIŠ|¯ž„ÍĨœŽëx6Zņß~‡ úˇ;„ûî=6ˇŧJō‡s3GčãMàģ*i*ŠxʄąĢ‰kˇY„‹SšzKy`Æ_\!įŒ\sĀeáR{āxû‡ī!ĮŽ”ĒŒķM…‹1ūeVķ_!íŊNš{”Ĩž›wv;0|ƒoŒ?š ÉGc%:‹¯[ˆĶÚcXø˜ŗM¯™/QzgÂō¤ôi['–aö …4ĪXcä‘[z >ˇhHâtg…c z>îĨĸwQIŨ|mĢq9­…Ô;ä–Ž.‡7u”›˛˜/ųĨw§™ūD–‚ °Œ §w ~ļ<Ēŗ ENēhTúąįß$äėF ˙tbCųyŪC¨†5ŽšÅ-Dyæöi„I6›MŌh§úØ@šĄ jĸŗwz§ƒēzŅeÛ *2;§ˇ1q¸% {⟇;†ē(ŗ;ĪlƒĪzeE1°kŦΙ bāhūÄŧ#sĶú-eį´SĀë´SŧJ~›˛ŖŒ}lŋøļŸS9;Æeîļë{leŋˆķūôsŒÜ>ZŲéõk|† öË˙&2?á*[ôwŅįē%õw#Žą˙ŒåvNŋųËĸxææŽ›;T7ņ™Ÿ™'@ü8`Aƒ&T¸aÂîūíŅaE‹1”˜‘cGAvô’dI“'QĻTš’eˏī$Žt9“f͌ėdÚÔšķäģoVŪôį/(OŖGŽ|gÅ[ҁC˙9E:uĨ>ĒW]JÅĒ0 ;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/images/uml/prepareStatement.gif000066400000000000000000001363231447311732500311520ustar00rootroot00000000000000GIF89aît÷!)!11!9%B!JDJ!B)R R!J!NZ!ZZZ!J)N)R)R1Z)Z)Z)Z1e g!f )q&c1p 1{+s)ˆ!†+ƒ13”)Ž5–3Ÿ6R!N! B!J!R!Z!J!!R!!1!)9!)B!)J!)R!)B!1J!1R!1c!Z!!c!!Z!)Z!1c1c!)g1k!m.k9s9{9{!1„9?H)R)!1))R))B)1J)1R)1J)9Z) R)9Z!9c!9e) m)/k!9y!>H1*V-9]1 f15N5BZ5Bc)9m,@rnIˆŠ^’`ŒŒk—˜k ĸqŖ¤{ĢŽ‚ĩąĩĩ„­ĩŒŊŊ„ĩĩŒĩĩ”ēˇŽŊŊŒŊŊ”ŊŊœŊƔŊƜÆÁČÙË˙ÎΜÆŊĨÆĘĨÎÎĨŌŌŠÖÖ­ÖÖĩŪÖĩÖŪ­ŪŪ­įŪ­ŪŪĩįŪĩŪŪŊįŪŊŪį­Ūįĩįį­įįĩīįĩīīĩįįŊįīŊīįŊīīŊįįÆįīÆīįÆīīÆīīÎ˙âÎ÷īŊ÷īĘ˙īÎī÷Ŋ÷÷Ŋ˙÷Ŋī÷Æ÷÷Æ˙÷Æī÷Î÷÷Îī˙Ŋ÷˙Ŋ˙˙Ŋ÷˙Æ˙˙Æī˙Î÷˙Î˙ÎŪ˙Ōâ˙ŪÚ˙Ūį˙įÖ˙įŪ˙įįīįīīīÖ÷īÖ˙īÖ˙īŪ˙īįįīīīīī˙÷Î÷įī÷īī˙Öī˙Ūī˙įī˙īī÷ī÷˙Ö÷˙Ū÷˙į÷˙ī÷÷ī˙˙Ö˙˙Ū˙˙į˙˙ī˙ī÷Ö÷÷Ö˙÷Ö÷÷Ū˙÷Ū÷÷į˙÷įī÷ī÷÷ī˙÷īį÷÷ī÷÷÷÷÷˙÷÷ī÷˙÷÷˙˙÷˙˙˙Îī˙Ö÷˙Ö˙˙Ö÷˙Ū˙˙Ū˙˙į˙˙īį˙÷ī˙÷÷˙÷˙˙÷ī˙˙÷˙˙˙˙˙,îtūųĩû÷ŧƒūüũKØOa…#Bœø°ĸD…đūÁK¸#ŧoõåkH?~˙Pj„׎åĀ‹0)Æ´(ŗ&͛3sÚÔ‰Ķæ>}ūΝÜw°ŨÁŖ{*åÉt§ĶĨO›Bewō$ģ}UYf|ĩ+Ô¯RÃz v!ÁíōÛ¨AˇG3ŽĶ˜” ŨąxËęUxr`ƌ÷ũķ[ōßģ“ũ˙|2/ŲĮŽ#ī•,ÕîžĀãúkėöŸ6x—˙uôĮôBĶ\‰ōåę¯Âç§ū;đōe J~ $xØßF~\Eo,x¸aāĮ—Ģfūü5tå §ģŽūÜ0vå ˇū×(û;ōđÖc{' qßē„n%h­wÆÖÖķ–ž\ŧsØŗewŸ•7Ũyøugœ÷!¸i z‡ ƒę‡R;WĄ„nvÕW’€mŠWŨqÉMį–…úmÆ_ˆÜˇˆƒå×]€ā%8jæąæŸzŗ-ä Bi i†Q…ŌAumØFĩõ'#€ßągŖs8¨czö¸Yjō§‘?—Ąc×;ÉũÍhtÁډšFĸÉą)ŠoĒb„#nI‰ÍĨ¸ˆËm´WÉ*ĸ‹z~ĮæĐŲŠ(qŒšDÕm¸•ŨIB 6PUŅeŌ_kEa¤ŌĒIŒ Ցsí`•Αūžm–ĐŦ)ä銸‚:ꎕĒQŽŋöVj¯ŧĻęąŋ;ė`%ûЍufY\Šķ>!ûėŗĖëmˇÆ+.Ēß.;Đ¸Ā‚kŽŠÚâZ,\'ōã–AoqåëļéŽû­ŗî–Ģlŗí ûīž'ë¯ŋĩ>”°]ōĸƒÕ9û@ŒŌh˛úļžČĒ;p¸Ŧņˇ 54ĢBúŧ‡R4†e„2pú•0IčfŦ/¸üęz°Æ1‹ îbžŌÕsÎÜÎLXÍûĩÖoŋŲuÕOû¸ÕWĢĨĩQ-i:˜IT¯…ÖÖW ÄZjŠeÛeë\XÍšIĪ*r?l÷“KVåõÜ_ĮõŨZË-7ūKZk÷ŪoÎ÷ā\ˇôiāZĮMĩâ]gä_!-¤ObŲ=7āzŪ7܆Î8Յ˙}xæ› ~šæ„žxՆ'ŪÛ]Î(4—`g‰^8Zw{Î:î^ŗ.zŪ–“ū5ŪĒkuzé~#ÎųÖ¨ëÎĩ?"ƒųŽ`s9ŌØ)ũ†YBÍŸûīÅ;îŧĻͯ.wÛ#W4oJo1‘Ú õn>ųˇ7ūũņ„^ēâË{¯<āW\˙HG5đũ/|ü[]Q r!xˆŠ#l#”­Ėbß°/iŧ 3¨ZŨĨ.¯ËČo’”ômƒÜ  SČÂē°…0|Ą [9xŧC!î€Ū9 ¤Íđ‡ū1 "‡(Ä ÂĘn™KBŪ0•mƒE$ĸŖHÅ)ZąƒfaŸĪ|ķĒĀüÃûĒ|HÆ+š‘ƒXĖâ?Ŧ1LQ…üØa;Ļe όUĖãg˜G=ú1{…ų` ōŽŖ´ãF‰‹"ĩĸ•D6˛(dd"š’Ŗ€$ņû6c—E*Ō‘’Œä$EiČPšr”Œ|ä)I™ĘŽō•Ēåg>“Éöƒ Õ`%,]‰Ę^F2–Ŧô%$…IĖRĶ”‹œd{–¸–_žō˜Ā|æ/yL]RSš­ÄĻ0S —Ā#—ĮX V†dœƒĐō#čÄä4ãâČkŗÚÔåAÔŠm¤LĀūáGG:Ŗ Pĸ“ëDĻ;Ģ™ÍwZs—Ĩ (( *ĐxĻŌ“ …4>‚ o|ãÚĐFŋ‘‹fÃĸ ũFHG*Ō’’ô¤ŪčhGŊÁŌ”^ÔšáJld#Ŗ7ĩéIMĘĶú´§@ũŠPƒJÔĄĩ¤Õh6ĻąĖ%đĐhQ§zÔĒRõĒVÍjIŗA›ftˆŒ–S=ķRŦšUĢh=ĢZĶ:R–ÚÔĻÕHj66ĩO’|dŖÚhŠ^ŲēÖžļõ­6•ë7ĒQŽ…CÕā¨\ßZQŋ:–¯}Ŧd… R––Ŗå¨G×ā†#a GÃFŌŽö´¨M­jW‹Z+¸ļĩ¯ū‚ âĀÔÚĘ(S°‚ĸ)ÄĀ Ŧ Žp‡KÜâ÷¸ČEíĐ`#؁ ķąFp–ÜęZ÷ēØMîØ…#La Sø Tģĩ&d÷ŧčM¯zUk…Ä@ đ‚h§`‡jXƒú¸giT03Ė7ˇë 0qÛûÛ÷FŧLø ;–Ø&E*oáëŪØ øÂÎpv;…ŌN! L`Ļ!(câHqŠÉĄ ģøÅ0ŽąŒUÜbrˆÃËX†2rœã(Äõ\fŒą rÅ3N˛’—Ėä&;ųÉKVƑ1†ˇŅT¤S@2”ˇĖå.{ŲÉö9ĖaŽ1ôŗ†Ū ‚ū–ŋĖæ6ģųÍ.6˛ŠL*Χ0iIĮNlcĶC†ŗ eLg1™ žĪ'Õ)Ųƅ´¤'Mé/ĮãÅ,sŽ­@ |āƒÅĮ3âa‹xÄcÔŖŽG/VŨ ^°ÚÕ̆uĢ_MëXŗÚÔĩ¨…=æņgX<ãôPŒ‘Ž;;ä$G@1=~ņ q˜ÚÖОu´eMíZKûÚ՞ļĩŗím{[ÛāîЁŊã(ŧŠĻņÆÄnnģûÛŨn7ŧß-īzĮģŋāŗéaä0ôŗ™Q7ģīMo‚Īûāö.¸Ânđh˙"ĖžGÄë<…s•ķ$éH‡Bũ‹QĮÚŧyÂūžđ‘¯úáOų<Č1†lܧ0/*Ė1”˙bguÃw^rž“üį&÷yĐ]͋ĸķÂÔ§&õĨ—jėE Æ3^ô_´účHOĩŠĩžôŦ#Ŋë[Įu<ča‹gĀBŋŪ72Ē,ú#h(,ž]j­sũî_Įģ×÷vžƒũīzīģāŸ÷Âû]īļ(ĩ8ˆ†.Ōęĸë>ŧáxÂKūō”Ÿŧå3ųޝēėbö1ayΛ~퍝ŧę5ŋúΡūôZwŅÅ=qà ¯â`øĄqbˆÃęļ`õ.\ {ÖßõĮüėãąō(|"öÉL6ĸ@œ_=ųŠĮūëŗūüîßûÜßzĢuQk}ĮCØNo‡|Otq?ßEī{ĒįīuúwŨîņpõ¯í„WaÔō0a€›ÂIŅ{°kÁwō׀agö—t(x¨æ€ø7`W ˜ˇjĪ lépvõ S@H)ȁxX/ø€1(3¨ŖF~ŗpiâācbꆂ-ƒ+HƒChƒH„ˆ„Gh„¨„MȄąFt—V R™‘ŧgbŋ÷y:× A(ƒE¸‚.†vwu­ö ä .Įh%¤Ų ä`uF'n1čb(„IȄvø…Dȁ{ˇ‡5x‡`hŧ° ąFjūgLG Æà jtlÎ6jX÷u~§yšG§Āo­@X@ ĘläāodƒR7‡–ˆ‰—¸Š\ĮŠƒˇŠ‹ŗčОX‹ƒWtĮx#čAđ pˇøŠ­‹ļ(‹ÂHŒ–xŒ¸¸ŒÃvŧ@~—FhP ätK&člÆŒÚx‹Č¸ŒĘØŒĘøŨŽÜ8uW§‹ļW…Cĸh­aÅ@ōđ~ĨF‡ŲXÅXŽÛxĢxŽŧP{jø Á,Ō‡ųftÜHŒâHŽö˜ÉȐyâčéŠų&nŖ†sĪĀlâ° Y0 ÆaH‰ĻælÎļjš×qΆ ø¸Šúö â  DPūX 7FSārŸb' SG ņ§ÍØu*i‘ˇˆ’§V‰Ė؍A‘Į(ŒW×lË`näDX†K𐠑XI‹Ãøv÷~ĘhtĨÖ|Ú@NÆqɔ+š–\Š–@9yŠj^™–_g†øf{1ЋˇôríāŽäā ×wé–Yš•a×q‘H—_gtũH1ĐQ qAĐŖ؇ķpŽJŠ”„Ų–ŠY˜–(ntšSwt^H†É™oŠj§lô@‰W 70 ˇĄĻŠI|ÄšS'—â6J§šģi‘ĄĩКö@lĐ ŋögQ€“Qí ˜žttXjljēūŠ›ŲɛŪ)—ĒYšJ'žā)šĒŲĀ šĪæqåijžų›ęš›áɞŋ9…RP–¤ß%ɞšžÜŠžđ9 ãéžĪ–žę…įųž jžÃŠēžķŲ›ŨųŸĒvt’¸ œ†*%‘ V  ņšę  ĄÁyj"ē įųŸJĄ *ŠžÚ žé›ōIĸšžŋ& ĘP 1Đ*“Ŗ4ŧ'â˜ˇ{(Ą*z%z 'zŖÁš›ī Ąēš%I{âđ˜ß=ø„lcؐâp™‘˜j ڞ2š¤-zŖ:œOú N* gʤžŪIŖ3ŠĻ.Ęĸ#ǧJž ę’§jū>ų Ę ˛É'P ĪĐ~ô(mJ§Öy§ßYšĩ  ô A e§ˆj(Ûáę'w÷pfZ§|š§Ĩ9Ŗ'š§5ŖDI§ę雀JŠS:Ą+ÚĒžGn>zgfŅĀ8Ģš šÄj’ę)žĸ) ´zĸ”š§*Ÿõ™ŦvēŦŪųĒņ œ.IV°†ŖâĄĘ`§Čڞj HšĮĘŦs žĒĻ7ŽuÉĻáj’åyĸˇ Žâ*—ŋFŽxéxļ‚qŌI"ˇ€‚įŦž—ĻËĸĻ|DŲϏĘĸųúuŠ ?×3+5(x§Ž*­ vņ: ÎŠʰ+Ŗ˅ÍÚą&[ūŠļēĸ,{Ļu‡tE— ‡¨­Ą…rH‡yžĩ jŋ` ô`jŋ€ ô`´Cųŗņ€ âFŧ uJ+´Ĩ ` j§f“ېZdŊ—I ôyŠdGœîYœJģ tĩd[ ĨĻ´Ä9´f+x?ûŠĢđumK˛nĢļņp äŠkŊpŠįY—§f{Q ĩ0— Ĩ'‹ĻŠj˛Ā¸ĨF|NjˇoˡHwˇbĄlĢjq;ˇ‹tôā ĒļŸKœŊ ˇTˇ¸ĀijĘ0 q¸‰ûĻë´sģlJ›ˇ&ųŗ?k‘´đļJįļDČ´Ļf¸`´ĩ ’šē¸ŧÛjdûˇĐKfĢ´Ÿû¸CūK´Đ[ŽûX°S(•uÁjƒj’ĮŠĻö´‰Š’P‹tģ+vJĢ’ŒÛ´Fû¸{œL‹ŧČkjN ĩ×{˜â`0ÅIi,ĀH´|7œˇfŦŒKœ$KœŖļ p{Ŋ?;´ škCk ˇ{jÅŲ Č[œe{ŊBKļ$‹ÁŌûģbwj˛ ŊēKjģÛœk ƒųŗ#ŒtÂ[ˇ ŧ÷H‰ŽöŋŪ0:+¯Ė7¨¸–ÁÄYœŌkĮžŦ´›ŊĀVœļPĩ`€jä@YÛ)w‘Q° ŠÁëŗĻö¸Ļëˇ. ¸+Œt)ŒÁ(Z›+ēc÷ŗŽĀÆ%\ÂĻ ŧ2|¸&°j<Äô@‡íûÅū4년{nuÔhVŠēŠ§ĢÆļ’kœ[ÄĪļÂn+ÆÉ‹ˆžkš¤F}<´PëÁî{š›’ôøĮô¸›÷ LđēvqH‰kšŽŒtą ‰CÛģ?ûpšHš{‹kC ŋšœkLjĮĪÛ ˇ`œÎkšŊ qØ™Ė’Lŋu|ģô[ēšŧOëļĒģĀŨ‹~ql˙ ÅĄÖĮĒÉlŖvŊ4ĘĀG loK˛ĨËĪûuģk6´ēpŠHÁŸ›ŧĩ°‰dÎĪ&SSâ‹k!pôø~‚+§v* ?›Â4Z ĀÖ G̉Œy›Įcˇ BkÁĀKĮmģļJēKû¨ ŧĪņāÆq\Áî;ūˇėë G7ļgŦŌk‹ž‚ģuųvŗ&VėçĀ=ģĪą€kŊ+Ŋŋ@ˏŋŠģ\ĝ¯lûk;LjT€H[Ëĩq—S×ŗĻIÄŊČâ €đ}ƎKŌô@ ŒđuĢ āÁ§oĢ´˜ĀzĄ0Ę ¸âÆˇ+üˇš ’Đ Ą€ Ēŋ!œÁÎėuøv~ÅāŊwQSą Č0ûuC ˇ¤đ¯ Ŋâ׌ Ž0Öc§Ī”ĀyĐŖ Ŋ}ŠJ‹”ē+nđĄđŲ§0 |ĢÂũģˇbŦē*—Ž[AŽm•ëĒŊĻ6 Æú“?K Î̚Ök Å9ÎôPˇšū š—ęĘŊ@ŋĩ`u{Ũäˇ ĒÉ ˛@šh;v ĢĪk+n˛ĀjŖđlbljA]Ë_ ­įI¸øĐvĮ6Ē€ļĀâܚ|ž[ˇlČËÁđ;Á–kšĖŨ†˜ŧ× ÄMkÁt\ā žwŧāĪM ãŦĖnU— -§åL|^mŲE|ŊãŦ’Ļ_‡ Ą`Ļ ƒĀāô |~@ĄG¸žy ŊŪuüŧˇ{˜Ā }Đ|§ĀũļŖ0 ŸĖž‹Ėž[œĩ͍ jĐĀk8ŨÃíđÃôˆsYjW - `@ĮiÅÉæOܚŋŲė‹ ģvŊ°@Á—ÕcôAūZÜbāiuŸ)vtŒ bûˇĄpŊ0 g ŠāÜņ€  ˛íâˆpĄ@˜ˆ@ ĩ  k † ņ  |tukÖĸ^ ¤Đ„›đā´›Ā„Nš€“đ  Īp ĒéG ˆ€ ˛<Üu)ČÅp„ÜIˆ{ȁ^x´Đš”0vF+œë’ë™ū ĻF BîꇐŧĻĐ—Pˇ˜p¤¤Öcįܤ`Š­î’pÖĪ Œā­y ŦŨ”Џ @ėĸ`ëpéĒNë7üá։ĘĒÜ+hiėM˛@Ë*™æđ´=›Ųjņl0”í­ģĶLūļ 0Ëä× ē  ąāãŽ6Á@Pœ\ŧBK ×{ÛzmۚŅš† 0ËGëÂY7œŲĖYTbž‡įøÖqĒ­ģ#ŋ´oĐíĐģŦËúûÆĩ𸠭Âņ0|+ŧŧô`%nŪũ í˜Ŋ`á¨ĒCĐ~Ŧ]Žļā |î¤  ĀF čŪ釀 `Œ đīô č3ΚđčŸÍøĩ} ™€îÄy ŽđŲôĐŒ é{ ĩę—ūčŒĐĄđg-Ŋđ„. –ū ā‚}č˜@œŪ Ļ`éæ~Ķîę’āäˆN^‹^Čl6ŊÃ9Ũå;­ž8‡ÖÅūų¸´P 0vôĜō–ŅŅŽÚôÔôŧ–ÉĪ|ÍĻį*qQÕG˛×\ā­‰Ģ@įÅK ˆ@’°š@”āĢĀ “ø°ēÔč)M{č‘ĘCęĪ$M„8 ŌäUŖJöVŲŖ7‘SV 9ņŠDjĻ>•*V˛¨éĨC”øJeˆ”ŸK39é1ÅgŊSŊâ *ôŲ/Ąņ”CĶŽß?¨īūÁĶ6EŅĸXŗÅī=D¤páâČɐŊI‘(IäƒļO§?¨4!â”ˆŌžP|(9Ŧ ‘$zķpŅĢH ¤Ļ<,9%DғCK~H•úŖŠ‘@R”"U$5“”žĪūĄžņĒ…5i<Ŗ¨ŸMų*TxŲŦj=M4éX{öXå€Ū¸pö‚ĻGėXŧ!°ĸgĪwđæd› oN/=׋÷Zx­ŽĩŒ¸ŽË@ņâöpÍS_]¸đ{ČŪ“ Ŧ}lwôDŸi-jT\ą(đáĮĩüųgŸŌ‘ĸ˜Ģ˛úå—ũč)–ĄÄûåŧÁˆŧxæņŽzžZĨ´_Ėģ¤cŽ8z’ŗĮÂâVųĘ8zžšÅ+­Fg oū* ü§ÚųÆĒĶ~ÉĒļĄöĶ/zYe0õH)„I"AÅ"‹>ņ%\,KE†~‘‰’?$ŅÄ.?*éCŽDpIĢ’“nūŌ„UPIėHHQŠ-Nöh„’BdZĖNūč15į‘äËUâCNB4ņ˛"NvjLN𰧒?8ņŖ“‘&éC“Iü0…Ŧœ$ę^œÜ—^ÄĄĸĮvĸ`Š$qŒ‡zhéę+Š‹žŨ ˜§Å āŽ  X\€jq˛Ąlm͟§^ƒ*(”‘•Ôl{˛Ģxž1nY*úãq Š$œ´ ŅÄK$™$zü@aeA:Y¤<ōĀŖ’B8.œD&A+’ēđ­¤DÂá$Dō؏ˆHáHIXĄBPųÔRÁ…’GĐ+Í´Ąhįŋ(Ō ÷ĩØūfÛJ]Ŧ~ą…UņJ 1LōøƒVŅKY„{(Id•ˆ#Š$ÎJ˛œ$ŠŅD;°\ŽĢ.´Š+ŌDvX’BÄ",’O !„zÂļ,JŠ&÷K­—g˜h ļ!l0]œąâČ9Į0āĻ%–§rāüáÎË­ķårc‚Îs›ĮrÔŅ+ĻDoŊ‚Ë͞[ė![{3 ôpƇs @uœÃ.7ķ0wĩIœģŸ}’Ÿ\$<]^~šĒÅĄhŽÅĨÄâ0—ôķčY‚Î[Åē˝c…ķãaįx˜°æ!Ž `ūôÔķĒĸėČđx ‘‚›yChCQRR„¤vĨF_ŅN8>ą‡B"ûT#ÂB˜ED„}Øtu”Nâ„î"މØĨ¤O EŒ¸D<$A CP•Ā"(BļO!Â’ū„C(QÂņX4&ĩ b!•ÂĄ& ]"+’Ѝ;‰Bąb)ąŸZÜ rEQŌRzöŗíqC#š,âA+Y|pĄPD/bCüDX„@!–@Ėe‹zã=Ü&*õG•Ā…ŋ0q\Ä28œ"Å{”ķ`!Â3ģ°"KkÂE( ÁĒČå,„ˆc `#›yŽ“h‰Ūn‚CžÕŠ'É ĮPÃÁšzÜcŅĢG8Ú7;Žuv׹‡paÔâl]įŌ†ŧ€q8įZ÷`Å%ڝ{\r0ŧÜō–ēē4W$zjğm …gōū^Āˇ q°Š[^=ÄWV}%Œ(N—tŽnÎsĄĸāΚĮ˛:DÔÕâ˜GônŅ€Ļ&§ŦœLĘŦ$HÁŠHHD2’ ˆš>I„;CŅājņ MÂ~ņpÄ$*: Cpĸĸ‘x"ôBāâcô°Ä#(ĄŗĮ/û‹Į$qÜp &"3s„žR!KT"‹ „ąH‹'x°Ōz5!"ĸ ˆ¸Ws>aˆ_Š{ˆGAĩà aÎŜ…iõķ ÃĄë}  ;áQ‘Q ؃,áUÎa°=p¨Î› 8n”JPŠR\ąūˆŅ O"…žNĸ´jĄ‡Ot…U+3äg Ą\Ŧb<\b"čT<Ėx įˆpä!_ĸĮøđ‡<œ"yYbö@°8*!ÁjEgĪøOœ2cyMҍĄēxĄO܌E—™÷2{”"<œ&‚ú5{đÁô]áĻķЉyäÁHŽa ™‘B¯ĐC•+ÁŠ<ķ{ÕÖ.måNŧ”†Ā“îX+ÕԔqĩ}œąĩB–ĄRv¨Â›vqĖĘŲېcõh@é&ĩÎÎÚõôãÕ }å}]ŨÜQū‘a€°OŪdU–qĸˇTyG/Å Gī1m\ļU´IĘ^ģ$%čę*ßUÄĄžÁÔâ:ɑĪUÕÃTԃ€l={T|tŌúŠvŖXx‡ãœyę6IžÛîŒG°ĩ ( ŠŖWƒõ ~Xõs(å^qץŽUč{ĀÅ-ÚĖ?ÛĨÍy8) ‘‡_ ›zøC8ËáĸÕ¯ø2ĸ>Ąę=˃y DĐü"9ã‰!„ ™$.Ŋ‡IԙN‚Č+ę>‚š@ÅKÍ6āxāú_Z0*¤´‡@äÔUw„öhe+\ũ1ļ(QĖUá &zēAm2ū[ŲĄ†õßäXņ[97zD(ģā–2¨Đ×Ā3Ah(*ŸŅs­ˆ(ęyGHKÚæŒ”#䨤8<Îä3ØãÖąĮ<čVëWŸÁi÷)Ö°Ú#ŦĖžÆÅoôŖ˙:ÁYŋaáĶëFg<ķŲküĒĖÆŲüņŨp0IîŋōĢņ 1đˍđ[ŋU?`…ë -ås> ô8 Ŧė +ôŖŽë)„žz°âx ‰ŠÃIœÅœĸ ū¸ ĄĒŦǞ‡Ļ"€÷`*Îēœz0‡z€7œ‡g ,\ˆ\hē ãˆō@a‘Ģģō8LBËa$ō¸ĨRūĒ~̟ŪȍķĐŪ¸tŅžų‘ņĢv,<ō¤ōŲC›Ô +Ķ{Cr€íŖ,ŒģÁķ(-Ô ŽŲŲ6@ÂˇŠžĶY*ĨڜĘ⠙’ ņžŲꞜëÜZ§Ŗ(ŽW0÷ë@¤Ķ>ë[; O< õģķŗžM¤¤îûķKáaæ#@TÔ8ķ?ķC@; Ā‡2ŦS,ŋ„A¤6{ÁĀz VŠŖŖh­{âĖķŖ]áņ “Ķ öKæŋpp ĒÎ)Ĩ2n„Ak) [ø=fŧØ j;—ĄI  hĖÉi‘l!|ÜG}41~|ūŧG€ÔĮÎČ|;#H41€,Č~ŧ‚E.-ŌīĖQ˛Âs‡Ás¸s`ŋrPÔī|žpR/UŊāp<Ē•ĐŒ­ GÜ < CĶHšŸ;=ŅÁa•õĪŦĘĒSŨO!ëŧüøPUQ(QŦUP[ĨUÃ˛D4řßËT=2 ę|Æ$ĄI;XI€„•Ė7͑ÉĐĄh€k €g°…slO˃-RúS"†c ƒœũ@§Ž{ZWt%AŠaņy5w•×xWw5š TūŌW–;ę×tu×tõwD SAŦČH …§ûKA­Ō¨´‰=6¤¸Ø€}×y%:%A—Á(‘ˆĢׂíŧX)‘;ÚX}ØŖŲŖXYÁuĄT×  ôH& }ė6‡TVieVĖÉĮ •É€ ښ Úh­I†DÚ{DH°Ö•œËü™Öæ‘ 5ÚeHĀžE+¸íų‘Ņô‘ ̐ € €ĢÕĮzD€dHˇENĘTÎü IhşhEېÔ¤…Ø¤ i•PÚԚà œŗŠĶė %Ų­ )Ž›ÁXŒu4‹EŲ~Ĩ\–”Ŋ'u-šßÚØ’MˇŅ¨×ĪU’÷qŲūŌåAuãØ]×zUĨyU'Č1 s°éĖŨ´#Œz…Z°wI;|˜:šNē#q°‚opЧ’q‰‚ų´ŖPĨАcCViMSŧzÕōÕ-¯=ßyļ¤ŠÂ醍‚dœÄĐÅŨĄ¨…öÜßUCėqßßõ5_~U@ëĒŌžŦ0œÕøÉŠ€XĄ\§›áQŦRØ(ąސĖ`āõā$[MĮ]AŠF( ^ŸÕ ,Eb$Ãē]lŅ ņĐI¯b•đÚ`ģĸÉÛ9¸28%-ĸx]c9ŸS€Ųb4Ūą *‘ū\8^äíØ­ŽYšVÁ[ˆb >ŸôP˜"×ÚT×čÔvøTģ­ÔL WÁtĐë‰cõ5ß:B_øûU­(`ŦĐcķāô­ËŽxØ]Üڏ)ļÛuF K Ōũ…7˛ÆUî QØîAĨŅIĄ°%™…‚ŪÛŖ^vÜŊŪS’įÄŲ 1ÕĄčôu°ī%dQJ9nå4eQÍ-\f\ü]W‘PúûéHûd’tB Ųí9ÚĪëŠtĄSXöãZ†åĶčšŌĀîČåēŒQŸ´ŠÆŲ ûũ u"­r—ĸ[`—ÉOް…b& ØuäâĀ#˜ĩ­Ēį ŅfūŽÆ…’ Ëâ`gg6UĄ8… >á[aŲ]āÅeĶžzŠŊŧŠ›9 Š‘ÄŠSEš9hø3mA`~2zČ'‹fũŨ…x‘ ‰Æã…Ũđ0Ž„ž§×ÍNŊšGüĖ\–Į&kŪcķEæ­Hæh8C>g˙%ß9>UlFÆĸFš^˜ÆûM ÎK—auOEæ•į<č"–UÖ_¯ÂŖ* {2æx°§’Z ^0ՏEq0måKۃĮ˜B7ąî[ Snų=kū=~ÅkøÍëŧæÁlĀ.äܚSՀFnėŧÆë=zėĮnėũlgN`gļO ûeqy‡ UXĄ, ūsė$Ŗy^Ë~lÂėÔÎßĘnėÕ~lt|ŪÅN—ĶníöĖk 9°.œėŊļmįß×kÔ.ė×>kW@MÜJMÂzÎߓ°[Ų‡ C ZšÎZūptŗ'^ eÔąˇ§,'ë^ …'ë)ķa § á~ˆbČĢfžeŅ Yißß˙ 7Ÿs:ŋmø­séDaŒ2¯ĖCĐ3ôÄ#=bšf2’Äؤ"e‰Ë[j’˜š<æ1#ÉÉ`´A" ú†5āņ +r˜ÖD&1™Mk"2‘‰tĨ'‰Á Xj“œ×Ļ9aIGcYđ†Ū˛ŌŽ›k{Û[O­pq¯pųc9”3@€d™2RC›qāŖZČßr2Ķ~ņķ:ŅBŸø’1>ƒÁ‹ÕJ¸83ƒáĸZŅJ`2B#Žh`ä¸Ā+p¸ÄĨ=‘ŅI|æ#ÂŦ\Ņh‡‚J[âōœÛTūä"éHH R’éØė‚å댴ëÔæ;¸Öhîņ,7Š“ÕVPxZáŗĮL5XS›‚d@ Ą}đķ>ũƒzV0‚JkŪÉZA ŧe.d Ū0ĄG˜CqÛáώˇR˜‚‹°Ū(Œá wŖąVũqƚÁcT˜ÂdĄPZ˙¸ÉfF/dÁģØÅFŗæ=‚J{æ9owĖĨėgUËZ×öŖWDL>ˁtŒHu3KG;h|´ŖˆfFĸ‡1…Dķc҉nŖ ­čtpēĐĒĢô UĮŽ? ?ū˜g}ĖhLSÚԚn5Ģ_éJÃzÖŽĻĩĸūhGˇÃc¸tŽsmëXĶ:ĶÄžĩĢ­ėt8šĐîĒ?ô‘}œ##ĘļŦk}éas{ÛŪ6öĻ{=‚DkCØÚÎ6˛—]ės;‚FĮĖã]É3{Š/žáŌ z|&c ‡8œ%/ŗ"ŖÔōč=äEĻÎ <ĄžÁE푌ílī RsVXŧ3˜ųˇÅ“QƒEĢ3ĨáN á’‰QĒiž)“SúÄXÆėØĒ+miFĢ.ŨÆÆvŦ/] Õu TÁžļˇŅkL'ƒf4?ŽĒ7RųƒT‰Ļęžîô$*zŨ¯VzēÁŽnŸ'}ŨāžtŅyÍiv'ģÛ_÷:ÜģūNö¯'šĶ6ôĄC­~´„æĮ~,ōû$qđI,|Ą/3Ūđ?üágVxŊíg?ÕĐOŪ˛2ī>'QZõ<â!īøĐ?^ô‘éSŸDɏHf˜ŲęN?zԗžö¤ŋ=íqø­˛ŽVĄEĐaøŅĪžø˛?žęq_üFÃà ‡a}îŖoüäKųûЇįĩløžĢɆö¸gODŠ0?Ėo›ÚTX€Ôa?üÍG€÷ß†ĶšÍûЃ€úŸ¯}˜˛üŸųœßų¨ûŊß&āh$ L-䄰D/ŧG°„ÄhŪ;øC>œZ;ŪáũIîMŸíYD¨Ŧ^;ūā6@Ÿ*ōõƒ>ôƒV¯Ę>,Ņõ^ žāVā Võõ ŸęÄÁŨŒ"ßū ˛ éą¯ėQ…U„âÉVŠ•Z‰dá7<Á}xŸæņ”Œ Ūęx_ÄXDė RÄŽĀCy!Oš!ĻĄžá~!ō”ë Ō–ˆÚĄ†áÆá"˛!E˜Ú!–Záâ ĸ# "#ĸléÍÆS$>bbb#ēáĻáføÕ“}-ĖZK™dĖ)>BԊdŦb<¨Ė3ŦĸpdŒr°bœ¨Ė+– ™(‡÷ŧâ.‚oĐb™(G0ōÆGÔb0ŠĮäâ˜dЎÜūÃāÔSĀŪČWQáāqÕ!Bĸ&b!*eáĐØ%rŖ ^áēáZ„9Žc&’ã;Æã&öa<ÁC8‚vŖ>Âã<öãŽH–ĄR„ë^>FLÄ|ãƒ7¤ABę#;&b‰ˆO$đ%¤%ĘŖ;ú#&"¤4ŠAF ?n$IäJ$:Žä>j¤>z#CRëT#GĒ$MÎ ¯$â÷…ß(Žb)J dÍ˜Ä _˜Ä^ԊNŦĸ,ē"B 寈 .Úĸʈ SωLņÆÆ\Ĩ-Ú"RŠÉcøäOnWZ`.ä#nc>ĒŖ#Ōc*Æ=žĨ[Îd&^áXÖeŠy!ZÖū$\îåÖå=<=d#Ž$_f ˛!"öaėá¤zĄ`^Ī!2$HÚe*âŧ‘aEZá)ĨcfÚ$:b¤$Ræg†&=.¤7LĻ$‚ĻhĒfe˛æhöTBbfV¤kÖ&ižfkbžä7āĻoÚæj’f=Æ&¯Ø[ŪN­…4ŪļX{4įSؓtJ WĘI@'4FgvnįĘĀĮ°@įyĐĖ픩•§5æcn'zęMdR<ŠgzÆ' æ6FĻÖãmg|ūf~ö§cj<¨A`Â'¨~¨!Z…$F¤ZdZŪ!{^ãi &zÖe÷9ĻElĻLæŖAĸc…Væ‡V(…ū~(ŪH(Lžäm†¨Š‚čŠN"‹Žh‹ĻhŒz¨FLbxLÂčŒäŽdLŌčExƒNÆÜd|rKu>'s§‘"鎔ĸsRįąGuJŖO^Š“&Š“:§w6ŒNŘ÷i# †éƒŠf…^cO]¤€ę芞ŠG†a}bĻ}öT_ö¨ŒÆ(›ži&†{æĄŠčŸi‹bąâa†Š)WY¤˜ĸ!„jŪâ(<˜Ŗ¤J**]&cĸél_Nǧ~*¨†ę¤Ļ㍎A¤úĄ¨ĻĒĒĒ*"rÕfŌi§ŽĒŦÎĒ#F*WyCœęŦîĒŦÚåŠZ!ö0(֗}ņ„wöä“*§˛*kū–NéM!Ģu:k‘fé´bŠĩ*é”"įv)5čę,ŠōjĻNâeÂCŸŠkĒR毞$JĸdŦĸ+ŧÂk­â ŧ§6Æ+žîęāEĒ‚Vd‚ōÔ))ĒĢĸĄāå v_;@ĒĢâ)QDÃęG‰zŸˆŦŽ>hjhžŌ~pfÃj™ŒmÕĀ:lĮ2ŦŠ=ŦĮęĮČvŦæmCæęÂ&ęÉļŦɂ,Ėn,ɊŦĖbŪŊšãfvh„rėĖž,ÎÆŦĪ-͆ėĮ2ęāõŽĸĖmÉíĪŪėĶ-īĄįœ–ʐįvžEOJé˛~­ŗ2+•Bi´f+•Vë´nŠW^'ÚrŠŲŽįƗÕĻŦÃFū­ĶV¤÷­Î¨Á šÂÔ-ÕÚėĐŌ!ۜ’!ŪáJ¤ë<­āÖėĮ:mã­Đ:îäĸŦËÎfŸU)ÍläÚ-åūíÔJmįâGâ6(ĻŌā‰H5RÄã™ė)-fÅ&,LR¤ęŌŽÄ´Ã!FŸīyhˆčGęæníėžÚ.á oņŌ.b"oíF[FxÃt`EœãņlōR/ņVođ*¯đ^j6"]J/ž!EŠoøoF˜/ųŠČŸœĄ´eC@¯öƯõ/ö/ũ l6j¨EH͐‘ntz’Ģ–RkŲ~åĩÚTOb§øq'ąōdd€'ÛNŠ|ÁNšėž**•ŪüĘ/bū˜aFDÛŠQ`]¯ ߯ų‚)šfl]rĖėŊÉĮz°ũŌđôfoįpđėđö?hîÄ˰×đß0ã0¯å.Á&Ņîfčöz_ĀžĄõēāŠáhėaÄņ"fgãĻÎL6ư_^ÆîGŪίør1¯qđĻąún•ėâVņđgoōŪąįq G ¸Ē/Ĩ–oŸoŗąũēą GīōōŽÎ âą 2!¯!§ąæ%*đÕ\ИÁ2¨'WM'Øpˆ(C…(‡˛){2*Ŗ2)—˛'¯2ØÎ*ŗ˛*ˇō,GĪ'ßr+C …˛.Û˛8 RĀžyz/'˛!žáū$įpĀlė’°r2r‡&âú~čę”, q4C˛4sŗ7Kr$›ėņŽp ›lw38Ŗķ3ķ:§ķųn[Ä rī‡v(&;ęEhÉvĻėŒvh tˆ–h>sá\ 4BĪ(™ĸeB 4c–Č‚kCOôQ>ÃÃŒSQm4GˇR+môGw4GUH“4.ųU%1ƒ$uJ‹ôHŋ4LŋtHĪtG‡•1Lšäąƒ—éĻjBz,ÄP8RtŒ4zî4Q'u‹ļ#°>ÁiąRGuQsæŽĘ&Š–Ę>KĩVk5AJ“øéĸnĩXõ‡šå$V"YĪ(}ZŨö ÖHÖdūhÉõgŅu\Ī5^×u^ßĩ^÷5_›ÖœÖ Ü@˜€\Ķĩ]ûĩiíõb+vb?6cÖ H D LÁ¤ Å2ôD[u%'†=uZ6i̍Yãa[æii¯öÆĻ‰Ē6kĮļrá]ō´lßvB+Æ7Ŧ€ŸâƒŪ|ĢĄ!ÚĨ7qŨq÷°)÷rˇrįÚs÷¨]ÚŨē9wr37q;7wg7twsãŪmÕ9H›T˙'ŠÚGŸú6{õĸ˛å€u{“6g˙ęKÂö|o5DĶöXæˇ̍âá}o¨ŸšážŽ5œž‚/8ƒ7¸ƒ?xƒŖƒ>Œˆ†3@8†g¸†ū^åžĩƒđé4]Fu}[Oßâ÷§øzĸčEŦ7cǏ{ę7B*Œŗ6%ō7×øĮ“˜*ŽōɋΎ÷ąƒĖČí9ką1īoņ&ų;ƒp9Ģņ“ÛīāEƒ6ԁ6\+y“Ÿ/”{š< ˛1+ą’Ky˜WlÅ ņ?X]V°šRŖĨ%’Č ˆļŽ×ųŠW2 |CŸF*RÛyR3ôX~ƒžŖ¸Ÿû4nĄrvĄË6ƒĄ ŋAû6qš,*9ƒę¨5ĻãiĻg…5Ŧ<8`ąšjÃ6Š—u;rÕöũÃöĄW5‰~#`ļúĸã6;fŦ'æŦŋų`^#ĸįēR?¤49*ēū¯“6qŪx¤ŗw€ŗŽ›ŗg:Ãâ˙ŧäO=æ}ä?~ãŗC4ˆ°įģŌs•Í#QÔ=ĐW}ā[í^$Å7~{Ķį`–)CמžÎ-îŋ%Ŧ‹6Øį~ÂĶūíWhÁzī#˛|õ\Rl÷éũęãöˆßßY4Ę7˙RŖú¨Š îQV,~éwžÎ˙åŖįáyâ'ūé˙šW>øC=ꃥ3HžúķÔ;œÃīŊŽôk™?Āöƒ!Vė›v˙œũđīß@„ 6tøbD‰)Fôį¯Bx˙6ö[ū¯Ũŋs +–4yōŸ?†ü†dųĪeË/cœ)“æM›9yâô HxO˛ŨȲįNŸJ™ÖtĒķéË}˙öųĢz•*?¤(šnŧČ1e?}ūÚiãzmZĩk^ĖƌÚĻūŗÆo^ĩqU.l†Q%ŧƒ ˛xX!b’„ \xlá9„‰7pŲac„Î3fXđ!bĮ)ũéĪėÅuũ™uįÁzi×fدīFžū@Ļ´køĘ3‡Õ taH™ÄgÎü%ōå6Ÿ;oō‰ˇG9F÷Ž1įtåĐÁ—ī.á>~VŲķ›Š´fpŌ…Ģö›:\~~ũkŨj\ØOūáۏ@ļúē+Ĩ}؁‡+ėA… Zė5ęė1Ē&ې5„bg6;Ŧ,!Gŗ¨‹ü!@›ÖQé ÍĒPFƒcဠÜŅĄ¯ĀBčĸíĮŠđƒ¨¯†’lëĄ%rČ&ĨlžĄž9˛Į)•Ô’É,ˇ\O'īt#0°áÖ҇#ŗŠ\“MōęĸëBÍ:-ĘÍ,vTj‘€cĶ €bdM ƒ 54DĖ<ŒMŅØTQĖ@ŧl°@AƒÔ  ģL!8H X`É@ü PI =`QĪB´“Į%‡ķ‡ˇƒ•ĸ#gŌˇž|õ X•~í•Wa‹ 6Ęa“´˛ūK&•=ŲgĨ…ļš7­…k?[ė 5\Ŋ•ĪGüËf<,ŋŨŅ×pA:M2 PØ ­´ŌXÅŅC įŒUG)mlļN[q yíMČārÄņŽüiæxœĐsŅn†°ŌE+{õ\H›Ēä‡Čޝ5Ĩ*Ÿ¸"sít9ŲāŌÍí:ČÚIĸJ”uĻm X†GĮķK˛¯7Zđ›2lLĨŠVcL€™bŒē`J§:hŸƒ` t5MũĄ4ęŠôl'jSâ‡Ō|‚´RaôĐjƒ6rpEmœH)$ļ#ÉĶÕØqđŪA;$: Čí!—Oœq‡w€€@Õå29ūŠžA"P0)V­ V¤^€$oúÄĒ#xP`¤Y‡ƒ&ˇĨŲQzzK‚údį p@…{Đdā ˙8C9\ˆ5C¤ÉŨ*„2A Ē"™VĨŽCÍxS;(đ„ŪäiÔá•Mļ'*h§.Æú)eö$˙Pņ”9deĮ|¤xÄLŗ Ž€\‰;j$d8ÖÉu`˛‘ƒä &íØXŦŅ' ļc wéMH´ Ž(A1dęĀDc8ēŠũņ"†@3Aū¨ÚØ e4@; Íļ }(įPÜzÍpčiĒÁUÎ!Œ!Oķ’δŖwŅ´;¨šų äEÂ:ūŖŠüq܈ĸzzŖČū1–ÁTsKĢÔe›`oXƒh#ՏWÎfËXĒÔu_™ÜKĶŧčŠ‰íø†8žaúĮA`ŲĻLĐi?°x“˜0YĐ] ųM„€Ķ&jG6á˛j*$BÂ\PĒD Ŧ–s,ÍĐ ; pmDU͒üļ„Ôåb™ #™XÉųMĨ ĄÜĐGˇ‡Ŗē„˛`ėxMJ5žŋf2HUâR0̈Ebé{’ ¤ĄÎPŅ÷,D:›’I% uë‚öYŧ8Ɇ°d™iuVË ÆŽŦ=-&yķ%˜ElLCČ:ø!=šf Ņ+‡zž5R%–|šūp ¤šļU%OĢKS;m<Ą ŪđiSĸÜĀ#ž\ˆ67:­Ãy4ĸ°8F­eMŠ_ÁLEYeÆI $yÅ;"ō.sĩ‰†â]ÚæĢŊ¯SëØīAšZ(U ūG* Ūrfmˇ/qĨlytš*ECVķᰁV¨šŽø[2}M=‹b$eFrß`g•P—UĄ fœ8Žņ8ąZcÔų˜Æ )K• Q%! å:E†G5ˆœãq ʨ‹Æ7ž!/Ø U( “Ņ oŦĄEĐøŠĻ‚ ŅGį˜įĢ5ōšywÚĶžÖ°ˇŽŧŖj dG€Õ*ŧÅĘ9yÎ^Öūôô=ŦcŒrūQ;–ļš @˜×<&ĒTžōm@ĸ˜‹ŅL!‘dV-æ´E\ÉĪ[zC–ŖšŦNíAU›„­ūŠÕ7˛›íz#ļĻ2ŽŠ<očúžÖuŽooÜz×ŋū5ގ‹c{ģš^öąˇėgīÚ×ÖvöŽm­Ũn{ã^čÁxĐ/Đ@ģTļu7jî …Ĩ~\eŒ*U¸Ë@ąÆ1A$¨‚“RŗiĒ ųQÁ¨‘lđ(¤p ˇv÷Đ7=Mú)Ž6P€ĖvˆŌđ¨ ÄĨ)Õ´Y¯>-=“z-×ĒüÅ`éË}8B…ÕÂü…6Ŧ9ĒGū‰ķ–:€ßx^`āvPƒnTĘUĸ˛6L`BnUCĶļūz°ü QÔqbĸÕ)EÅÅčEˆ"%RXO#%c:Ä| €Æ ĸœJM`ÂĀ'‹¤“)6.ŊâgS6D4<Ŗ00„DH‚7Ĩ1*ÃOJP36Ãl4ƒ@ĐTâŖ&‚VŽĻdBø|.Ū€/ųœ\tŽÕzÎųbMøŧTMX4¨ÄmēáÖln8ŽŖĒbA–€eā*IœÁäÂoję ˇ klú‚üŋ‚wX°Ú*XāÅ1’‹Cô„$bkpNãĮ„'´āahė0Æį ÁrÔ¤™&ŦĖI%ĸĄ3üá^DDąéQ°3ĒĻ_âU^…$ÜpĄ0°1BdD`Nū¤IĻBHöIæræbÍÔzĐĪI‚°šV‘ttÃ'gNF¤pĘqą…vņk‘Ŗ$Ūā!V`ģ„äž`>f…Š´ĄČĸš† š¨ŽxĮ7ô„ ‰gw(æ+N.´‚'%¸X4+ĄŦ‚X„Å’´QX”¨i¤į"Ēĸ4h%ļôFƒÔā|Íhdđ*Į E¯[´&Ąlp|0¤D‚fMdbD ca8ą´ ãCö gƒF<°[Ię:`#ęB\LįXHø põCÅLŒįPn$ņMf1-RJÎÂ%]æ"Ā ĮūAüáĖ`7æ*%4hžÁhlĖÉŽƒÉh,(‡rÉūŒ ɂĖ(ƒ˛ÆĒÁh 2ĮvŒĮœ2ČĖĘVĻŌ)‹ÉÆZ¤rŧv€ ´Ā¤(yėØRāJPuãiĐHĶ0e2@&ä â   T%ãūm‰đņ‰ĒF!4œĀe˙r./a„HSe2„¨!5‚ @bYR.%ŖD9xC3ŗtZ‘ĻbkÅåMÆĘ\H5ŸOW%Y“øvŖ/Ž#ŌL“ĸÜÚ¨ÁۘÍÖēíÛ| ×rØ|3Ũ¤Á֜ ˆ“ÚžíÖŌí8—7{SģŌÍؘ7omŽS;ģmÛ¸­ŧ ürĀ Är:•­¸Ā’“ĘH…Ĩ¨Hû_ü’ū_čå`bƒUr¤^˛Rö’1c$8Ŗ_:Ĩ‰Å`–H/1f B°āÁ ŧAM|Ņ35B•Œĸ3'”?€ÅRōqĸoW~nÃRŽ1åF4DO5Uã7‰%ÛҞÉZ éÔĀ^ ė` ”n T G‹nč^āT č¨n v´Gktíî@ \`rôR` ‚t舎č–T R@G” ÖāFstKánKUĀDā¸t Ô L‰Nîîv”GŠî\āī܀ R âéĒ@tĀô.z`d  ĐÎ ¨@h`GĶ 4 ´!FTb;øi°Įđį1Ն`ÔæRīūrmŌ͆mZ%!´0"[ƒS2‹Ô&FcT#ė zr2Ä1T/^ÎEĶ?ôMdĖ%aĒ7(I§ØŠB™hĘ $¨-§ĮŒR)õ(ĩÁĮŠĸŦĮŠōY‡ėÆPÃh~,Z›•*iōYŌ[7B˜ĒDģv z žĀĐ͓Œ†ĘˊŌʀA<ƒŌüĐl2æ/'‘Ū:pī%!;Õ0×f÷_ø&B,ráūrU7ePc%Â0PH;\Iį<“ĨrųnWOKCOŌ#9ms#'ƒ••.“ēz§E5$$j‹ ÔDX(æyĒQgsē|#g§b‹(f5xö­ūĒq5͍å ŋŅ7†öہgŸĮĶÃMP,w üēpÍ RãšzūJEz°čhôDÁ¤ˆb;Đ/×&`đscĐn ”b m'åAZõ_#ŗ˙ôaƒ4D­Úa ”hgdmˆ7dhds•IôJ q$}5.ÆBXÖϰÄ'ãíI<-Nv–Čpœ– ŌOƒŧAŧZHe1 ›cWË5Ŋ¤Ļ\—iIĸ|Čą÷4„ MexĐpu[Ę*ôB؁ )ƒxī€.MāAPM9¨p¸œK§ĸpŖåW-.ŗ‹ĄÔj4ElfKã-,Wļ8ˇp9"ŒÕz Éd•%ÛBūeī†VōHP‹DĄÄ~Ž3Ĩ­J 3ņk0$C„z”ĐĄD9t ā!›ž×>´á~Í&܄}ų#’7}3uËéA^aHOĨTĢZ…É&ͧđŧQŲz5ŦX]ŋ:= ÔĢËąlÛ^5ŠR-Ķjßâ| ĒM[P~AŠt›ą#‡?~čČ4ąâԃūk 9ōâĮ’)Gļ ŗäŧ‰ŋšÁÆ´dO–[ŗē=ÍÖôS”*_ÜE ;öU°ĸ™~#íRĩėŨDu—ū÷ūí6XŪÄÉz{ĨIđ˛}Õ]>~ųųīë˙ī_€ũ Č|ü<–SīĀÄ;íØXw>EtŌ]“oÜQöÄP~¸›v>Õahõˆ"OĻõÍ(žXVrĘ=Ļ–…/ŪHS\U8ĻM6.žƒÎ„iS†uí÷Í) w”8ꔕ?ėü3%sOŧ&šV¤Ąõ$ˆ*ĸ_W2Ųe™Gũö ה'mhMš'@îcSĒMJ˙,¨.ļÃÎVžÔoĒëĸ4%ŠNÉ;,hlÂī’ÔŽX†*ę–Ķ^ëVr/ųsNŗŽa,Ŧ­(éSėŠ ōXh&ęO?Ė~œōtŌ~ɜskÅ|aËũ'čc6OøsP%6ã”ŅānŊîn8īcÎP‰rģíčģšĨüŧZ?Ĩ0ūĀS:đĪĶđ ŦŽOī ŧ•ēŦĶnÚSļk0Ā˙€r×í”Č&…-Y‹ķ™\úÝ>ũd sßm–”æIũŦŗŨņŋÅĶ:ƒëO5Weg”ÜŪ|9˛Rũs\Ļ5*įŪĐĨ nŌ; ĀN˛&­ÃÎ:ŨÉ.ՔÃsrwŦĶĖ|$UIR÷˛#@ë˙đšIÆw,å| ~^ü?‡­/}­W)%ëTjˇM ĪĩfÕW„ŽwŽThĄļü˛6čwYŌÎēäōĸÆļû~RšÉ]R>BįĻ™ÍSŖ ¯@§§æ¸H4ųaÎ †rē~øcđōš"ģ N됀Ö,¨/Ú@įū IõĐŊ}@xŲkŠ?œq)`k ›c¨<­é  aë.H%å­Nvë˜aĻTĒ•‹€Į&&$¨đ̀;IV;˜•-!QŅM-[âԑļ-&%Mü6ū%F›tEPšĢVŲ˛;=ĻEđāŒTÂĮ)Ŧ…ÎxŨņ †ĒąP{˙˜ ԊčŒôņx&ŠŪJ˜¯āMɑëš%O’ĩBuÆz—ŦÆČf oXV˛āõÆCS|#—÷u îsetĻînl'ÁŸ-m’Ĩų#…ûĨVøˇĮšNĒéôÖ@šöēö4””rĻüúĮ¸ŗĶpʋŸÛ‘g/Eu€§ũĢWkb;0ļŦl<…—kT ¨pé¤cÅå÷āqŒ”$Ą˜d•Í”4.”tcÔú˜^œpQWf+>i[‹˛iŅčO|ŅS(̈́–ËŠėú‡˜ÆLrĢī@ūÜâšÎã  ”Ō!˜tɂm­˛úBjf™HÍĪų˛lŋā7GÉT%JøRĄŋÎȅ‹Ō_ė’WŨŽÅڈƒų„Ë×ÕĀC8d]ŖŒ\čFäBIÚ‘ãIfõ*ÜĨ•~›Nš~*“9…‘jå%ĻˉĒx~UBaĩwm ŽŦIēŠ‰"ŪčËÛų1÷¤{Ĩ¨ÍŪĢÛåŽ St}Ų4ën÷¤Ž47xJAI'áA;˜hC “ÃaˆEšÉznÅ>=Vá&Kŋ*Ŋ˛ŠŠĨåR‡ÆxY4‚>œį'Š Í’žIŨji•h2ŌđXTLŗ’\…Úθ–õÉ×į$kÅüU1žXėlžtŲš3Vž“˧Jķ˜`f–‰Ŧö’€iÃy›3¨§ŧcG;Û(PÖÛģuģę*ˇZĐ¯JŦįũ”o$Úgļ~LŗÉūLî^ûZn7Áđ*ũ ÄėĪČËÄ7‚xrgíæāX6iüŦęizĄƒNVĄ9.*Z/wŅļąĄßˆ'ųyԗ’6shŽōۜÚŅ/7`žį¸o’÷ģ¯w6ˇ NX}ģʼnËJŗ=ÍsúŪ ģōÎųM n1ˇЂuĩYh6čy#Zt,÷ļ˙N’öÎÜŪוöŊFZuĢW1ŠRū3•žq*bÖ~øĘĢĢ‚gœÔđfļXąÎJŠŋ„ę—ûž‘ux+ˇëüöĢÉC×sjģgG'IËĮœęPߜ툯y¨ß^1Â;>C;¯{ȡܠ3sīūîûŧ MÁ<ÄMĶĶ!ŸūxéN}~6^ŊLJßvģįräŗˇvÚą-ë *(0FK˛œų-ƜôĀ7=ŧU‹[Õ-­žōҞ\3äŨ€´'zöųÍy%ŨdK§+MÄ;ü‡7˙üßŋ˙{ŌĶ&€ĢqpåĮ$ú€˙7€ ˜K ؀  8`ņM 2_ãw||.kĄu$G~ĢÁ,Äĩ~ėį|%e{҇{Š6¨ÂxŗfåE ¨E1¨EdÂKԄ EutŗTÜáƒīĀ4‹5)í „š¤ƒ0ŧT(Ą-16äĸw3C¸T VM3IŗDč€5(ƒ6¸€bČ…dR!l`nķF>Š(ūíŅVļÅė“8ÕÆFøo~§r÷nƒW0†_x€¨CZÃü€?5ÅOö0JĶ.Z¸!GH0 “MˇÕĀMōÔĀčâ.e&/ÜQ/F*>č.úÄJCƒd8†^Ø`ĄëĀ>38‚Næ+';kö~e­ŗ8•‡%vŲvtG§(iwƒˆš–Wúƒ ‚04‡đā û”KÄVfaŖ*1$öQÕCA“Ä8qų!Pū` g°R"hdOAÅįĀ/™O9vâFF1‚ø'A Ä?.C\z’Kĸ1/sd•%*Q/3ƒÍ÷uXĄm'(ūk)ˆt¤s]ŽV‰šķhĶ’Ą§":„4ķą…Ę#Nį$OŗG0IHOŖ•NA´C•ĩ,Ä#+ŪĄ `ß@ °į0#˛3 @úāY4šZc,ęô.3äSîĸ"š†#Š•!ɕ_Š3ˆÃė 8ũđZųu׆ŋ(7QdÔ:͒†^Į9—‡ŋhLŌW]Õ'jÚą%†5#ŽÃ[‚I˜ƒi˜ËŅ:`<K›tn!äH'ôB’y<(iA$q˜Q 0@“ĨĩCĄS/áN ”‰ ™?„™˛ĸ™Î€<ļÕcšS˜ˇy˜š‰›ģy˜bŠQą$8đū(–S‰ÎĻ7ׄĸhqRĔ‹ųÃmm”‡ˇˇmō‡qd1L"˜ųĩjŨéŪIW/ôÕĶž#%&„ž—iA'Ŗ5ĢĶGHs™°ãYY3 6CSŠĨU!1  5[Ø @°HeB†$%=4BûĐ5ę›&Ô:%tžáų7ʝ߉ĄzĄz› Õ8ļØ*ę–Æų€ū†Š¯7!AåQΉ>ũERĮhtÚ0pĘø9Mq_ (‹­øŠøûY/Hã/ëF’57ũ’S4TSA˛N°…ī‚;<õG“uOCÛ!“JDi`>;Õ5ã„DÅDėĐSÂäu (“Ŗūj¨Ŗ<ēĻo*rĖyVoö2ƒžéiĨĻoE4 ˇP°GŒâÅX‘ū…‘Ĩöw”Q`ēԑkĸĄm ŠlZƒĻĩŸdĶŖ‰’MSSCOs“ŠŖĨN‘F•Lä0Ŗz<ö. ]˜¨˜U™@tÃ™ė°ŸDLķd NUaTETŸ‹;ŠpęĻ("ÉQ%|Ą k qZ„§yēe§í`\Åų–9ß ~)V¨+v¨zF]*ØgžIšČ*w r“úˇJ$ƒŠ.$ũÂihNu€(hŠ_ū˜>˙ZĖ‚=ÁĨš¸Ox9WŽĻ ˜'Ĩ×úe•÷\|Wūt)pdįrÃ#÷‚é•[ ˛+˛˜äœŲ•…Ô„t˛n™n6 z=Ąc֐+û• ÷%#Kŗ!K’:ÛŲđ Ôā5Ú F §\(gr`ō9‘Æ7ĶŲZmÛzmŨędzЍ=cÍ0đw1øŅ$Åh/Hļgkļi;ļŧ)˜ bOŖļŠB;[ļË4ž—&–b2\ĩnvjQûЇRKļ(K„K¸Æķ:qyˇu‹ˇvË@+š‘Kškš‹ˇđ°50ßP *‰ ›†ژËG9­´ÂĸųãTFyBw‡†ZąˆZZËLŅ/w…’ÁģŊūëģŋ›Îĸ@ËģzQ(ĀÛģzĄ nā ŌēÛ(Î*áģՀŧ׋Ŋ×û Ą\Đß ŊzĘÚ(†€jyėæUD˛gLXVĩŗģecŽâh/ŲĐ×ãÁŋÛŧ˙û ,ĀLĀlĀŒĀ ĀØđ Ų€ \ĀŪ Í+ lÁūÁœ Ų0 ė ;p ÜŧŒ 5Đ Ø°Áû›Ā˙+ÂĖĀÜĀ- Á3|Á5LÃė „!;P5€ ėŗlÂ|wqFä? _`VctFV­[¯K‘[{ōģe‰Zk´ąÔĢš[@ņ/Pc,elūfŒÆgŦÆiĖÆkėÆflqTkđÆą"@vÜÆmüÅOPÆO vā€\_P‚ŒO°T w \āv€qĮ}ŦÆT°)`kđq|ÉĄŒÉŖ,ĘwL=ā?Đ9ĐŊ[ -pKPj@^lKM@ŊH<œˇjiW[ČLĮųĖ÷žÆ}Ĩļy;V“Ŧ ‘ŊŅ,ÍÁKÍ\ ÖlÍŌĖGrŌāŧ‹ņ v Ág4ÍãÖ{ŧåŦÎĀû ^ĀĢlŸáāģtAĪāëŽåEĢûÄLüˆĨÄ)­¤Ã"îûKa‡'ĶitûÖ)7æĢūqĩ)–…kž$e¸x۝,Ņ.dŅS‘ie+ĸˆéBíÄy9ļ÷ˇcļŽcž#M%$!Ž+ŌĩéŅĶ š<Ņ8ŨĶ8 4°<ÜšßP¯q™ ĐkÕ8ŲÄVzz' ĩžÚ '+tÛJ-ÉŦgXK}Z›vĸrŖzF1Mœa$"~$Wœ&qzq=ņÖīĘt€¨ķ…Füĩ[]{üü8Ņ˜ĘĐzUģ´ņyÃØ}oáwÖîVbqč>Aáƒy4zMĄc7ÆųË$b§[ˇ€QlĐļÔ~0ĒĖŲyi˛{n÷Jč7ŽĢto ĨЀŠ+Ũ‡Å7Qčû-%ōMũūœi"ÅĮģĐĨĐ;}´Tv.Qu‡m8k‘ˇ‡įq-!Ė$7ũ"ŲIWŲ¤æŦŪ˜ö6q ûíË×É=tĸŨÕÉØeT†`/{zŠvĢMqĄwRíĻ.Šwĩ‘÷-ĩuˇÛ&Ÿ-ØŋĐVëd¤íОgvØbĘ])Ė=bÎŊāÄŅÔ­ēŦ‡r´qÛãƒÜ!’ÔŌ"„JśŗáTäՉÚ˧Ū`ļŪk‡j#jKZøcށ´]‡FgĄ¸ß!§,,"'Úú\nÅ>ØŨf܍×áÂÅāâā`mŌĩf/%§ bŲםsŋ˛]Tū§ÔbJŊõŨ}Ú\=ŋ¤]ŪūĻw’§âf}ŲQˇž'ãÍLã4HÖĒ1K#‘;qø7,CQ}ĖT›vÁ¨{XÜh~ä–ØKŽaQĒ|@ņ—XGÖ=â>WoŌtķčc+’ã2ÄčãZ)ŪažmcŽtFÎ{¨Ú,ŽæË™]ķ}ŪqpŽ‹]´š‘Fč-Û?˙ŗé_B@ŪbčĮáTĻØíÖä:Îv †âXÎ{¸ô1ũ ˇÖ´Ü=ëft×°â~ĩXlâæ]æįwæ†Îv..hPŪ‡S^ãzZÛ/Ŗƒž´u1EÎ âwŌįŧžāCn}f÷˛•2IŽ)ė}čĪũWéŅõ­īīcß&ĘŖÃŒÄeČūQâ<ņĸ`~Å2ĘĖ'ŪíÆūíūîŋ+˜ßIđŽÎqoWœMhvĩ°]Ž3ĄíįŪĒr‹ĒâŦ>’Úåĸ+™Į•á­ÃžŲĒÛØH7˙d;ągŗąč´¸Ō"oãĮ'­Į•ŪúĻō1ã×É$ņîĐĘøü.Üá,Áņd .ø3„?öMƃ˛M2@Á´Sf?‡öŅ€ķ˛Œfo, K- #ļŋ†öčķkVhVk÷įÉ?pīESÂöŗx\’ößCapčö%÷ATŖtīøŲ:ļČ*pė`ŧAÁÔđ D3!z~ÅPgŲ(ĘjQŸ2,Oīø%æČņMū#lÚāÍĢŲ jPåûØ*Ņ6 ŲaFÎMa í@ 'aĄ/S…bž<ÅLŨ[Rj„ büÂfÉŋüÕo Mõü´ũÉ geŊ˙ ’¯Ü‘üMõ„Jč,î#l>ũ"b ĶĪ͟ "l˜rüáīŸĩvÔūũĶ!ŧv ÛũcO[CˆųAS˜pāŋvī8*Ü'‘ĸ@‚˙ąShíßž†Tŧek÷-a6mß$žųMáÁŠ<}ūTčPĸEEZt§?<áÁsаiRĒU­^E:ĩ"­ģÔßžđŪpūķļ‚Ššoß°Ų¤†7!ۘOc~ËÆâ7o6CRļŲPfaē3kæŧØ&ŧlGK„,™nex—YkūܙôgĐŸ>M˜›î•n/Ō-œp7lŪĒũ ÎYælĐĄņ>-ŊųvÍȓYģÎlÚæršÍmІnzzjë–Wg—^8›–+*ė¤XSÅÎā%iœÜ>ČÔ_?ũqũ˙‹Šž ĸĸ´üD0AŸŌ:čŽoĖR0ÂąÖ:kAˆ˛ņĒ- 7ܐ+ģĖæÃüÎ9%lЍiŧ™ÆŽ4– 2舊鍿Š3R¨Cĩ'ÖXĄŖĘxa cč*#8Jƒį ęHč'ˏ/Ą2šūHƒšÂĘ8#ŽÅvėĸƒôˆH#‘T’I'Ą¤kĘ2žiHÆ30j2:jōF‹ęx¨.*ė‚ÜX#ĸ$—¤ëŒ$ ´iĘ*áš2Ë-ģü’GŌĖ#ŋ9TÍ'ŖtT"HąÔ’SJu´TLLË,ōHHͤK+ŪČf›l¤qÃoJÅM/ũä0XŲŌjލ46Ų¤´ēĢ̝”…–,gŅĒĐCļĸÅÖ­šžYa'kķÛ •žqŖ7ÖČ5l":¨•P:ș“îŌf%QëUMĻyŠfŖ!â§^Įîj¨†āŅ %ÜėÍí¤Éđ¨_•ū…'⧆č!É:H5˛Ņ—ŖÅūt˛CšĖ>BØ_‡ žX∠~*áé–ČáÎöMyb›†ˆŨ—–yáÎ↠ÍĻŋQ3†8vĒÁŗĨÚ*`„Ę›ĨĒæš'ˇzđŲŽ…ĨP+HËplĩĸëCÜDôįĩĸæŽÃā™&5ž°Ãmöų•Ķڇ/xØáĢ'ÁęˇÂ÷bjžĻZüy§>K˛“4ߊōÆŠ…ÜÉŨy#?Ɂž°‰‡€…§;ZßËëŗ}rž*ŋ\l4g‡ķ›úÜöĐG§ŧŠŪúŊDáO"\ŠmŽ×hž!Ŧ5ÍĪQMjüÖ(ŋĘēĩđŠf"gĪį°lūã×B–ũŽįōFÄoķ Iĩ%´Fēžø‡GÖÁĶŨî§û]íÖŊ.)‚“ J.—@žDúāJ¨Āņe‚kāYAxLPpt˜58<ÍåGO(MũĄŅAd߈F:bÂÚY„lŪ>6Ȕūãƒ5tāįÅCFPt@”ŒUGD2Ј"„`¸tâ…,đ){d˛Ā¨ŨE~áģZĪĸr 3 ëk‚Pä>ÛĄíZr\]ē"¸aŒ/Ŧc‹> ōũĢ]YÔ( R €ã" x V’ÍĢ]î‡I9r%áØ›"JR ckūĐ9ų;x r‘<‰î2gĄKŠqr’Û¤;iIPJr”;P-ow\Ļ…“äĨÍ\wČ>å6Ј?ø!F<ʏX?)_üĒ  ôQh›ūŸņÔgm~SXÛr[Û|•xōW=ķÖôzbFōMíbâ\…ʉ9{ÚķY Ęį׿IĪģ”/(Oy‚Öl§OF t(bëįŗîų¸†2”(•¨?EØũđ'$kŒ'¸~ĩOsn(RčJJš 7N&Ž+ dG’ÂtXõķVˆô’¸§k¤ØŒš<ˇ6Q3:nĄ=›O0ÔŗÕsk˛hĩ°æ‚Áã Bĩ56ūRC jūOšZF6Õ¨I kX‡ęT‘ˆ)üaŠAÅ§Ī“Ú´CŌSęj×)U}/åĢUdš–pöœzôNëX1ƒ^l?pe(@Ŗz°ĘĶ-ĩleĄZŅŗČ•‘=K¨f5SĄˆ6.˜õĢ× ųŽlöį̆MÖ5ķšŌÄÁV,-Ĩ `mKŲõ™íBiÛm‡ōŌŗ>ë`(ŏBúב6ˇŽüLmtĄĢęJˇŸmŨ(áÚ M¯55´ü°nV{Q JĩäE/Yđj,­ũ4ĩį îeņęŊÖ4žBéæúîË[ā2ÔZöŨīUčg?Åb $˙ˆJQ¯ÂVī•7ŧæ}oƒÉę`ËÎôŗN íAūË'^ g6ēõÜʄœVĶÎ3ĸCŠŨ]\˛WõXAãŖ/m]\܆mÆí­…hzã˙ –äûÍęRĒփyÄãmąƒ5 āšv*ܝŠV+6]ļŲÃÖ-J[0ģe-iÍvAĖc“jšžd>J~u‹æÁvvZh~ : :܍d. ŨĢ‚ųųЙZ 5ĢW%+YėÎw¯žÍķ‚ŧu,‘Îm6ųsYģJēŠēģ~4‹- PK#5uEË\v’a,;ÎX‘mŒwRÛSãWŅß0|g,Ķja莭ËũH#ĸôÃpb‚ôk;láwvwŗ€öjĨ_XCˆęTūģbĩdĄ–9vY“Đe_zAĐÎtd#ģėu{zZļכÆ7Ĩ%ŪHt•ĶLož€÷+-$‘!×Bsx¤Tiį€ŲBy#L/;ĀŦJž¨ĐpĪŧ–1ŧą|â>Ņ\m5×1rw†l×T*Γ—ŗ;ÜxŨÉ:øC*,ī—áōĘ}KÅāgé + įoųvĮFėpßļĩ4ˆÔŲēËbŽ?Īâėˆ8Ų7î°R~Œäw׎%„†CÉ `ĸŗ}´P!’éx)Īgˆ=€ņÚ\ËaŽūøuœí@ŧķ,Žp§GRpQ/:֏ŽtĘũÂF‡ņå×;€ˇY-oÖ|RœX^ŋûŖPfø†TÎx•¯’ˇ7dq¯ûşdû ĮÛĄ…B2š“BWÉË­<÷7÷xâŖ?ûĮOūæ|âqŪ|Ģ!)účBRīi3˛‚¯##č NŦģgŪÅ´–æŋĮĪ6nå´õW‹^ąåCĮĩō<] ąĢ=l9Ūs>2ē ;`’uĐ ”PƒiPˆˆã=•;†)9Ëų‰č[<2ŧÚSŧ Ä>œ[°˛jÁ Y›?ĒHŸ1ē˜×IŊw+A™ °c˙JAŖŗžĄ3Į ū3ũ‹= )%vp<É+BÄÁģ›;Ûģ9ˆ Â‹ ü‘ ĪCˆ tāŌ¸ļĢ= l!˙ƒŧĄ)dÂCíģ Ø!&ĀŠ™‹gãĸzš"Íã<ĻØĸŌS,Ģŗ5&K=]Ķ)¯Áŋ'ŖA‘XBÉ۝Š€DÅ+ģŸpBÄĶ0TCd ø ˆ`­9ĄhB*Œ;;ŒYBɀÄ5ŧ>įk>ū{>lDŒi>LĖ56ę— ŠC9t7Ë:˜p?2ģAÆŖ†38ÄûĸŖI:ŊūÆƒŌ†ģü¨! ŠÄ1|žXCgXC[,ŧhÅëƒÅƒūĀę;0ĸ}(ļ+dšv2ޝô‰Â[ÃEôÆāYD tEëC Ķ@]tX$Ã,ƒ*†ø‡fā%ø†h Æ ’ Ā„<5¤“Ššp>4 ?„F‰T*­S§{|ˇüÃFh9G`ZÉMä ]TDŸˆDt|Ép<HŧĚtŖJÃp‰ôFH|ŠĻY0E'\Dœ<ț HļģɛDĮ5|ŨĘyÅĸ”IX„ÄĻTÄs4H¤ŦŠx‰8€=‘TÁ h‡40bÜ/ޞ'X[Æø2=ųcËk;‹BDÅR–°ŦÄŨAHšŒJ̤Io\ĖÁJr”ūŦd‡VlEˆĘ}0J5¨…°Jxhšz €2Å$G” ~ K­ LôJtLĖ“PL—dĖÛ G×ÁeYHǤŊlK:TˇģœË$› ^k5øû­[ÎÉ Fœ2ÉšFâü0LDśŊW ĮJ”ĖĮDMrTÄÄLĖ›4ÁqË´0„Š HĘĪLMol‡G[€›ä‹íÜJÆ´MÄ;€ČT؜L#Ėõ\L'œĖ° Hp¤Íę;LŒœĢjû ¨ŗæ¤1ŋŗš¸øš#ވĩĻË1CŊæÜAŧ¸?ˆ@IÁLhŠp H‚Ô΁ÍŨDW¤QÜ<ˆĻ´~\ū vtQö¤‚ΕĖüÜÄū,ĘV´ĘõFǔԤJ(•<ežŌj* „S3*ļ(Ÿ{DS›ũbĶÕ'ŊdKc=>LlDˇ˜@čķ@į#ŧëëŌËĮę›EŒY v #hœá3ĸTĘS¤­‰Ņœ"4Vnt˜/å>/´ #ū\ģ1Ŧ¤ąĶhûˆ3mUWU4FËĐ"[MN\­ĩÜKu"ŽÖ“NĪǚ3ŒEF,Â/>Č3ŧí“ÎæųģŦ™ˆŊp†ĮD‰Ų1ˆžCCÆs<€=C)ŒÅ„´ÅŲc9„DÕlã‰wŠĶv}ĐQ‹Ģ2ŸxMUFZĶzũČ÷ Qā\Ŋž,QX L‘•ŊŽeŧ ;se>Ÿ¨ĀŪ[ÖÍą ļā‹w`‡ˇĶ0Eœ†PR<‹„š4DVœŖžo5¤Ž#Wė¤>€=V˛$Šg—ƒŖNāDĒlŊ´ęÜZ[ؒ?ÂzS2õą áWĢ_*-+Ã2čęœP”>§čēC2%餘ŽkūPT‹iŠŽęžø‹†Å˜)û"}ŲŊчˆ;›ĢÎáđV=ƒˆÕŦ]9…]X2Î:œ’eÕŠ\ĀMĢÛĨ].{ŨÜĩ]Ūu°¯9QYj7´ō6}m7åÔU‘Qã=ˆŽS,Ė.,[* -ĀÍ(Žų;žčE dHŽģėe]öŒÜvĄ—¨Pėe‰°™ bŦ5Ô¸õõ^œÃڍ9%+͘+Ģ0›ēĘē˜x%Κ^酰a+1î2`ƯQŗ~+ŊŖ ?šõĐĢŖPAėŖ~­¯ūØŨžŨžŨøÅN•($–S †Üv˜ ƒpĸœ_îĩƒua˛+ūԐQ×õLīmxy<…GwšÜčž8áÅ\ęí°ęͨŦjŠIIŪ_%FāVāëēb&6Nx“6@jÜ`ĩ­ô17{=›šŨK^ÅŲb§ßĖ_ʂcĒā2ՍIJûŠ•ü đz‡čģ"% ’Œuˆĩl ũ`@HļPn” kČSŊĀP ĖჍ>Ž)L܍ã‡bĐų¤ŗqãNN/¤ ÎSŽŽ¤@Aëß–48ĶĐwŖ×2Ļā÷šÛ &Éâ2ˇéœž§’4pæc f¯䞌DôÄI0TfW\æ5LŋŠPĘĪtÔO< `ÆÅČÁĖ ū˜§›ÉĒlž ‘ĶŲēÉĪ ?ÅĖRíԛۋМhæ{Î4ßēš}Sxũe|ūį|čCčačƒ&hŽ§‚ĸĮ)sY%#cĒ3c~c€ģŲ8͏PlŦØˇNëčöčV)ĐŦG]øÃu8€ßšV2"ü‡Ō\CˆŅxĮ`€ ͜fāPËČQĻ8ĀYéδXœÜqB™fĐŸ$išž”éĢé*ėĩ*hÂę¯Îj°ë°&ëąöč9mãy{čÔˆÂX32kSģåæĖÛ]û§§`¯Â'ŠÚ4JKļžūkāÕ'ÛÍJ¤ibšæūkžæAžÅ š6H€Ä(ėGvX;˛¯hø€o`€‡€ûÜ 0ÄĖ“€XōˆzģÃŖs€ĪĶfm0l†ĸVJ!ZĐlŠ ėÜūkö%_Uâmž&4ÁŪíânŋ>nãÎíå&nŨæ`§ģPŦ‹´™Ē tājAã]ÕWeã aW+ÆâđaÍ’8†v†x@‡@RkHáãuMŌļé~I¤ƒ(€€‡GĢt`ŌX€Ÿ퓀īvØRXŦ˜Ü„‡J|ˆv€Í~C ‡îŒ_įīņN`˛āęQöđ˙đĮ_ņ.ņgĒåJĒ‚"ĩšŊ¯“<ūNņĀĘËšN .ˇøÍŪFqrŗšh(€q~đ%dGũLō#/¤ĀĐŅu†Ņ"ÕGíŋ €pÖĘön?•Oûõ;)m'ĮŌ WLmĨRĖ1ņ÷+? u[b?ņ5§s9gķđ~,-('ˆHŽ’îj䅨qžBŪėVŪēöËéƒjŽ]D˛ŖđķķÂ^;ëžÆŦYõžƒ<DqI`a7Ŧe5ã÷ 9NÆ\§p8;ĶĖŨLe9>[´P‡p‰HNūÛG‡u\Wå1Ąv Ĩ^z`}ú⨛ë>ĢÎÂņ|Íe^SŒØYcĘ'Ļv„6č„ļv€N?lūˇĐŊmŪM€‘ėŊöĻØörĪ6ûūKt¯vn—‘Œf0ö‰âvvĪövˇ÷z/č}Ī4B˛ 'ŠzĪĐŠē¨#=Ų:2t‰ŧčû‡œ—Ā62&g”ĻŠĮx˛øĪxëø‹ĪęKéqĄx×jÖŊ§"¤G;ü;i'šp˜GęøČZ sX Ļ}$ķ+뒞Ĩ$霐ÉúĄ˙ųĸ@Åŗ ĄĒž‹O zúÁúuúǧúĢwzŦŸúŦįú­÷zŠ{Ģīú°×úņ‰‰-¨å`ĄĘ3:ŲŌĨ|8v„wāGJ^‘ŦëAŧjC‰;КÛđûŋüĀüÁ'üūÂ7üßQüƒĄ ÆŋopĘІ„püoŽĶø{ĮüQ|xB|Áį|Æ_ŒĪ'}ԟ|ŦÁüŌWũÕgũÖw}Á—†/ȁ-¨‚5˜†Â(vh†ŠŽ/„iõāë>c|=t’¤ŗWzˆlhk( ]q~]ÁŒĘūč§ūéˇūęĮūë×ūėįūí¯Œlx ]Yí'˙æ˙ūŲĀ8Œl˙ö÷†č†â  ë‡~ī')ŽÃđūî~]€đömÚ7 "<¨0!Å~‹čM`ļl߲asØpŖÆŽ?z r¤Č’ŊåøŅCG=jXÔöīģ™6oâĖŠs'Īž>ūŨéĪßLxđfú‹f4(ĶĻNŸ2…įĘQĸH˙ųƒ—ĒU¨^ŋ‚ ģS擪˙´–ĩéo];ŖđļlĄō„Ę‹Uîž Ģ7/ßŊ~ûū+80áÁ† ŋXC×Κ.SĄ˛bnŪ'Oė¤xĸ掊5ŽPAaĮŽf*jÖˍÁŲôáÁŒķÚiØoŠ5|¯˜­[6ä'/,[ĻŌB1i*whėNÎ[9ķåΛ7rĨu?x¸Ü§Ũŋw5ł˙ÔęPĢnŖĨvF<ûö>ĨrĩɏhÖŠđēēΝ*XÍYĨ?ķUy'}|æų'}˙ø‰ „ęyhĄ{ē¨ĸz˛C_MūLŠčŸ6Ás(:XÁŖ†“˙œ““6v|JSĸžjÕ:UVJ%}ŽĸjgŸxZjhŦļÎ*hޏšį…gĩĮ‰°îĘhąę(¯ĩĢlŗĖ"ģ,ąÎFûŦŖ4Á#5Ô°E7iqbMܕYîW]ūu#Uæ˛ûž7iuEŸ—øĩ[¯XhøŽ€„ø„7ZÚpSabú„ôžå/Ā3ŦÁEŧpÇՖ¤juã7TdS%ÅzÖYKüņ–^z|•˜÷™ÜōXßüW”žlz Ī>đÄ 0Â.ŗË˛yüāü/­7m3ĪöŒîÍT}´Ķ?õ÷¤Čđ(ŧķĶ[◮}WG‰rŧœÚg5×ö­fēgjšįYY1]ōØXƒ)2§m]TŅWŊMĻUPŪ÷ÛÖŧų5ÜQ=Ŧß\†œ.ɇŗįuÜ+‹Í¸™ú•MZxÛÜ7Ū’īįsQ@Ķ=NEßÉy~Icēô‰Ļ?m;wĻë/§Ŧūģ—õY[ĶŪeØjU`äšįWvˎ_nčÚ8¯|í#uˇč˜öũģōcE.œMOß0Q2!ĒÕ˙š—=X‰ŧŽøQm_˜[ą|ž”hÛ¨Mņæ-}Ęî{åųY  ũ<Ļm—ã™Ō4'@všICųÎ÷0u@§Øeä‰ãŽRŸ1MP<@ŖņŌÆĻû0ƒLQŸÜØÖŋŦEO„#lĶ˙ė§Â(eOĸáV”ú„|ęr[+¨2öI‡@šŅđđÅģŗ¨NgB„ZâøWz‘n‰y”§7øÄVИpŦYųz)@ež%‘ũ|Y-—ļGvķˆŦf%‰–Mr0uz\hPF° s””ā)×õĩ ļŖ7IãūŲž OōS›ĖĢį?ĄWĮuNp—ØtĄJYBģåŒ(@“ŠZndƒâĄë)˜Ūš2Zh6ôĸD…2ž)ū§T­jSíækúo§FkæÃnf†ä1ĩŖr#ZĐzF…OCŅP}(¯Ũ1U¨ķŌĮ?˛ņ‚ aĨÜyG§čŠ™ĐIt4KMV%+šXĨtDR˜¸ãX:Av&ÜyÕ8kŠĮQŦâŨ›>‹Y(šÉ üG;Ę`°ĩã.°§MqyĮ´áGv \ZÕZBY-ĨvŌęôjēŲ~ČU”ɤ\š×„+”ÚØ7ؑŠuPj&Ú`]CÔ‘YƒĐ8 ]ūeŌŽw°ö(7ƒQ•G í’EŦVž{”đŽ÷tĩkŅûŨõ~—(āäK8ī2ÖFQ\"r{šÅ‰ÄuŸq˙]äŽĩˇY žVõ°Î’`‘ę‡ ĢQWTZ=QAĒp}¨‹\PĸÉ7ĒЍ‹ä(":n‹ptĸš%GŲpB2WdįøFĘFŽuĩÅI>ōEˆėĄ›YÉQ˛Vš,.ëÆ–É:Î]d@[^nnD!rˇ§aŸ:Pą4Ųėnji•ļ EŽéēĸ27ČĖKÅÅCҊ @¤”ØNčF-ØB ęãšLCehÂLô2œ!":CŖŨūô„Æœ÷eHŒ1nT†4ÄÁIđ8ƒ}#'˜!K’nB,iM…Ķuđ4¨Ņ;ę5”úŌ¨V5Ģ]ũ X“Ą(g0Cp¤Ú¸!Ū Œbœ9iÂįĢ)k? c¤j8k’ ޝ8 Īę÷ģ†Äk:}—×~ôãfe´Ž7Ž ci{#ߐƃq„"™ÅžēĐĄƒĖ/ É„Č GzøËÂL\ž(jÁáaŨ ŧ?ĻR2ļÚŌp›¸‰"˛†(”#o`ã /Xô™mtĶ|Ūp-°ãŪ›s˜“Ŧ¤—{u6&‡âŊÃëqÎU)ŧ‰Bš›ac iø@|S7Č%6NbĮ‡ķ\ū%g(+ߥ:C‹ž”Ŋj(ë(T›Ŧ‚õ kŊM ,ûLž~ŌĎ=eä ÂÕ@lDD ĸ•–ŠĻm÷É+6ËŽÆknķ ¯p}ØŲÕîmŖP*´_¯mĖ"ũšŧØ)ĩ$×ķ5ŲĮ;œQ:ŨÉÃką0ž"åYxœŨķwō,dąģĀė’ŪôCA=ë#ĩ*ĮŠ[ąÔėMÅ_vČĩ˙P Fū äš×ËTšgYî(ŋJø†áßõhĀ-Ļéžũ‘#'œØ¤B˙ŗJoäŋjVããōFĖōĢ<í°˛ĘŽĖEˇZ˙˙_ÍɚÍÄ:đÉhņfņŸŸŒ˙ūņß  Ą …ādŨĤôƒč\ČfĩƒŪq›ËĪ<Ųža‹°<^ZíL;¤AМ`öĐËÃÅ7ŸĄ˜žLŪB™‡B‰_š ‰ …íŒ))מAOÜĐĮ „ åĀĄŨ!­ ĄZ<š-Y’mYi­Uá´ G%aQĩÕR TbŠK•Ô—ÖĐy!•ē` ÍÍĀ ÚŅáO‰áÔ¤™Į$áJLߊŒîKܤS>QyüƒT­NXÅEĄĻWÄtŸ÷MMÄ •š…yxÃ Ž›úĨģõԞ 0=S!:a’á:bvÉX¤"îYUdāPEJ>Yâūō‰Q@b$öMU!&š“$1×úĨTZ‘”?d §ĀLĀá‰æaP¸ žĸ*ö„,-L6 áR,…!^Ķ"ūK#)­ŲFņâ ÆĶŋ’‰Í ‘Ôrqĸ zbOĩÅÖĀâ]Ŋ€ÆKRcHšâH…Úũãnã QcV#ôė™VšUß AŖf…É÷˜ĸJŊ ß5ĸ9’Ņ0ǐRŠáŠáã?d`Ežß}øI?*ĸ¤BF$K.¤(ä áLŧÃî ÷]#ŪâÍ E[ÄT:ZPQdÅ ŒãF⍁‘<ĸ!=˛_? …ŸÅî“îKjĨ:ĸ bššūŠmå†U}eRÖMTáÉC‚` öäžĖQP×Ez!Øi$0ęŒŌ’PV„$T‚MútmÍf}TVęÉXĻeY~ÍVĄå&f: ÚĒ 9&yteք íäQōœNÜ$(ĨPîa ÔÂxŖ2åũtä1öT;ĩOW:•O‚ØY:Œf™Ęŧƒ mŨOôĻŠd—hąŨøM j !§ŒŅćLˉŖ[ZâÂ$VVėĸPJaí"]*ĪCVAŅ`ĐĨØ_.TUļá†É3Ҍ˛Ļ$zQ;ÔÖõ&׊EMœ×ũfoŪĖ>„pļIéĐí™Jorā?`]ČÔĪN9ūŪ"jū$8Z§WúĸbO"^kŌā<öN=Ē”T‚ŨLDDĖP‰•ˆ_ˆ† ‰edŪL¨nōƒ‡]EyM¨ĐŪķ˜V`]UJqފ~B ô'zĀpĄ gŪt.J \Ž&i֌E~æ Ŗv˛#ÔRõJ™#t}üÉ!CŪáW ‡‹ū˜éëņzyVcŅD}ęÄw);œNœË°ÃĄ'×iáæ^ [&¨H‘Ą?%O %bNJR(@Æã9Õ`†>Ĩ7͉—¨'aR€¤åAn!"w nž8ŖÅÉÍ×Y××Zzõ雐 w´ƒ›ÜūÔz!šiŦ΄5 ÃRé+å>g4âĐÎP_[>hH æÆüËUēŖNėKDx¤Yi*‰'YąĄî‹Tx)e>Ŗ’d*ÎY›XOŽjIŸ†*;´C´ę?8Ā?Ėk™˛VŽĻéQ­–)ŊæĢ™ŪēΊ3 ;ü*}YĄEy&R:azET˛ĻKW&L˙`Öŗæáy>Aú5Ĩ¤ē&î–}ôRšTÔĻbš,VøÉaŊfĀgQ?ibŨîÜūC3ėC8VËÂ,VđėëüƒÔ6CĪ­UÄŦëŲ‰œ6UÂcWlV¸Ճr'Õ"h^ĨŠQūŠéا\Ģ/ŨUĻ‚ÉyÆLJÖfdžŦVŠījbąŪp}Ė *v•Šč ŠÁŌ  ÂŦ™Ž…ßš)āâIÍnfö)b ĒiŠāÚė-&ĢUÁCîŪâ­Mr‰Č…nlkū]ąrč}đÈę7,€¨›R°ŪÎ9æzr•Z$íMôé‡õ) Ā~ÆŽÍŦĄŠáŦĄÄŦpöî¤TęLŦé=q ’ōŲ ~?|ƒē%kmōՍHāŒ… E›…éj^iØzĘ|˜>d`lũG;`Ũ7 HŽ)kĸĄō‹ŠŦ¯p ÕčI͚&îŪ¯MĀģšĘāö/ÎŠ3°ëUø/Mū@JėÖ|ĸwNĢFÁÖbÛtnqáQÂÛÍt­Ø>YØ›\đôøĪ:ĀŒ™˜æŽį r‡ōŸ\ųåx‡āØÄ>LíęIcīj›nŸíYßŧŪqšjÁ"§ua Ķ"į¨ÚzX×|Š"Úâ[ŅĘqéÍ=hö"¤2ō•6”ŽÃÕÕķo>dEsÎ×ĘÛ¤öSšü•Ļ6xƒä%°ėČWI áÜĖüÎWæč1gJČ1 ‹ĖÚ1<ÜŠ|§5ŒKˇŲzUârš wôŽ…ĖĻ|@ËÁIļÍĶ ´ƒ\ś5vŸ¯U?¨C‚ˆ ÛŠŨæ–RūĮļ0#ŨŒČhHAØ[‹îžĄē6lA ˜1N –}‚"˙'įZīMÔi€.q2ģ¯āĖr¤¨`"âĮĄ*¯õ‰á:L/[§Äb[|‡XÃ&ÅöBę<ʋ÷6#qĮxEŲ7tCø•yC p 䀸ˆŒ Č† ?´‚´C'A'<¸sUH…´ÃČ}ˆ†PƒŒhCÉ!ˆ†\ˆˆ`´ˆ,ô°v&,ķ?Pí^ä~pæ‘ÅĘĻQØĒzhlWHž†ļŸCŲ͎\„7tC āČ4LD7hÁ°DKø@LIõCH„EPB õE AÄEāŨPDT[B|Ū-ūĩAdõU[„žU„@`ÄWoŪ…ã'ЎŌ×1°V˜s䂸­NŖtīˆ!–üōဤ¯1ådH(Ŧ­ÁĶ}@ŦÁÔĀØĀôvü€KToĮdČÅ Č…dĪ…eWļ\HÆeG†eĢƒu6kXö”ö † ¨Ė…\ØŨe[ļfŗļd؁j3h6h3˜Ũĩ6j?ÁnĢeDÆk?AĶĨ€ԂŪåg ]Q’ ÂĩPhCĒåĩō¸á}gSŽ­G¯qü•[LÅ<Īsl­OĪĀä@X‡ˆĶž"7ž |ģˇ|+ˆˆ"ČÔŧw~Į7}펃Ø7÷š…ūXÄYŋœ’‹.Vmôná/ĘTø`÷&ē2–öڀ7ŲļŅNM6Ø3KpÁ7Ŧmģ=cŲžĨe–(JfWV•e^gœ^Ņ8+/°ugT Ŗc:JqÛ FÔRžŗvƒ _wōĀ[‚Yā,n7¸¯7)°;ÔōœÅĢps 95‰‘uelĒî?@ƒžūí!ūp-ūÉ'ĨĖčŽ˜nŨ‰œA†ÄVD_XIXšWÉš_ŧš]ĄY`:…jMĪ?Đ×ĸÍSXĻüÕÄĨØUX×YYÜfy=Qœ]gÖZ(į3ƒĘf—ĶĮhUJōĮĩūą 9˙9@c•ĮôĐ:¸ -hRĒ[ģwņžęŅ•ŗyî ¯īØĻLŋz{bXpcĮx—î#LåÛNok„ũæmš7o×Ū¸IQGŖ*‹Í’Qr†šŲ2gâH„Wæi†Ļ0œB 5xßʤ‰íZC‰ßœ˜Ézõ´ß¯c3¤mnŨexû.\qãŋū“7¨ÍĖ“ÜŸhŠá ۖ*`ʕ{6ūcû÷˙#k2!Ôŋø Đ-¸ūšĪ¤úLp@ũĂčŋŒ­ÉšęĢlüBP ![ęˇZ(›5ĖPB *^¨Â5Žp›o´AéˇÍ€úíˇîāɨã(rP(Œ3ĢĄ˛ŅȉtĖLHŗĖšČ,%âņĸĖ€ôfIŒÄQ›$Ô(ŗj~ķ&›7´¨ĸŠšāÚË? 9lķǝä"˛üsĶÎĶtĒÎęēĶĪüœ‚¨°?Ũ¤ÁõŖMBĩ!Â[ŠĄpJãšTČÉĀФ‘ ŠéŸPKĘh§NOúg!0;‚'ū…ÄJhUX?ũįՕHũÉSxPũ”׈zu$ˆdũÕĶRuĶĻ‚>Dŗž…ö\´Ņ Ãz‡?§Ív@8ŊV[;ë#ë3ūû?CÅCÆĖũVŅMa]Į!äÎi?}ā\JRĢü)iS“tb0Ŧ€ķķwĻØ ž“ØLøßT¸*„õ;˜áf '2´„g õCp>iÛÅSÕá1ÃŦ’YÎ*Ũ”ÍbĒĪ–íŖOáđõ‡&šk4>ÄåųO9]ėĐąžúÆčĀHú͸<ęĪŲŊ°mÚiˇūĘķŸsúņgĄĢiŽ>ŠRuSĢÁNká“ũé_ŒĶÆ Ō ķË1øŨ$ūk]ĒĸÅÛą|’ī‰&ĩ†Čŋ™Īkí†Öi[Ÿŋ×6M›åÕ)ņʡũ;á~Öá•sŦ}ΏŦÂĐ/ĸ ĩ01§[uģ4´öŅ:¯zöOūĮmĻÚũOą—Š{å~­4Z _”ŦôÃB=úûô†ũ°×˙CėúļÂÚ/Îŗāybj§æcüû­ÖVÕa}Ę^ŸÃú* =ÄCåßJávvčëü­´ˆ]´ ëüļ=AiQô1 ūĒb;Šĩ¯[sÁßõō7ŦƒlÁ €ÄkĩÄ$ÉûāÄ0ļ”[Đ)Š‘ƒėV@Ē%{åęŊ7C~Ą Q ū‹ų(ȐÅép‡dYČÁJåA"nNÉNRˇ>īÅ&ĄÆĘõ@tņhÖ[bZĒĮ@ĀĩŽnˆú" Ī’Ã-Ŧ@Ū:ãŅFŌ U)Ą2odÚ^ôS čbKŧXēãnąnëŠâO'Ævīä]ČDĀŠ)*vÄ_ķv‡•Y2/ljG@Fš†P”"× )0ZR'%qeĒ(ôJũœƒ!Ū°ÃYJÂÛAŦ$&lGX†%Ë>Ŧ­l ;ŒyLeĻ ™Ä,æ0yiaŒ`öúĮ.UĩF¤Åō3|™(ˡIN.HCdqÂʲˆA ũį7K;a*ahČqŒ`&qÆūoÖP $rĒōF †uĻdn,õdæItRE„´™ ;šLjūÃu(ÄĘLcRSĸĶI4Œi ”Øá|NyYÔĮÂu6e!kœ'dđNxČ)\csJϞ‹wãäD)ZųŘū8Į;ā1;äD™’™J7úP€E”ĸŧˍ3šŌPŦ:´ĄŨj3šĖh—¯”Œ$ĩ&ÄP6RxlĒC\úŌģˆL’DtëŅøÁš]đB>§.§"¯ßŦā?ŋôšĄJRÅĨ˙­4¨,ÅJOŽruĢ mĘU3ÖTA•*í#guâ)“ŒÄdqiîÖôEˇōã+ؒ+[ūr8§ų͛o! õ:=Uz‘•Mņ‰5öĄ“ÖédÍ@É7T“āIEí8Hp] €ĒX4Ē•îC ÚYŠē’×=‰t“™YŠRÕĸ‰tŖ‘āN…§}¤îtH<§hŦ||-lų62ģpŒyÅ <û*Ã7ōC'8xG•[•)Úđ†āAļ< !ØuĢ(^b&ĶĀHč”yŨ‰zÖą&ņp+# VČn8ģ¯,‰‡IōC*īhGt´MJ x”W9Øm÷tßå,/¨d|QØ_1jQˇ=åņã€lļdĒNÎŅ` ᤙūŽh“'â‡JŲŖė8@3AūlâōjåœĨ¨wSįĢō2ąĶ]&E 0ÚTyĘ´"|k›Âųƒ§Ķ[:„­ģ“ī “ļdŽR•ō|iwãŧ“oŦ`Ŋ[ŠtáQŋŧƒ`ØuŠ\axwÕ/>0ŒWĒ6Ö­ž2ĢŊÛŨX¯úĀÄŗ‰ŋ[`Vŋx™ĩ‰WŨ Xgj ĮhÕ^ĨŽE4Z>?–2dIsgn!ô2Ūڑ`ĢöpŋÚšŒü ĩJĀ{fPxĘį 1ą=å|gZßS. ˆ1pĢŋÖ÷™Õ,cbc:šQ61SŽ[€„ÁLđķ$åĶÍÚÚ022Ŋ6ļĶ ū‘¸ÖT‹€j›ƒ$ ĀŊū,Q–~ŠwpØlM)ũب+á}€Öˇ—Ĩ‚jaŖ:Îæ^8ĀŽ›fĸëúØoƝģËa)OųÕų†ķdQÍŧ™O_Ū‰.ŽZio›Û?†ëĄ?î˛Øū°I…S)ˆÛ˙ę†ã&÷‹ĢؤذƒŠĸŽy™ßøĀ?Đ/LÎÔSŪ`Öafũ,ÕfÔwЍwŨ˜dëfū‚'~b:ĶŽy]^|Ũ}ØÎÂD3ķęĨë Pāß(QUųÂN?@ŋ=P.tĶî•ŖÕ—äŧŠÂüËdŖąŧ†–Ÿ,;l‰ĖœĮ ™ŧPøū'´ŖĢ@ŋ"#é.åËļgÕS˙o/TŊö—ŅģŽtķĢ×´>Đ/Û|SŨį%ŅŋíĒčēâãØüáĀĀ˜‚Â<ĨĀÚô‹ėâBN€Ėž‚/+Haüc,RĘĻøK>’oŌčŽ{œīųŽ$Ãđ ™ŧæŦ!G.…%4+ÆŌĢ˜Ē˜´ŠžzĪ™Ž`ŧĘúđßūC¸ŽĮ˜ōL‚Ā” 1¤ĸŧŦÛÚÁ@&­v¯ĮĒâ/ …+°Įč¤ tŒ ãQ„"åōgåL'†F Ē5ėĀŠę ļdŠ8bĄ€Fîį „°!Ē—ūfXūĸTÎ Ô` ĄęÉúJūõ­T̚ŠĀh c —‚įaā!ļî_üĄŊVFėžLČËĸø˛Đ#ôÅ)ĐĘbxī‚`Hi)čuH—r `@‚!˛aB†"ŊPâŸ*ƒ´œÂÁēa´ ?Ģdž ŦÆJ˜Ē5ËĄÉkJĖ 2LĒȊB!|ņSJEGd4n‰‡Đ<. -PDŽĶĐŅĂ@€ƒŋ‡§Zίzk˜ĸ5V◐HFD6xFŽ€ lĀt SZB72"#4B!B6€"&€¤!D!!Ō!Å%nq!e"=#)ŌIj"ĩÁ ’ãÄâ¤d1Đ ‹,ĘíūĐQ+žâ%‘f?hŠüámd•`‘Ō^K_ÚŠD °Á Ŧ$˛ĄŽĄ¸@tĀ~ t 6Ŗ*ĢŌJ°ō*…ÂJļ˛+ĩ2+ÁR+Å2,Įō+Í2+Í2-Ŋ’Hė¸āEPRˆ,¨U§BÂ'ËZ%&ßDC&į7ø¤_ˆč ëwâg§šŦWŌŽ€R"%0Ä4 ė` ĒāDŌ` j`vĀ)} x *¯ā Nc4Eŗ4Iķ4M35Qs5Uŗ5Yķ5]36Qķ hŗ4iĶ ž ŌĀ ^ Ū€ôdėžH0qĻlŽ0õ’o.Į$@VčrvōdŒ~ô‰'ÃÍQ|ōūžÂČ0~ƒ rŦ;˛á¤Ē@ ŧā)ĀlĀ 1˛=Ũķ=á3>ås>és>;Z ¤*ȁ†pė…0•(9ˇ§d,ÜÆ!ę"x)MüÅōáļ^ņ:E2ėNČ6BØÁÁT2JtCÄä¤A v lĀ (]ԑ¯ĮōT4EQ”E_´EYîĸ HŠ‚Ž01ÕÉ{Ú_lŽÛt)T”úAøđö§@â—;+ôĨ–ĸz–&G^ "B$$ęË,ēƒ=ŪDî'j 'ˆ%L˙fĻČLû°L}čKĮ4MŅ”MÍÔM۔Msp#XøP2Úø‘Xĸ„ú2@´ÛūE_B'4ž†>VČ:eh\îžɨà bÃ~"ρ&,Fv†|zĪS1T)GTAĩ@BõSáĻTQœš¨÷lOúîĀ9âō‘4,$â•&"P•n.dX€”õ'\"Ž(BŲ…ĩåIįIa˛DôŖÖ%rē&UāįpžákœS—U*$ƒĐŧ•ORÅ[ˇ5\Yk\ũĨ\e†\ŋÕxô]Áõ\×U]Íĩ]ŋ5a~,!T‘ŠÚA›æĪÆqÚČįļŒ~ §íVb_æQR,ŧcõf _ú˛Ĩ·äHąĻjęE÷kšv‡Ôqφ‘ļü ÛáNŌwvt‡h-iĶN ũY‘4Ļ>På3‘tԎÂŪÃ2Z 'Ū`FQHų†¨gMgEeļvŲ$eņGŅbˇeŸj)䅃`e'D€Á)m÷뚮ø–@‚sOˇMnÉP~Lū]ėQČĸœU]ŧTŊ(Gˆ–cĶÅd…ųj7E]v|ՑwshíPTw&'7¨OžĻ$ė ÅQ8Õ6Nd‹24ˇbuoˆt§w}ViŠ\¨rh;=$îĀ7~‚XÂÅWkÁãž°h˙ˇAō$ƒe7q˙˛mú%dÂĒÁȀs?%В€fyáVhß yßNz7¸.{ŌnåĒo"ÅAĀŅ)B6Ëx“ėi-…n†~—d~æf&酊rđĨTȀ šD"ŽgiuÅ&sÛVĐG€?7PäŽÉ$tˇŽ7‡áEiBd3Îd3°Ō3˛AŠ6ŠlD˜fEŅ…wˇwY~ĩū.XnĄ†„$ÂR„=\ ãB%ũ5yÆÚš7†įōsi˜ną‡Ą4Y—Ļ;Ԁ6ã`\` \`Vä rL!cĒLUYX „Žåã•ËzbY–U™–Yšĩč&~fš–=ĸ!ā($)ģA Žālķ4‹ˇMv"l쏈ŋøČ¸@Cˇ y wŅR1Æ[#€Eiœā;āA ŌāœĀ¤ Ȁ5žã ¨X"Ę`ę T–` t‘–œāōI:Ō  œ¤ šā;žœųšž šā 8ØŲß9ž!bžëš:đLfcŸûųŸƒœÉ`'œĀ ŌLĶ ´€(h€2ŽY†ūkk÷ŗ™ˇpĨ?x†ļ€įņ†ĪøĨ2-F_$#â Â:ĸH23pä|#Gę°íĐ!¸˛Ŧå:C!ėPKmGŠäFš¤¨ģˆ1…&ÚōZ›úЇä8ŽšĒ™¤![ÃIĸ&ķ ôS­J—•Y2˜WWû\ųTŒ§™zGˇimútīæKB5%ŌUrâ&zŲšî§GĒÖCƒ2ĸoĪ"‡HąueGbIa.û%äCą'[6,Û!Lp'rÄ>āIZ`rķz§į†w’ų´’ ŗŒãŠĻ_k¯ūg!ÕxTø$sU k6c(pâŖ<Ę{TŅt&jū`NQsb‹šĘšEF?ŪF!Ōā”ĩáŧ0wĒô­ķ‡pÄBŽa’ļwŒ.ĸšLķÚ€ĢšîŽYČdĻÃ]PLGv_42ā"a*æq™ÂæĶaū[§õCdũĄ´üû`äE_Îa”PĀ}‰[Â##Á†ÁĪÆÁ•ĀOĻ~Qb \››l›’}’éZ’aÉpûhšŧ÷K\Œæ?ë[ÁTrfŗN0å¨_‚7„˙û˜pš)<¸ú%ÂáB^äH`JâĮŲ!Člȋü˜Žpn ū øĪŸŋíÂŖâ A‚đœ|ƒˇĪāË3jÜČąŖĮ ü/a3„Jž\ɲĨ˗0ŽčĐģāéüw3ĻΟ@EŌ$YPÛ7'A“*ũĪ•šBáe{:sŠÕĢ1›>q(ō ŧo[áôˇOaM‹DeĻ ÉõaÛĩZ”RíZ¯qßēÕ8’Žß‹g‡ōƒ÷ĸáP…˙$D‹ĩņU¨žûˇ^œ‰Ž3köYu`ģū8Ų¸ęŨLúcgŧ ŋ™]ēĩÆĻOë†ô[ŦëÛXĨRíJŌŠÃfũ‚ëYŌ`Yvc‘—|š?}‘äG6šÍ‡Ō{ö¤lĶúōÎĄwŸ^ũ]õ›Po^įI“ßŋáÍĮîc§3fˆ$á=™ .î˙UEœ{ųíĮ€*EW€av`‚Žu×W[Aˆ`m˛ą5•mv’VzYԔ %!×Îdė°c B<9wPEr͇œ{c͕âl0F–ĸ?ÔÍFĶŽ1Ō%#‹zåˆĐŽ=vÆNBŅ÷ž>(ÂcG6j‰FŌ •䟇­I¸Ķ?ƒæ™?Uå~š÷ šWIHqūŪŦgiÎ$WmrŪéá`ž č•7W’¤M6ŪdÚ8„äv7ŽÕΎ‘&$”6mã:ëĨs"ŌN6šŽFĻŅ4”É­ĀøJ}e ŦåąücF>ęō5ž4!ūw(į0jÂĪļ†ÂÛPĢ.û’žPƒ¨<ŗ/Ą6žP3ŊPČ`ôƒNÔķĖ˙DĶ1FŠ€*ČēŒė—BáåXØôNx*ˆŠk2Ķ—ėiBhöƒ$ß@#?ejNVΑR‘ÔøšjĘ2-W”#̈́ĩ‡zŽĖĐaž‚ÔČä›! Iž„*´%‰ÆD ĄŅ“b„8ÛR$=]š™š¸Ecdĸi†Ę(ÁzŠņ›ŖŠL09Ö)E Ÿå QšiŌ×0ôĨ0u¨E9b°lT(0 ¨N`šKS§y×M6 ’u§ÉQ@šxÖ8šSdm5ĘĪ5Ęë‚õǐ3ū&‡$z=0 3ci¯>(Ž\ÅcF’i vOŠÉ`&E”ĩ$ë  đR†Ņ¸ļ&ˆcëeƒGwĸL,š<Šähō,—žQ%Ö¤Ė?¤—w­E^Ņ<›ŲReļŸ/EfTœĒ˛`đĒfĄœÅĸŪŽ#ėp›Tč[Žĩ‰{.iwF”ĩnõĢb\-Ī´ĒSģļœyu”t&R ļŧidŒ]m`į;_wŸČäVå B/§Ü‡@Í8Č1´ûRÆ§ĒŦ¤b@ÃˇdäRM6IS=ˆ `ũĘ î:’Á!X[č˜:ģØŋ2ģĖŖKœ3Á>ÍŋmąM­ū‘Zc$…ĶŊËsŸÉ_}ÚxŽ>ÚfšjŨT´ Ž"…œfBŨmki Ã?Š*\ÆŠ3Ȍņd,ËI3 wyA6ÍhŸä2ĢžˇšžáŠ{\Äęūx/y%ڛãIãĀcŗsVНmE–ŅŌE,ÃYX’5ԇ$\/āÕ7ė ) ¤"ÎŠĖŖ#ąFŽäI?(I–ĸÚöŌE˛-Y&ķJŋČ —Ž…GŲįNÛŲ&Æ}slK™ĖJ%~–4c6l—ô¤ŋs։mŒØ¸tпƺKš ¯pg;4-­" ŌáŒØĩžl‹tĶ…7|# >Ŗ[žüZ–uųj( ąT Ņū%Š›$éfí?PH’Áôk^‰wZŦÁî6wMúŪ ŊSŒÎûŒņzĄNŒr:KAé×Ā&öLßۛč#8•´˛eÉÕ~ŦÃKā…'cÖ!x´ˇŧ|ԋŋŧ†tcZ(āWT‚:DC'fĐę~W‡i|… J¨ƒāî\ķhІvjG¨phčÄ AÜ7ʐĄ—Ģ Xßyzūķ¨ë¤ E?:’žôĻ?ŨëS¯úŽĻŽumŦĢ/Pʐ'ā qHAė 鑊œ÷Ũ¸°üÜ3ĘÖ>÷Æ­čŌ°ņĐŅÆŒÛ*–‘3ZĖđ7Øh—{5E `ĄÁēĩūCŨM'mķÛÕi7´eŖkNƒšßÄö•D-kRkÛWچē‰|÷í MÔĘ64ڃ+4€l×tû¯č„L‹ZÔåˇoLãõ<93yģx֛،iĮpúQ+›Úė‡:¸mĪÂÛ99Ô<įÕŌpĩ@pFŠÛ˜kîsÁ{'ũ1Dáy•E ÃCč°žD “úoųŅ^x0'2YÉļB 8^b/ ¨Õā|ņ˛{%‚FG;‘@ŨįGg;vëĐlŠ—‚ĮÂ[cŅ0>tYÕG7g~¤a[57q(w0†’Ņ)¸ Ä™UIļ5¤&J—)–DūŌņhŠr$Y8jVØTØ"Y8EV8åĮ/íuN0čQ…QŠ•‚OGx–NJÃ#ƒ1UÜĸB<Č9D:€Ôpæ_K#BU!ķVJ$…Úā"Sļ įĀ!Õ!)"ņĄ{U˜Ø"W8#ąWdH—HŠØ´‰–GŠ–5I•Á/Úđ@DRĪáīpsՇ &dįĨ]ĶÔUđ0`í׆‡+qā í7PØ2\Ņ(Ō“M-ņ‚‹TU]ÖH9cR#´ąkžĸĐņ?"›vŖ–Zã‘4s”ņ5–Y­ö‰ sībŽîh\š"[ōȎQŅM˜†ū„ėôA߀+‘¸Iįr6ö+č\d3´.—AŒÕøRŸ6†Gg%ž–$âX~Ā%Iõ[ī’’â –SE˛ąb&ļš1ÉČ"-!ŌÔČOr҉ļ9SՂ|ø}Yb1&a†‚ĩá á 1kwE_PYG5‘O›įN‹(U“Uyn‘AC™‡ÚĀíĐ@(ˆƒKU\´–4 `Ô#-ˆ29áxôqn,%zdf>"G€ÉŊõg|D$ĖÔZŨgRĖQnvā ÖĀeŧxx ‘]Œ™Mĩ–3™FH鑊}í0tž˜.I-æe|ūŲeEg)fņ´'›ˇ9\ą.`™˜™ų g—í 9‡F•a™—ŠTØÅ@Ā)—äõ?Ŋ2>įe\nQŋ…“Ļqf¸E•Š€˜VŐ?Ϙ˜SœŲT~˜LDV{R™ĸ%ž"ĸžĨågXYnDđĐqđ%ĩIŝÁÉKÔ9Q‚UleÄĩÁ!P¤Ūé`^ ĩ)ž4s—Ė•_đi1œëYœøF5æ~CņZڐ(jđŌC 4AY“Ãq ö—}9˜m‰ĸiéšW†A)‰k5ܤ›'ĩŸ žšVą"D……ŖUĘ`\y‘™™]BĒAyŪ0Bn@zūûgoã”#æWĖØĄųACōN4´&1vĨ'hĨZJDĸá äBjR2؞4›aä \å0gą¤L*¤6Ä)§kŠKÉŲĄß \`5Đ åōf?ëŌfPžĸ vđŌ3‰+°L įP+°ō;Ž*Äã<‚èÎÃ5ĖsãŠ[Š“ •zŠ„¤ŠœZŸmĒd Ēß@WpŸė0Ž›–.ߎ)žÚŲŖq!%Ö*\zž:‰á&s¤G™¤Ęb§CŸŪpØ ¨äbÕį/nC›Ø –( øĄŊį|Nô-Qä{EŗzY3âJŽĩ‡}õ2{FĄŽņĸū6ŪĐGcĨ+WPŨˇ ;úʞa‹›(Ą8øžC$”Š,Ųu° М2wF/p%Nôd1^rCĮYķIš;ˆ/ ķ% 1éæ%;nŊö!ë#K)ہëPr÷*°4 :) B[Ą0‹GŦ.頗ļ.HPĄZĘŦFMkiŦnJJڂ0ŌazS÷dŅ)ąFjŒÄä”I}öPš4ĐųÚÁéôĩ3ļÚ1ļ“Ãۊ(ŪĐ 5€ |3 ō ‡Dk­?F*ģŖ2Â5™DQ&z™Š9ąq ¨T‰ĄČ"ūĀ”i dī@ībƉōÁiĘ1‹šë#”;I–ū‹šæá››Š$SĪc}kP/Č5ûW[´F+]fā īöcą…]rˆ¸Ô갞UĩNá+Ãņ‚ [LTĄöļ˙p˜tj§ō"L™PŅŧ5ōlãąÍ[…ĐKļŨQiՋjA ņō q  ¯‚.Ãz›šiŦah%ĄaVʏö´=š¸ĘBą.•LgĻSd– Djđ€—;*Äo)ŗģ[Ā—{o>tüĀĀeĀü€ĀĄĀė|šDåōŒtŽGaĘĻŖ4ÁŖđ›" ¤Bg9ZÎÔĄ{ʞÁKbčéĒá(æF_K*¤i’!oBôÃnVo1v)W3?ĖZAŧĨrCœ„qŅų€æFˆ0Bem*@õ‚Ōę` Ô ƒ\UŋxŠE bŦÂĢY˙•gWęŦ`ÔøÆtÄahÜÅo­Ëq0lĮ'ĖĮđûĮ€|3peœ\Ȇ|ȈŦ8xŦT~œČŽüȐÉb”„,ɖl!;commons-dbcp-rel-commons-dbcp-2.10.0/src/site/resources/profile.jacoco000066400000000000000000000016611447311732500257120ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ----------------------------------------------------------------------------- # # Empty file used to automatically trigger JaCoCo profile from commons parent pom commons-dbcp-rel-commons-dbcp-2.10.0/src/site/site.xml000066400000000000000000000052531447311732500225470ustar00rootroot00000000000000 Commons DBCP /images/dbcp-logo-white.png /index.html commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/000077500000000000000000000000001447311732500220115ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/building.xml000066400000000000000000000035601447311732500243340ustar00rootroot00000000000000 Building Commons Documentation Team

Commons DBCP uses Maven or Ant as a build system. The maven build requires maven 2 and JDK 1.6. The Ant build works with JDK 1.4, 1.5 or 1.6.

To build a jar file, change into DBCP's root directory and run mvn package. The result will be in the "target" subdirectory.

To build the Javadocs, run mvn javadoc:javadoc. The result will be in "target/site/apidocs/".

To build the full website, run mvn site. The result will be in "target/site".

commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/configuration.xml000066400000000000000000000440521447311732500254070ustar00rootroot00000000000000 BasicDataSource Configuration Commons Documentation Team

ParameterDescription
username The connection user name to be passed to our JDBC driver to establish a connection.
password The connection password to be passed to our JDBC driver to establish a connection.
url The connection URL to be passed to our JDBC driver to establish a connection.
driverClassName The fully qualified Java class name of the JDBC driver to be used.
connectionProperties The connection properties that will be sent to our JDBC driver when establishing new connections.
Format of the string must be [propertyName=property;]*
NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be included here.

ParameterDefaultDescription
defaultAutoCommit driver default The default auto-commit state of connections created by this pool. If not set then the setAutoCommit method will not be called.
defaultReadOnly driver default The default read-only state of connections created by this pool. If not set then the setReadOnly method will not be called. (Some drivers don't support read only mode, ex: Informix)
defaultTransactionIsolation driver default The default TransactionIsolation state of connections created by this pool. One of the following: (see javadoc)
  • NONE
  • READ_COMMITTED
  • READ_UNCOMMITTED
  • REPEATABLE_READ
  • SERIALIZABLE
defaultCatalog The default catalog of connections created by this pool.
cacheState true If true, the pooled connection will cache the current readOnly and autoCommit settings when first read or written and on all subsequent writes. This removes the need for additional database queries for any further calls to the getter. If the underlying connection is accessed directly and the readOnly and/or autoCommit settings changed the cached values will not reflect the current state. In this case, caching should be disabled by setting this attribute to false.
defaultQueryTimeout null If non-null, the value of this Integer property determines the query timeout that will be used for Statements created from connections managed by the pool. null means that the driver default will be used.
enableAutoCommitOnReturn true If true, connections being returned to the pool will be checked and configured with Connection.setAutoCommit(true) if the auto commit setting is false when the connection is returned.
rollbackOnReturn true True means a connection will be rolled back when returned to the pool if auto commit is not enabled and the connection is not read-only.

ParameterDefaultDescription
initialSize 0 The initial number of connections that are created when the pool is started.
Since: 1.2
maxTotal 8 The maximum number of active connections that can be allocated from this pool at the same time, or negative for no limit.
maxIdle 8 The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit.
minIdle 0 The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none.
maxWaitMillis indefinitely 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, or -1 to wait indefinitely.

NOTE: If maxIdle is set too low on heavily loaded systems it is possible you will see connections being closed and almost immediately new connections being opened. This is a result of the active threads momentarily closing connections faster than they are opening them, causing the number of idle connections to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good starting point.


ParameterDefaultDescription
validationQuery The SQL query that will be used to validate connections from this pool before returning them to the caller. If specified, this query MUST be an SQL SELECT statement that returns at least one row. If not specified, connections will be validation by calling the isValid() method.
validationQueryTimeout no timeout The timeout in seconds before connection validation queries fail. If set to a positive value, this value is passed to the driver via the setQueryTimeout method of the Statement used to execute the validation query.
testOnCreate false The indication of whether objects will be validated after creation. If the object fails to validate, the borrow attempt that triggered the object creation will fail.
testOnBorrow true The indication of whether objects will be validated before being borrowed from the pool. If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another.
testOnReturn false The indication of whether objects will be validated before being returned to the pool.
testWhileIdle false The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to validate, it will be dropped from the pool.
timeBetweenEvictionRunsMillis -1 The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run.
numTestsPerEvictionRun 3 The number of objects to examine during each run of the idle object evictor thread (if any).
minEvictableIdleTimeMillis 1000 * 60 * 30 The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor (if any).
softMinEvictableIdleTimeMillis -1 The minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the idle connection evictor, with the extra condition that at least "minIdle" connections remain in the pool. When minEvictableIdleTimeMillis is set to a positive value, minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are visited by the evictor, idle time is first compared against minEvictableIdleTimeMillis (without considering the number of idle connections in the pool) and then against softMinEvictableIdleTimeMillis, including the minIdle constraint.
maxConnLifetimeMillis -1 The maximum lifetime in milliseconds of a connection. After this time is exceeded the connection will fail the next activation, passivation or validation test. A value of zero or less means the connection has an infinite lifetime.
logExpiredConnections true Flag to log a message indicating that a connection is being closed by the pool due to maxConnLifetimeMillis exceeded. Set this property to false to suppress expired connection logging that is turned on by default.
connectionInitSqls null A Collection of SQL statements that will be used to initialize physical connections when they are first created. These statements are executed only once - when the configured connection factory creates the connection.
lifo true True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle instance pool in the order that they are returned to the pool.

ParameterDefaultDescription
poolPreparedStatements false Enable prepared statement pooling for this pool.
maxOpenPreparedStatements unlimited The maximum number of open statements that can be allocated from the statement pool at the same time, or negative for no limit.

This component has also the ability to pool PreparedStatements. When enabled a statement pool will be created for each Connection and PreparedStatements created by one of the following methods will be pooled:

  • public PreparedStatement prepareStatement(String sql)
  • public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)

NOTE - Make sure your connection has some resources left for the other statements. Pooling PreparedStatements may keep their cursors open in the database, causing a connection to run out of cursors, especially if maxOpenPreparedStatements is left at the default (unlimited) and an application opens a large number of different PreparedStatements per connection. To avoid this problem, maxOpenPreparedStatements should be set to a value less than the maximum number of cursors that can be open on a Connection.


ParameterDefaultDescription
accessToUnderlyingConnectionAllowed false Controls if the PoolGuard allows access to the underlying connection.

When allowed you can access the underlying connection using the following construct:

Connection conn = ds.getConnection(); Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate(); ... conn.close()

Default is false, it is a potential dangerous operation and misbehaving programs can do harmful things. (closing the underlying or continue using it when the guarded connection is already closed) Be careful and only use when you need direct access to driver specific extensions.

NOTE: Do not close the underlying connection, only the original one.


ParameterDefaultDescription
removeAbandonedOnMaintenance
removeAbandonedOnBorrow
false Flags to remove abandoned connections if they exceed the removeAbandonedTimout.
A connection is considered abandoned and eligible for removal if it has not been used for longer than removeAbandonedTimeout.
Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one of the execute methods) resets the lastUsed property of the parent connection.
Setting one or both of these to true can recover db connections from poorly written applications which fail to close connections.
Setting removeAbandonedOnMaintenance to true removes abandoned connections on the maintenance cycle (when eviction ends). This property has no effect unless maintenance is enabled by setting timeBetweenEvictionRunsMillis to a positive value.
If removeAbandonedOnBorrow is true, abandoned connections are removed each time a connection is borrowed from the pool, with the additional requirements that
  • getNumActive() > getMaxTotal() - 3; and
  • getNumIdle() < 2
removeAbandonedTimeout 300 Timeout in seconds before an abandoned connection can be removed.
logAbandoned false Flag to log stack traces for application code which abandoned a Statement or Connection.
Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because a stack trace has to be generated.
abandonedUsageTracking false If true, the connection pool records a stack trace every time a method is called on a pooled connection and retains the most recent stack trace to aid debugging of abandoned connections. There is significant overhead added by setting this to true.

If you have enabled removeAbandonedOnMaintenance or removeAbandonedOnBorrow then it is possible that a connection is reclaimed by the pool because it is considered to be abandoned. This mechanism is triggered when (getNumIdle() < 2) and (getNumActive() > getMaxTotal() - 3) and removeAbandonedOnBorrow is true; or after eviction finishes and removeAbandonedOnMaintenance is true. For example, maxTotal=20 and 18 active connections and 1 idle connection would trigger removeAbandonedOnBorrow, but only the active connections that aren't used for more then "removeAbandonedTimeout" seconds are removed (default 300 sec). Traversing a resultset doesn't count as being used. Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one of the execute methods) resets the lastUsed property of the parent connection.


ParameterDefaultDescription
fastFailValidation false When this property is true, validation fails fast for connections that have thrown "fatal" SQLExceptions. Requests to validate disconnected connections fail immediately, with no call to the driver's isValid method or attempt to execute a validation query.
The SQL_STATE codes considered to signal fatal errors are by default the following:
  • 57P01 (ADMIN SHUTDOWN)
  • 57P02 (CRASH SHUTDOWN)
  • 57P03 (CANNOT CONNECT NOW)
  • 01002 (SQL92 disconnect error)
  • JZ0C0 (Sybase disconnect error)
  • JZ0C1 (Sybase disconnect error)
  • Any SQL_STATE code that starts with "08"
To override this default set of disconnection codes, set the disconnectionSqlCodes property.
disconnectionSqlCodes null Comma-delimited list of SQL_STATE codes considered to signal fatal disconnection errors. Setting this property has no effect unless fastFailValidation is set to true.
jmxName Registers the DataSource as JMX MBean under specified name. The name has to conform to the JMX Object Name Syntax (see javadoc).
registerConnectionMBean true Registers Connection JMX MBeans. See DBCP-585).
commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/download_dbcp.xml000066400000000000000000000236341447311732500253420ustar00rootroot00000000000000 Download Apache Commons DBCP Apache Commons Documentation Team

We recommend you use a mirror to download our release builds, but you must verify the integrity of the downloaded files using signatures downloaded from our main distribution directories. Recent releases (48 hours) may not yet be available from all the mirrors.

You are currently using [preferred]. If you encounter a problem with this mirror, please select another mirror. If all mirrors are failing, there are backup mirrors (at the end of the mirrors list) that should be available.

[if-any logo][end]

Other mirrors:

It is essential that you verify the integrity of downloaded files, preferably using the PGP signature (*.asc files); failing that using the SHA512 hash (*.sha512 checksum files).

The KEYS file contains the public PGP keys used by Apache Commons developers to sign releases.

commons-dbcp2-2.10.0-bin.tar.gz sha512 pgp
commons-dbcp2-2.10.0-bin.zip sha512 pgp
commons-dbcp2-2.10.0-src.tar.gz sha512 pgp
commons-dbcp2-2.10.0-src.zip sha512 pgp
commons-dbcp2-2.4.0-bin.tar.gz sha256 pgp
commons-dbcp2-2.4.0-bin.zip sha256 pgp
commons-dbcp2-2.4.0-src.tar.gz sha256 pgp
commons-dbcp2-2.4.0-src.zip sha256 pgp

Older releases can be obtained from the archives.

commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/guide/000077500000000000000000000000001447311732500231065ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/guide/classdiagrams.xml000066400000000000000000000026511447311732500264510ustar00rootroot00000000000000 Class Diagrams Commons Documentation Team
commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/guide/index.xml000066400000000000000000000024251447311732500247420ustar00rootroot00000000000000 Developers Guide Commons Documentation Team
commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/guide/jndi-howto.xml000066400000000000000000000102231447311732500257100ustar00rootroot00000000000000 JNDI Howto Commons Documentation Team

The Java Naming and Directory Interface (JNDI) is part of the Java platform, providing applications based on Java technology with a unified interface to multiple naming and directory services. You can build powerful and portable directory-enabled applications using this industry standard.

When you deploy your application inside an application server, the container will setup the JNDI tree for you. But if you are writing a framework or just a standalone application, then the following examples will show you how to construct and bind references to DBCP datasources.

The following examples are using the sun filesystem JNDI service provider. You can download it from the JNDI software download page.

commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/guide/sequencediagrams.xml000066400000000000000000000024731447311732500271560ustar00rootroot00000000000000 Sequence Diagrams Commons Documentation Team
commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/index.xml000066400000000000000000000104031447311732500236400ustar00rootroot00000000000000 Overview Commons Documentation Team

Many Apache projects support interaction with a relational database. Creating a new connection for each user can be time consuming (often requiring multiple seconds of clock time), in order to perform a database transaction that might take milliseconds. Opening a connection per user can be unfeasible in a publicly-hosted Internet application where the number of simultaneous users can be very large. Accordingly, developers often wish to share a "pool" of open connections between all of the application's current users. The number of users actually performing a request at any given time is usually a very small percentage of the total number of active users, and during request processing is the only time that a database connection is required. The application itself logs into the DBMS, and handles any user account issues internally.

There are several Database Connection Pools already available, both within Apache products and elsewhere. This Commons package provides an opportunity to coordinate the efforts required to create and maintain an efficient, feature-rich package under the ASF license.

The commons-dbcp2 artifact relies on code in the commons-pool2 artifact to provide the underlying object pool mechanisms.

DBCP now comes in four different versions to support different versions of JDBC. Here is how it works:

Developing

  • DBCP 2.5.0 and up compiles and runs under Java 8 (JDBC 4.2) and up.
  • DBCP 2.4.0 compiles and runs under Java 7 (JDBC 4.1) and above.

Running

  • DBCP 2.5.0 and up binaries should be used by applications running on Java 8 and up.
  • DBCP 2.4.0 binaries should be used by applications running under Java 7.

DBCP 2 is based on Apache Commons Pool and provides increased performance, JMX support as well as numerous other new features compared to DBCP 1.x. Users upgrading to 2.x should be aware that the Java package name has changed, as well as the Maven co-ordinates, since DBCP 2.x is not binary compatible with DBCP 1.x. Users should also be aware that some configuration options (e.g. maxActive to maxTotal) have been renamed to align them with the new names used by Commons Pool.

See the downloads page for information on obtaining releases.

The Javadoc API documents are available online. In particular, you should read the package overview of the org.apache.commons.dbcp2 package for an overview of how to use DBCP.

There are several examples of using DBCP available.

commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/issue-tracking.xml000066400000000000000000000133231447311732500254650ustar00rootroot00000000000000 Apache Commons DBCP Issue tracking Apache Commons Documentation Team

Apache Commons DBCP uses ASF JIRA for tracking issues. See the Apache Commons DBCP JIRA project page.

To use JIRA you may need to create an account (if you have previously created/updated Commons issues using Bugzilla an account will have been automatically created and you can use the Forgot Password page to get a new password).

If you would like to report a bug, or raise an enhancement request with Apache Commons DBCP please do the following:

  1. Search existing open bugs. If you find your issue listed then please add a comment with your details.
  2. Search the mailing list archive(s). You may find your issue or idea has already been discussed.
  3. Decide if your issue is a bug or an enhancement.
  4. Submit either a bug report or enhancement request.

Please also remember these points:

  • the more information you provide, the better we can help you
  • test cases are vital, particularly for any proposed enhancements
  • the developers of Apache Commons DBCP are all unpaid volunteers

For more information on creating patches see the Apache Contributors Guide.

You may also find these links useful:

commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/mail-lists.xml000066400000000000000000000237141447311732500246200ustar00rootroot00000000000000 Apache Commons DBCP Mailing Lists Apache Commons Documentation Team

Apache Commons DBCP shares mailing lists with all the other Commons Components. To make it easier for people to only read messages related to components they are interested in, the convention in Commons is to prefix the subject line of messages with the component's name, for example:

  • [dbcp] Problem with the ...

Questions related to the usage of Apache Commons DBCP should be posted to the User List.
The Developer List is for questions and discussion related to the development of Apache Commons DBCP.
Please do not cross-post; developers are also subscribed to the user list.
You must be subscribed to post to the mailing lists. Follow the Subscribe links below to subscribe.

Note: please don't send patches or attachments to any of the mailing lists. Patches are best handled via the Issue Tracking system. Otherwise, please upload the file to a public server and include the URL in the mail.

Please prefix the subject line of any messages for Apache Commons DBCP with [dbcp] - thanks!

Name Subscribe Unsubscribe Post Archive Other Archives
Commons User List

Questions on using Apache Commons DBCP.

Subscribe Unsubscribe Post mail-archives.apache.org
lists.apache.org
markmail.org
www.mail-archive.com
news.gmane.org
Commons Developer List

Discussion of development of Apache Commons DBCP.

Subscribe Unsubscribe Post mail-archives.apache.org
lists.apache.org
markmail.org
www.mail-archive.com
news.gmane.org
Commons Issues List

Only for e-mails automatically generated by the issue tracking system.

Subscribe Unsubscribe read only mail-archives.apache.org
lists.apache.org
markmail.org
www.mail-archive.com
Commons Commits List

Only for e-mails automatically generated by the source control system.

Subscribe Unsubscribe read only mail-archives.apache.org
lists.apache.org
markmail.org
www.mail-archive.com

Other mailing lists which you may find useful include:

Name Subscribe Unsubscribe Post Archive Other Archives
Apache Announce List

General announcements of Apache project releases.

Subscribe Unsubscribe read only mail-archives.apache.org
lists.apache.org
markmail.org
old.nabble.com
www.mail-archive.com
news.gmane.org
commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/release-notes-1.1.xml000066400000000000000000000447761447311732500256200ustar00rootroot00000000000000 Release notes for Commons-DBCP 1.1 Commons Documentation Team $Id$

There were a lot changes since the 1.0 release on 12 Aug 2002.

  • All existing features can now be configured by JNDI Context providers (Tomcat)

  • The double close() of a pooled connection is more effectively blocked (you may experience more "Already closed" SQLExceptions)

  • Prepared statement pooling is now implemented in BasicDataSource (set poolPreparedStatements=true, maxOpenPreparedStatements=xxx)

  • Access to the underlying connection is blocked by default You can access the underlying connection by setting accessToUnderlyingConnectionAllowed=true and by using the following construct: Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate();

  • New minIdle parameter for a minimum number of idle connections ready for use

  • New connection default properties: defaultCatalog and defaultTransactionIsolation

  • Missing driverClassName will now give the following error "No suitable driver"

  • Bad validationQuery will produce a meaningful SQLException

  • UML Class and sequence diagrams, configuration documentation

  • The following issues were resolved since v1.0: (see Bugzilla for complete description)
    IDDateSevStateSummary
    69342003-09-20BloDUPLSQLTransformer.java - infinite loop in getConnection
    70382002-03-18NorFIXEDBCP does not build under JDK 1.4
    77272002-04-20MajFIXEInfinite loop (stack overflow) in BasicDataSource
    77282002-04-20MajFIXEBasicDataSource cannot use many JDBC drivers
    86202002-04-29NorINVAClosed Connection Exception on setAutoCommit
    90732002-07-20NorFIXEBasicDataSource - invalid connections are not checked
    98502002-07-20NorFIXENo way to get at SQLException if connection to database fail
    105922002-07-20NorDUPLdataSource.getConnection never returns in Tomcat using DBCP
    106142002-07-20NorFIXEDBCP connection pooling broken in Tomcat-4.1.7 (regression)
    106882002-07-20MinFIXEVersion in the Manifest
    109692002-07-20MajFIXEBasicDataSource defaults are unusable
    115072002-08-06NorINVACleanup dead connections
    120472002-11-01NorINVAvalidationQuery + MSSQL
    124002002-11-07NorWORKsame connections
    124092002-11-01BloFIXEConnection can be closed twice
    127332003-02-06NorFIXE[DBCP][PATCH]Statement.getResultSet() doesn't return null if
    128692002-11-01MajFIXEAbandoned Connections are never closed
    130772002-11-07EnhFIXEJdbc2PoolDataSource issues
    131292002-11-01NorFIXECPDSConnectionFactory prints invalid error messages
    131552002-10-30NorDUPLunexpected "exhausted pool" error
    132352002-11-16BloFIXEreferenced UserPassKey instances get erroneously returned to
    139302003-03-06EnhFIXEAdding connection parameters to BasicDataSourceFactory
    139882003-03-17EnhDUPLpermission error makes connection loop
    142672003-04-28MajINVADBCP doesn't work on Tomcat 4.1.12 and Oracle JDBC driver
    145922002-11-15EnhINVADBCP must be robust against e.g. database shutdowns
    146632003-05-14NorREMITomcat5 server hangs when trying to get the database connect
    151232003-08-21MajFIXEIncorrect stack trace shown when abandoned connections are c
    155392003-02-06MajDUPLStrange Result Set on output
    162832003-02-01NorWONTInproper use of Exception
    165812003-03-06MajFIXEDeadlock in AbandonedObjectPool when firewall closes connect
    166292003-03-06NorFIXEorg.apache.commons.dbcp.jdbc2pool.Jdbc2PoolDataSource: setti
    169872003-08-11MajFIXErace condition in PoolableConnection.close()
    170152003-03-06NorFIXEGenericObjectPool.invalidateObject() doesn't work with Aband
    172002003-03-06MajFIXEDBCP: org.apache.commons.dbcp.cpdsadapter.PooledConnectionIm
    173012003-04-08NorWONTNPE in Oracle driver when using DBCP PoolingDataSource
    174562003-04-08EnhFIXEBasicDataSource should use commons-logging
    176352003-03-06MinFIXEPoolableConnectionFactory-Construction declared to throw Exc
    176772003-05-31MajINVAPooled connection architecture vulnerable to double use
    176782003-04-01MajFIXEDBCP Fails silently in many cases
    176802003-03-13MajINVAPoolableConnection.reallyClose() doesn't decrement active co
    179112003-04-07MajWONTProblem with getConnection() and Informix
    180122003-08-26EnhFIXEBasicDataSource doesn't include PreparedStmt Pooling
    184832003-04-08NorWONTAbandonedObjectPool.removeAbandoned never cleans up the trac
    185022003-03-30BloINVAjava.lang.ClassNotFoundException: org.apache.commons.pool.St
    185502003-08-25EnhFIXEAdd defaultTransactionIsolation to BasicDataSource
    188342003-04-08NorFIXEJdbc2PoolDataSource throws a RuntimeException when database
    189052003-08-11NorFIXECouldn't get connection (Jdbc2PoolDataSource)
    189212003-08-11EnhFIXEPer User methods not working in Jdbc2PoolDataSource
    189822003-04-13MajINVABinary distribution missing package
    193742003-08-11NorFIXEPotential for DelegateStatement, DelegateResultSet to be lef
    196142003-08-13MajFIXEPoor performance under load
    196152003-05-02MajINVAUnnecessary global synchronized in AbandonedObjectPool method
    197062003-08-26EnhWONTAdd Initial Commons Logging to DBCP
    206492003-08-11CriINVAdeadlock when acquiring connections from a pool
    211322003-08-11CriDUPLBroken pipe despite validation query set
    211822003-08-21NorINVA[dbcp] removing a webapp does not force connections closed
    212292003-08-11NorFIXEConnectionFactory throws SQLException but implementations do
    212732003-08-11NorFIXEMemory-leak like behaviour in DBCP due to warnings chained t
    214182003-08-11MinFIXEExample code
    214532003-08-11MajINVANullPointerException in DBCP when used for client-server ap
    214582003-08-11NorFIXEStatements and connections don't implement equals()/hashCode
    217482003-08-11NorFIXEBasicDataSource.close() throws NPE
    220782003-08-12NorFIXE[DBCP] testOnBorrow fails if setAutoCommit() throws an excep
    220792003-08-13NorFIXE[DBCP] if connection closed twice *closed* connection is ret
    222142003-08-11MajFIXEDelegating ResultSet causing NPE
    222292003-08-13CriFIXEFoul connection causes livelock of all pool operations
    225982003-08-21EnhFIXEminIdle Functionality for DBCP via Patches Posted for common
    227362003-08-29MajINVAvalidationQuery parameter hangs getConnection method.
    227502003-08-27NorFIXEBasicDataSource always sets testOnBorrow if given a validati
    227762003-09-20NorWONTDBCP should not be writing messages to stderr or stdout
    230662003-09-13MajFIXEDriverManager.getConnection() throws DbcpException
    230812003-09-20NorFIXEDBCP - Bad DB Validation Query Hangs Everything
    231382003-09-13NorFIXEgetDelegate no longer useful since v1.7 of PoolingDataSource
    231572003-09-20EnhFIXEadd defaultCatalog to BasicDataSource
    231852003-09-21NorWONTPoolableConnection.close() won't allow multiple close
    232912003-09-20NorFIXEimpossible to turn off all validation tests when a validatio
    232932003-09-20NorFIXEsetAutoCommit(true) when returning connection to the pool
    233042003-09-21NorFIXENullpointerException when no driverClassName is specified

  • The following issues were resolved since v1.1RC1:
    IDDateSevStateSummary
    227762003-09-30NorFIXEDBCP should not be writing messages to stderr or stdout (removed unneeded logging in AbandonedObjectPool)
    234912003-10-13CriFIXECan't configure PerUserPoolDataSource for use with tomcat, more...

  • The following issues were resolved since v1.1RC2:
    IDDateSevStateSummary
    238432003-10-20BloFIXEPerUserPoolDataSource.getConnection(username, pw) may return connection under wrong username

commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/release-notes-1.2.1.xml000066400000000000000000000044551447311732500257460ustar00rootroot00000000000000 Release notes for Commons-DBCP 1.2.1 Commons Documentation Team $Id$

NOTE: DBCP v1.2.1 requires Pool v1.2, make sure you use the correct version!


DBCP 1.2.1 is a maintenance release to restore full JDK 1.3 compatibility.

The problem lies in the improper use of a JDK 1.4 method: java.lang.Boolean.valueOf(boolean)

This method was used in the defaultReadOnly property processing.

We recommend to upgrade to DBCP 1.2.1 to avoid this problem altogether.


If you use the defaultReadOnly property in a JRE <1.4, you will get the following error: java.lang.NoSuchMethodError at org.apache.commons.dbcp.BasicDataSource.setDefaultReadOnly(BasicDataSource.java:75) at org.apache.commons.dbcp.BasicDataSourceFactory.createDataSource(BasicDataSourceFactory.java:162) at org.apache.commons.dbcp.BasicDataSourceFactory.getObjectInstance(BasicDataSourceFactory.java:144) at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:176)

The simple workaround is not to use this property. For example remove the following from the tomcat config.xml. defaultReadOnly true ]]>

commons-dbcp-rel-commons-dbcp-2.10.0/src/site/xdoc/release-notes-1.2.xml000066400000000000000000000204211447311732500255760ustar00rootroot00000000000000 Release notes for Commons-DBCP 1.2 Commons Documentation Team $Id$

NOTE: DBCP v1.2 requires Pool v1.2, make sure you use the correct version!

There were some new features were added since the 1.1 release on 20 October 2003.

  • Performance optimizations for the PoolableConnectionFactory of BasicDataSource.

  • Add BasicDataSourceFactory.createDataSource(Properties properties) for creating a BasicDataSource.

  • Add initialSize parameter to do pre-loading of the connection.

  • Refactoring of the DelegatingStatement classes.

  • Make some properties dynamic (changeable at runtime), this will be completed in next release.

  • Improvements to the prepared statement pooling.

  • Driver specific changes/optimizations for: Oracle, Informix, DaffodilDB.

  • Several fixes for PerUserPoolDataSource

  • PoolingDriver uses now a PoolGuardConnectionWrapper by default. If access to the underlying connection is needed, you have to enable it: PoolingDriver.setAccessToUnderlyingConnectionAllowed(true)

  • The following issues were resolved since v1.1: (see Bugzilla for complete description)
    IDDateSevStateSummary
    245622003-11-10EnhFIXEPoolingDriver needs a closePool method
    243282003-11-10NorFIXEPooledConnectionImpl ignores resultsetType and Concurrency
    246782003-11-14MajINVADelegatingStatement.getResultSet() never returns null
    250962003-11-30EnhFIXEPoolableConnectionFactory synchronized methods
    250012003-11-30NorFIXEOracle 9i and default isolation settings
    257622003-12-26NorFIXESharedPoolDataSource getConnection() throws ClassCastException
    250672003-12-26NorFIXEPlease give possibility to access ObjectPools from PoolingDriver
    257952003-12-29NorDUPLNumberFormatException: For input string: "myDB"
    257942003-12-29NorFIXEClassNotFoundException: org.apache.xerces.parsers.SAXParser
    249662004-01-06NorFIXENullPointer with Oracle 9 driver
    260722004-01-18NorFIXENull pointer exception being thrown in SQLNestedException
    262622004-01-20MinFIXEDBCP log message in tomcat has incorrect day
    264222004-01-25EnhFIXEAdd BasicDataSourceFactory.createDataSource(Properties properties)
    255142004-02-07EnhFIXEAdd initialSize parameter to do pre-loading of the connection
    240822004-02-28BloFIXENumberFormatException: For input string: "myDB"
    241362004-02-28NorFIXEClassCastException in DriverAdapterCPDS when setPoolPreparedStatements(true)
    272142004-02-29EnhFIXEbad &gt; entity in javadoc
    273202004-02-29NorFIXEDBCP 1.1 incompatible with Informix (driver doesn't support setReadOnly(...))
    274652004-03-07MajFIXEmemory leak in KeyedCPDSConnectionFactory
    269662004-03-07NorWORKConnectionpool's connections always returns same hashCode
    272462004-03-07NorFIXEPreparedStatement cache should be different depending on the Catalog
    274362004-03-08EnhFIXEWith Oracle jdbc driver, an unnecessary SQL "set transaction read write" is issued each time a connection is retrieved from the pool
    285792004-04-25NorFIXENumActive can become incorrect when removeAbandoned=true
    285802004-04-25EnhFIXEAbandonedObjectPool/Trace should log to stdout
    282512004-05-01NorFIXEReturning dead database connections to BasicDataSource
    286882004-05-01CriINVACant Deserialize the Class PerUserPoolDataSource
    288932004-05-12MinFIXEPoolableConnectionFactory has incomplete javadoc on validationQuery
    289122004-05-17MajFIXEConnection re-use conflates logical and physical connections
    290542004-05-20NorFIXEsetTestOnReturn(boolean)
    290552004-05-20NorFIXEAutoCommit and ReadOnly

commons-dbcp-rel-commons-dbcp-2.10.0/src/test/000077500000000000000000000000001447311732500210675ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/000077500000000000000000000000001447311732500220105ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/000077500000000000000000000000001447311732500225775ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/000077500000000000000000000000001447311732500240205ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/000077500000000000000000000000001447311732500254735ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/000077500000000000000000000000001447311732500264655ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/StackMessageLog.java000066400000000000000000000076071447311732500323560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.EmptyStackException; import java.util.Iterator; import java.util.List; import java.util.Stack; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.logging.impl.SimpleLog; /** * A logger that pushes log messages onto a stack. The stack itself is static. * To get a log exclusive to a test case, use explicit lock / unlock and clear. */ public class StackMessageLog extends SimpleLog { private static final long serialVersionUID = 1L; private static final Stack MESSAGE_STACK = new Stack<>(); private static final Lock LOCK = new ReentrantLock(); public static void clear() { LOCK.lock(); try { MESSAGE_STACK.clear(); } finally { LOCK.unlock(); } } /** * Note: iterator is fail-fast, lock the stack first. */ public static List getAll() { final Iterator iterator = MESSAGE_STACK.iterator(); final List messages = new ArrayList<>(); while (iterator.hasNext()) { messages.add(iterator.next()); } return messages; } public static boolean isEmpty() { return MESSAGE_STACK.isEmpty(); } /** * Obtains an exclusive lock on the log. */ public static void lock() { LOCK.lock(); } /** * @return the most recent log message, or null if the log is empty */ public static String popMessage() { LOCK.lock(); try { return MESSAGE_STACK.pop(); } catch (final EmptyStackException ex) { // ignore, return null return null; } finally { LOCK.unlock(); } } /** * Relinquishes exclusive lock on the log. */ public static void unLock() { try { LOCK.unlock(); } catch (final IllegalMonitorStateException ex) { // ignore } } public StackMessageLog(final String name) { super(name); } /** * Ignores type. Pushes message followed by stack trace of t onto the stack. */ @Override protected void log(final int type, final Object message, final Throwable t) { LOCK.lock(); try { final StringBuilder buf = new StringBuilder(); buf.append(message.toString()); if (t != null) { buf.append(" <"); buf.append(t.toString()); buf.append(">"); final java.io.StringWriter sw = new StringWriter(1024); try (final java.io.PrintWriter pw = new PrintWriter(sw)) { t.printStackTrace(pw); } buf.append(sw.toString()); } MESSAGE_STACK.push(buf.toString()); } finally { LOCK.unlock(); } } } TestAbandonedBasicDataSource.java000066400000000000000000000354521447311732500347120ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import java.time.Instant; import org.apache.commons.pool2.KeyedObjectPool; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * TestSuite for BasicDataSource with abandoned connection trace enabled */ public class TestAbandonedBasicDataSource extends TestBasicDataSource { private StringWriter sw; /** * Verifies that con.lastUsed has been updated and then resets it to 0 */ private void assertAndReset(final DelegatingConnection con) { assertTrue(con.getLastUsedInstant().compareTo(Instant.EPOCH) > 0); con.setLastUsed(Instant.EPOCH); } // ---------- Abandoned Test ----------- /** * Verifies that PreparedStatement executeXxx methods update lastUsed on the parent connection */ private void checkLastUsedPreparedStatement(final PreparedStatement ps, final DelegatingConnection conn) throws Exception { ps.execute(); assertAndReset(conn); try (ResultSet rs = ps.executeQuery()) { Assertions.assertNotNull(rs); } assertAndReset(conn); ps.executeUpdate(); assertAndReset(conn); } /** * Verifies that Statement executeXxx methods update lastUsed on the parent connection */ private void checkLastUsedStatement(final Statement st, final DelegatingConnection conn) throws Exception { st.execute(""); assertAndReset(conn); st.execute("", new int[] {}); assertAndReset(conn); st.execute("", 0); assertAndReset(conn); st.executeBatch(); assertAndReset(conn); st.executeLargeBatch(); assertAndReset(conn); try (ResultSet rs = st.executeQuery("")) { Assertions.assertNotNull(rs); } assertAndReset(conn); st.executeUpdate(""); assertAndReset(conn); st.executeUpdate("", new int[] {}); assertAndReset(conn); st.executeLargeUpdate("", new int[] {}); assertAndReset(conn); st.executeUpdate("", 0); assertAndReset(conn); st.executeLargeUpdate("", 0); assertAndReset(conn); st.executeUpdate("", new String[] {}); assertAndReset(conn); st.executeLargeUpdate("", new String[] {}); assertAndReset(conn); } private void createStatement(final Connection conn) throws Exception{ final PreparedStatement ps = conn.prepareStatement(""); Assertions.assertNotNull(ps); } @Override @BeforeEach public void setUp() throws Exception { super.setUp(); // abandoned enabled but should not affect the basic tests // (very high timeout) ds.setLogAbandoned(true); ds.setRemoveAbandonedOnBorrow(true); ds.setRemoveAbandonedOnMaintenance(true); ds.setRemoveAbandonedTimeout(Duration.ofSeconds(10)); sw = new StringWriter(); ds.setAbandonedLogWriter(new PrintWriter(sw)); } @Test public void testAbandoned() throws Exception { // force abandoned ds.setRemoveAbandonedTimeout(Duration.ZERO); ds.setMaxTotal(1); for (int i = 0; i < 3; i++) { assertNotNull(ds.getConnection()); } } @Test public void testAbandonedClose() throws Exception { // force abandoned ds.setRemoveAbandonedTimeout(Duration.ZERO); ds.setMaxTotal(1); ds.setAccessToUnderlyingConnectionAllowed(true); try (Connection conn1 = getConnection()) { assertNotNull(conn1); assertEquals(1, ds.getNumActive()); try (Connection conn2 = getConnection()) { // Attempt to borrow object triggers abandoned cleanup // conn1 should be closed by the pool to make room assertNotNull(conn2); assertEquals(1, ds.getNumActive()); // Verify that conn1 is closed assertTrue(((DelegatingConnection) conn1).getInnermostDelegate().isClosed()); // Verify that conn1 is aborted final TesterConnection tCon = (TesterConnection) ((DelegatingConnection) conn1) .getInnermostDelegate(); assertTrue(tCon.isAborted()); } assertEquals(0, ds.getNumActive()); // Second close on conn1 is OK as of dbcp 1.3 } assertEquals(0, ds.getNumActive()); final String string = sw.toString(); assertTrue(string.contains("testAbandonedClose"), string); } @Test public void testAbandonedCloseWithExceptions() throws Exception { // force abandoned ds.setRemoveAbandonedTimeout(Duration.ZERO); ds.setMaxTotal(1); ds.setAccessToUnderlyingConnectionAllowed(true); final Connection conn1 = getConnection(); assertNotNull(conn1); assertEquals(1, ds.getNumActive()); final Connection conn2 = getConnection(); assertNotNull(conn2); assertEquals(1, ds.getNumActive()); // set an IO failure causing the isClosed method to fail final TesterConnection tconn1 = (TesterConnection) ((DelegatingConnection) conn1).getInnermostDelegate(); tconn1.setFailure(new IOException("network error")); final TesterConnection tconn2 = (TesterConnection) ((DelegatingConnection) conn2).getInnermostDelegate(); tconn2.setFailure(new IOException("network error")); try { conn2.close(); } catch (final SQLException ex) { /* Ignore */ } assertEquals(0, ds.getNumActive()); try { conn1.close(); } catch (final SQLException ex) { // ignore } assertEquals(0, ds.getNumActive()); final String string = sw.toString(); assertTrue(string.contains("testAbandonedCloseWithExceptions"), string); } /** * DBCP-180 - verify that a GC can clean up an unused Statement when it is * no longer referenced even when it is tracked via the AbandonedTrace * mechanism. */ @Test public void testGarbageCollectorCleanUp01() throws Exception { try (DelegatingConnection conn = (DelegatingConnection) ds.getConnection()) { Assertions.assertEquals(0, conn.getTrace().size()); createStatement(conn); Assertions.assertEquals(1, conn.getTrace().size()); System.gc(); Assertions.assertEquals(0, conn.getTrace().size()); } } /** * DBCP-180 - things get more interesting with statement pooling. */ @Test public void testGarbageCollectorCleanUp02() throws Exception { ds.setPoolPreparedStatements(true); ds.setAccessToUnderlyingConnectionAllowed(true); final DelegatingConnection conn = (DelegatingConnection) ds.getConnection(); final PoolableConnection poolableConn = (PoolableConnection) conn.getDelegate(); final PoolingConnection poolingConn = (PoolingConnection) poolableConn.getDelegate(); final KeyedObjectPool gkop = poolingConn.getStatementPool(); Assertions.assertEquals(0, conn.getTrace().size()); Assertions.assertEquals(0, gkop.getNumActive()); createStatement(conn); Assertions.assertEquals(1, conn.getTrace().size()); Assertions.assertEquals(1, gkop.getNumActive()); System.gc(); // Finalization happens in a separate thread. Give the test time for // that to complete. int count = 0; while (count < 50 && gkop.getNumActive() > 0) { Thread.sleep(100); count++; } Assertions.assertEquals(0, gkop.getNumActive()); Assertions.assertEquals(0, conn.getTrace().size()); } /** * Verify that lastUsed property is updated when a connection * creates or prepares a statement */ @Test public void testLastUsed() throws Exception { ds.setRemoveAbandonedTimeout(Duration.ofSeconds(1)); ds.setMaxTotal(2); try (Connection conn1 = ds.getConnection()) { Thread.sleep(500); try (Statement s = conn1.createStatement()) { // Should reset lastUsed } Thread.sleep(800); final Connection conn2 = ds.getConnection(); // triggers abandoned cleanup try (Statement s = conn1.createStatement()) { // Should still be OK } conn2.close(); Thread.sleep(500); try (PreparedStatement ps = conn1.prepareStatement("SELECT 1 FROM DUAL")) { // reset } Thread.sleep(800); try (Connection c = ds.getConnection()) { // trigger abandoned cleanup again } try (Statement s = conn1.createStatement()) { // empty } } } /** * DBCP-343 - verify that using a DelegatingStatement updates * the lastUsed on the parent connection */ @Test public void testLastUsedLargePreparedStatementUse() throws Exception { ds.setRemoveAbandonedTimeout(Duration.ofSeconds(1)); ds.setMaxTotal(2); try (Connection conn1 = ds.getConnection(); Statement st = conn1.createStatement()) { final String querySQL = "SELECT 1 FROM DUAL"; Thread.sleep(500); try (ResultSet rs = st.executeQuery(querySQL)) { Assertions.assertNotNull(rs); // Should reset lastUsed } Thread.sleep(800); try (final Connection conn2 = ds.getConnection()) { // triggers abandoned cleanup try (ResultSet rs = st.executeQuery(querySQL)) { Assertions.assertNotNull(rs); // Should still be OK } } Thread.sleep(500); st.executeLargeUpdate(""); // Should also reset Thread.sleep(800); try (Connection c = ds.getConnection()) { // trigger abandoned cleanup again } try (Statement s = conn1.createStatement()) { // Connection should still be good } } } /** * Verify that lastUsed property is updated when a connection * prepares a callable statement. */ @Test public void testLastUsedPrepareCall() throws Exception { ds.setRemoveAbandonedTimeout(Duration.ofSeconds(1)); ds.setMaxTotal(2); try (Connection conn1 = ds.getConnection()) { Thread.sleep(500); try (CallableStatement cs = conn1.prepareCall("{call home}")) { // Should reset lastUsed } Thread.sleep(800); final Connection conn2 = ds.getConnection(); // triggers abandoned cleanup try (CallableStatement cs = conn1.prepareCall("{call home}")) { // Should still be OK } conn2.close(); Thread.sleep(500); try (CallableStatement cs = conn1.prepareCall("{call home}")) { // reset } Thread.sleep(800); try (Connection c = ds.getConnection()) { // empty } try (Statement s = conn1.createStatement()) { // trigger abandoned cleanup again } } } /** * DBCP-343 - verify that using a DelegatingStatement updates * the lastUsed on the parent connection */ @Test public void testLastUsedPreparedStatementUse() throws Exception { ds.setRemoveAbandonedTimeout(Duration.ofSeconds(1)); ds.setMaxTotal(2); try (Connection conn1 = ds.getConnection(); Statement st = conn1.createStatement()) { final String querySQL = "SELECT 1 FROM DUAL"; Thread.sleep(500); Assertions.assertNotNull(st.executeQuery(querySQL)); // Should reset lastUsed Thread.sleep(800); final Connection conn2 = ds.getConnection(); // triggers abandoned cleanup Assertions.assertNotNull(st.executeQuery(querySQL)); // Should still be OK conn2.close(); Thread.sleep(500); st.executeUpdate(""); // Should also reset Thread.sleep(800); try (Connection c = ds.getConnection()) {} // trigger abandoned cleanup again try (Statement s = conn1.createStatement()) {} // Connection should still be good } } /** * DBCP-343 - verify additional operations reset lastUsed on * the parent connection */ @Test public void testLastUsedUpdate() throws Exception { try (DelegatingConnection conn = (DelegatingConnection) ds.getConnection(); final PreparedStatement ps = conn.prepareStatement(""); final CallableStatement cs = conn.prepareCall(""); final Statement st = conn.prepareStatement("")) { checkLastUsedStatement(ps, conn); checkLastUsedPreparedStatement(ps, conn); checkLastUsedStatement(cs, conn); checkLastUsedPreparedStatement(cs, conn); checkLastUsedStatement(st, conn); } } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestAbandonedTrace.java000066400000000000000000000023751447311732500330310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import java.sql.SQLException; import org.junit.jupiter.api.Test; /** * Tests {@link AbandonedTrace}. */ public class TestAbandonedTrace { @Test public void testDeprecated() throws SQLException { try (AbandonedTrace trace = new AbandonedTrace()) { assertEquals(trace.getLastUsedInstant().toEpochMilli(), trace.getLastUsed()); } } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java000066400000000000000000001257221447311732500331750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.ThreadMXBean; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; import javax.management.AttributeNotFoundException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.sql.DataSource; import org.apache.commons.logging.LogFactory; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; /** * TestSuite for BasicDataSource */ public class TestBasicDataSource extends TestConnectionPool { private static final String CATALOG = "test catalog"; @BeforeAll public static void setUpClass() { // register a custom logger which supports inspection of the log messages LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", "org.apache.commons.dbcp2.StackMessageLog"); } protected BasicDataSource ds; protected BasicDataSource createDataSource() throws Exception { return new BasicDataSource(); } @Override protected Connection getConnection() throws Exception { return ds.getConnection(); } @BeforeEach public void setUp() throws Exception { ds = createDataSource(); ds.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); ds.setUrl("jdbc:apache:commons:testdriver"); ds.setMaxTotal(getMaxTotal()); ds.setMaxWait(getMaxWaitDuration()); ds.setDefaultAutoCommit(Boolean.TRUE); ds.setDefaultReadOnly(Boolean.FALSE); ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); ds.setDefaultCatalog(CATALOG); ds.setUsername("userName"); ds.setPassword("password"); ds.setValidationQuery("SELECT DUMMY FROM DUAL"); ds.setConnectionInitSqls(Arrays.asList("SELECT 1", "SELECT 2")); ds.setDriverClassLoader(new TesterClassLoader()); ds.setJmxName("org.apache.commons.dbcp2:name=test"); } @Override @AfterEach public void tearDown() throws Exception { super.tearDown(); ds.close(); ds = null; } @Test public void testAccessToUnderlyingConnectionAllowed() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); assertTrue(ds.isAccessToUnderlyingConnectionAllowed()); try (final Connection conn = getConnection()) { Connection dconn = ((DelegatingConnection) conn).getDelegate(); assertNotNull(dconn); dconn = ((DelegatingConnection) conn).getInnermostDelegate(); assertNotNull(dconn); assertTrue(dconn instanceof TesterConnection); } } @Test public void testClose() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); // active connection is held open when ds is closed final Connection activeConnection = getConnection(); final Connection rawActiveConnection = ((DelegatingConnection) activeConnection).getInnermostDelegate(); assertFalse(activeConnection.isClosed()); assertFalse(rawActiveConnection.isClosed()); // idle connection is in pool but closed final Connection idleConnection = getConnection(); final Connection rawIdleConnection = ((DelegatingConnection) idleConnection).getInnermostDelegate(); assertFalse(idleConnection.isClosed()); assertFalse(rawIdleConnection.isClosed()); // idle wrapper should be closed but raw connection should be open idleConnection.close(); assertTrue(idleConnection.isClosed()); assertFalse(rawIdleConnection.isClosed()); ds.close(); // raw idle connection should now be closed assertTrue(rawIdleConnection.isClosed()); // active connection should still be open assertFalse(activeConnection.isClosed()); assertFalse(rawActiveConnection.isClosed()); // now close the active connection activeConnection.close(); // both wrapper and raw active connection should be closed assertTrue(activeConnection.isClosed()); assertTrue(rawActiveConnection.isClosed()); // Verify SQLException on getConnection after close assertThrows(SQLException.class, () -> getConnection()); // Redundant close is OK ds.close(); } @Test public void testConcurrentInitBorrow() throws Exception { ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver"); ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:50"); ds.setInitialSize(8); // Launch a request to trigger pool initialization final TestThread testThread = new TestThread(1, 0); final Thread t = new Thread(testThread); t.start(); // Get another connection (should wait for pool init) Thread.sleep(100); // Make sure t gets into init first try (Connection conn = ds.getConnection()) { // Pool should have at least 6 idle connections now // Use underlying pool getNumIdle to avoid waiting for ds lock assertTrue(ds.getConnectionPool().getNumIdle() > 5); // Make sure t completes successfully t.join(); assertFalse(testThread.failed()); } ds.close(); } /** * JIRA: DBCP-444 * Verify that invalidate does not return closed connection to the pool. */ @Test public void testConcurrentInvalidateBorrow() throws Exception { ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnRequestCountDriver"); ds.setUrl("jdbc:apache:commons:testerConnRequestCountDriver"); ds.setTestOnBorrow(true); ds.setValidationQuery("SELECT DUMMY FROM DUAL"); ds.setMaxTotal(8); ds.setLifo(true); ds.setMaxWait(Duration.ofMillis(-1)); // Threads just borrow and return - validation will trigger close check final TestThread testThread1 = new TestThread(1000,0); final Thread t1 = new Thread(testThread1); t1.start(); final TestThread testThread2 = new TestThread(1000,0); final Thread t2 = new Thread(testThread1); t2.start(); // Grab and invalidate connections for (int i = 0; i < 1000; i++) { final Connection conn = ds.getConnection(); ds.invalidateConnection(conn); } // Make sure borrow threads complete successfully t1.join(); t2.join(); assertFalse(testThread1.failed()); assertFalse(testThread2.failed()); ds.close(); } /** * JIRA: DBCP-547 * Verify that ConnectionFactory interface in BasicDataSource.createConnectionFactory(). */ @Test public void testCreateConnectionFactoryWithConnectionFactoryClassName() throws Exception { Properties properties = new Properties(); // set ConnectionFactoryClassName properties = new Properties(); properties.put("initialSize", "1"); properties.put("driverClassName", "org.apache.commons.dbcp2.TesterDriver"); properties.put("url", "jdbc:apache:commons:testdriver"); properties.put("username", "foo"); properties.put("password", "bar"); properties.put("connectionFactoryClassName", "org.apache.commons.dbcp2.TesterConnectionFactory"); try (BasicDataSource ds = BasicDataSourceFactory.createDataSource(properties)) { try (Connection conn = ds.getConnection()) { assertNotNull(conn); } } } /** * JIRA: DBCP-547 * Verify that ConnectionFactory interface in BasicDataSource.createConnectionFactory(). */ @Test public void testCreateConnectionFactoryWithoutConnectionFactoryClassName() throws Exception { // not set ConnectionFactoryClassName final Properties properties = new Properties(); properties.put("initialSize", "1"); properties.put("driverClassName", "org.apache.commons.dbcp2.TesterDriver"); properties.put("url", "jdbc:apache:commons:testdriver"); properties.put("username", "foo"); properties.put("password", "bar"); try (BasicDataSource ds = BasicDataSourceFactory.createDataSource(properties)) { try (Connection conn = ds.getConnection()) { assertNotNull(conn); } } } /** * JIRA: DBCP-342, DBCP-93 * Verify that when errors occur during BasicDataSource initialization, GenericObjectPool * Evictors are cleaned up. */ @Test public void testCreateDataSourceCleanupEvictor() throws Exception { ds.close(); ds = null; ds = createDataSource(); ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnRequestCountDriver"); ds.setUrl("jdbc:apache:commons:testerConnRequestCountDriver"); ds.setValidationQuery("SELECT DUMMY FROM DUAL"); ds.setUsername("userName"); // Make password incorrect, so createDataSource will throw ds.setPassword("wrong"); // Set timeBetweenEvictionRuns > 0, so evictor will be created ds.setDurationBetweenEvictionRuns(Duration.ofMillis(100)); // Set min idle > 0, so evictor will try to make connection as many as idle count ds.setMinIdle(2); // Prevent concurrent execution of threads executing test subclasses synchronized (TesterConnRequestCountDriver.class) { TesterConnRequestCountDriver.initConnRequestCount(); // user request 10 times for (int i = 0; i < 10; i++) { try { @SuppressWarnings("unused") final DataSource ds2 = ds.createDataSource(); } catch (final SQLException e) { // Ignore } } // sleep 1000ms. evictor will be invoked 10 times if running. Thread.sleep(1000); // Make sure there have been no Evictor-generated requests (count should be 10, from requests above) assertEquals(10, TesterConnRequestCountDriver.getConnectionRequestCount()); } // make sure cleanup is complete assertNull(ds.getConnectionPool()); } /** * JIRA DBCP-93: If an SQLException occurs after the GenericObjectPool is * initialized in createDataSource, the evictor task is not cleaned up. */ @Test public void testCreateDataSourceCleanupThreads() throws Exception { ds.close(); ds = null; ds = createDataSource(); ds.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); ds.setUrl("jdbc:apache:commons:testdriver"); ds.setMaxTotal(getMaxTotal()); ds.setMaxWait(getMaxWaitDuration()); ds.setDefaultAutoCommit(Boolean.TRUE); ds.setDefaultReadOnly(Boolean.FALSE); ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); ds.setDefaultCatalog(CATALOG); ds.setUsername("userName"); // Set timeBetweenEvictionRuns > 0, so evictor is created ds.setDurationBetweenEvictionRuns(Duration.ofMillis(100)); // Make password incorrect, so createDataSource will throw ds.setPassword("wrong"); ds.setValidationQuery("SELECT DUMMY FROM DUAL"); final int threadCount = Thread.activeCount(); for (int i = 0; i < 10; i++) { try (Connection c = ds.getConnection()){ } catch (final SQLException ex) { // ignore } } // Allow one extra thread for JRockit compatibility assertTrue(Thread.activeCount() <= threadCount + 1); } @Test public void testDefaultCatalog() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = getConnection(); assertNotNull(c[i]); assertEquals(CATALOG, c[i].getCatalog()); } for (final Connection element : c) { element.setCatalog("error"); element.close(); } for (int i = 0; i < c.length; i++) { c[i] = getConnection(); assertNotNull(c[i]); assertEquals(CATALOG, c[i].getCatalog()); } for (final Connection element : c) { element.close(); } } @Test public void testDeprecatedAccessors() throws SQLException { try (BasicDataSource bds = new BasicDataSource()) { int i = 0; // i++; bds.setDefaultQueryTimeout(i); assertEquals(i, bds.getDefaultQueryTimeout()); assertEquals(Duration.ofSeconds(i), bds.getDefaultQueryTimeoutDuration()); // i++; bds.setMaxConnLifetimeMillis(i); assertEquals(i, bds.getMaxConnLifetimeMillis()); assertEquals(Duration.ofMillis(i), bds.getMaxConnDuration()); // i++; bds.setMaxWaitMillis(i); assertEquals(i, bds.getMaxWaitMillis()); assertEquals(Duration.ofMillis(i), bds.getMaxWaitDuration()); // i++; bds.setMinEvictableIdleTimeMillis(i); assertEquals(i, bds.getMinEvictableIdleTimeMillis()); assertEquals(Duration.ofMillis(i), bds.getMinEvictableIdleDuration()); // i++; bds.setRemoveAbandonedTimeout(i); assertEquals(i, bds.getRemoveAbandonedTimeout()); assertEquals(Duration.ofSeconds(i), bds.getRemoveAbandonedTimeoutDuration()); // i++; bds.setSoftMinEvictableIdleTimeMillis(i); assertEquals(i, bds.getSoftMinEvictableIdleTimeMillis()); assertEquals(Duration.ofMillis(i), bds.getSoftMinEvictableIdleDuration()); // i++; bds.setTimeBetweenEvictionRunsMillis(i); assertEquals(i, bds.getTimeBetweenEvictionRunsMillis()); assertEquals(Duration.ofMillis(i), bds.getDurationBetweenEvictionRuns()); // i++; bds.setValidationQueryTimeout(1); assertEquals(1, bds.getValidationQueryTimeout()); assertEquals(Duration.ofSeconds(1), bds.getValidationQueryTimeoutDuration()); } } /** * JIRA: DBCP-437 * Verify that BasicDataSource sets disconnect codes properties. * Functionality is verified in pcf tests. */ @Test public void testDisconnectSqlCodes() throws Exception { final ArrayList disconnectionSqlCodes = new ArrayList<>(); disconnectionSqlCodes.add("XXX"); ds.setDisconnectionSqlCodes(disconnectionSqlCodes); ds.setFastFailValidation(true); try (Connection conn = ds.getConnection()) { // Triggers initialization - pcf creation // Make sure factory got the properties final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ds.getConnectionPool().getFactory(); assertTrue(pcf.isFastFailValidation()); assertTrue(pcf.getDisconnectionSqlCodes().contains("XXX")); assertEquals(1, pcf.getDisconnectionSqlCodes().size()); } } /** * JIRA DBCP-333: Check that a custom class loader is used. * @throws Exception */ @Test public void testDriverClassLoader() throws Exception { try (Connection conn = getConnection()) { final ClassLoader cl = ds.getDriverClassLoader(); assertNotNull(cl); assertTrue(cl instanceof TesterClassLoader); assertTrue(((TesterClassLoader) cl).didLoad(ds.getDriverClassName())); } } @Test public void testEmptyInitConnectionSql() throws Exception { ds.setConnectionInitSqls(Arrays.asList("", " ")); assertNotNull(ds.getConnectionInitSqls()); assertEquals(0, ds.getConnectionInitSqls().size()); ds.setConnectionInitSqls(null); assertNotNull(ds.getConnectionInitSqls()); assertEquals(0, ds.getConnectionInitSqls().size()); } @Test public void testEmptyValidationQuery() throws Exception { assertNotNull(ds.getValidationQuery()); ds.setValidationQuery(""); assertNull(ds.getValidationQuery()); ds.setValidationQuery(" "); assertNull(ds.getValidationQuery()); } @Test @Disabled public void testEvict() throws Exception { final long delay = 1000; ds.setInitialSize(10); ds.setMaxIdle(10); ds.setMaxTotal(10); ds.setMinIdle(5); ds.setNumTestsPerEvictionRun(3); ds.setMinEvictableIdle(Duration.ofMillis(100)); ds.setDurationBetweenEvictionRuns(Duration.ofMillis(delay)); ds.setPoolPreparedStatements(true); try (Connection conn = ds.getConnection()) { // empty } final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); while (Stream.of(threadBean.getThreadInfo(threadBean.getAllThreadIds())).anyMatch(t -> t.getThreadName().equals("commons-pool-evictor-thread"))) { if (ds.getNumIdle() <= ds.getMinIdle()) { break; } Thread.sleep(delay); } if (ds.getNumIdle() > ds.getMinIdle()) { fail("EvictionTimer thread was destroyed with numIdle=" + ds.getNumIdle() + "(expected: less or equal than " + ds.getMinIdle() + ")"); } } @Test public void testInitialSize() throws Exception { ds.setMaxTotal(20); ds.setMaxIdle(20); ds.setInitialSize(10); try (Connection conn = getConnection()) { assertNotNull(conn); } assertEquals(0, ds.getNumActive()); assertEquals(10, ds.getNumIdle()); } /** * JIRA: DBCP-482 * Verify warning not logged if JMX MBean unregistered before close() called. */ @Test public void testInstanceNotFoundExceptionLogSuppressed() throws Exception { final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try (Connection c = ds.getConnection()) { // nothing } final ObjectName objectName = new ObjectName(ds.getJmxName()); if (mbs.isRegistered(objectName)) { mbs.unregisterMBean(objectName); } StackMessageLog.clear(); ds.close(); assertThat(StackMessageLog.popMessage(), CoreMatchers.not(CoreMatchers.containsString("InstanceNotFoundException"))); assertNull(ds.getRegisteredJmxName()); } @Test public void testInvalidateConnection() throws Exception { ds.setMaxTotal(2); try (final Connection conn1 = ds.getConnection()) { try (final Connection conn2 = ds.getConnection()) { ds.invalidateConnection(conn1); assertTrue(conn1.isClosed()); assertEquals(1, ds.getNumActive()); assertEquals(0, ds.getNumIdle()); try (final Connection conn3 = ds.getConnection()) { conn2.close(); } } } } @Test public void testInvalidConnectionInitSql() { ds.setConnectionInitSqls(Arrays.asList("SELECT 1", "invalid")); final SQLException e = assertThrows(SQLException.class, ds::getConnection); assertTrue(e.toString().contains("invalid")); } @Test public void testInvalidValidationQuery() { ds.setValidationQuery("invalid"); final SQLException e = assertThrows(SQLException.class, ds::getConnection); assertTrue(e.toString().contains("invalid")); } // Bugzilla Bug 28251: Returning dead database connections to BasicDataSource // isClosed() failure blocks returning a connection to the pool @Test public void testIsClosedFailure() throws SQLException { ds.setAccessToUnderlyingConnectionAllowed(true); final Connection conn = ds.getConnection(); assertNotNull(conn); assertEquals(1, ds.getNumActive()); // set an IO failure causing the isClosed method to fail final TesterConnection tconn = (TesterConnection) ((DelegatingConnection) conn).getInnermostDelegate(); tconn.setFailure(new IOException("network error")); assertThrows(SQLException.class, () -> conn.close()); assertEquals(0, ds.getNumActive()); } @Test public void testIsWrapperFor() throws Exception { assertTrue(ds.isWrapperFor(BasicDataSource.class)); assertTrue(ds.isWrapperFor(AutoCloseable.class)); assertFalse(ds.isWrapperFor(String.class)); assertFalse(ds.isWrapperFor(null)); } /** * Make sure setting jmxName to null suppresses JMX registration of connection and statement pools. * JIRA: DBCP-434 */ @Test public void testJmxDisabled() throws Exception { final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // Unregister leftovers from other tests (TODO: worry about concurrent test execution) final ObjectName commons = new ObjectName("org.apache.commons.*:*"); final Set results = mbs.queryNames(commons, null); for (final ObjectName result : results) { mbs.unregisterMBean(result); } ds.setJmxName(null); // Should disable JMX for both connection and statement pools ds.setPoolPreparedStatements(true); try (Connection conn = ds.getConnection()) { // Trigger initialization // Nothing should be registered assertEquals(0, mbs.queryNames(commons, null).size()); } } /** * Test disabling MBean registration for Connection objects. * JIRA: DBCP-585 */ @Test public void testConnectionMBeansDisabled() throws Exception { final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // Unregister leftovers from other tests (TODO: worry about concurrent test execution) final ObjectName commons = new ObjectName("org.apache.commons.*:*"); final Set results = mbs.queryNames(commons, null); for (final ObjectName result : results) { mbs.unregisterMBean(result); } ds.setRegisterConnectionMBean(false); // Should disable Connection MBean registration try (Connection conn = ds.getConnection()) { // Trigger initialization // No Connection MBeans shall be registered final ObjectName connections = new ObjectName("org.apache.commons.*:connection=*,*"); assertEquals(0, mbs.queryNames(connections, null).size()); } } /** * Tests JIRA DBCP-562. *

* Make sure Password Attribute is not exported via JMXBean. *

*/ @Test public void testJmxDoesNotExposePassword() throws Exception { final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try (Connection c = ds.getConnection()) { // nothing } final ObjectName objectName = new ObjectName(ds.getJmxName()); final MBeanAttributeInfo[] attributes = mbs.getMBeanInfo(objectName).getAttributes(); assertTrue(attributes != null && attributes.length > 0); Arrays.asList(attributes).forEach(attrInfo -> { assertFalse("password".equalsIgnoreCase(attrInfo.getName())); }); assertThrows(AttributeNotFoundException.class, () -> { mbs.getAttribute(objectName, "Password"); }); } @Test public void testManualConnectionEvict() throws Exception { ds.setMinIdle(0); ds.setMaxIdle(4); ds.setMinEvictableIdle(Duration.ofMillis(10)); ds.setNumTestsPerEvictionRun(2); try (Connection ds2 = ds.createDataSource().getConnection(); Connection ds3 = ds.createDataSource().getConnection()) { assertEquals(0, ds.getNumIdle()); } // Make sure MinEvictableIdleTimeMillis has elapsed Thread.sleep(100); // Ensure no connections evicted by eviction thread assertEquals(2, ds.getNumIdle()); // Force Eviction ds.evict(); // Ensure all connections evicted assertEquals(0, ds.getNumIdle()); } @Test public void testMaxConnLifetimeExceeded() throws Exception { try { StackMessageLog.lock(); ds.setMaxConn(Duration.ofMillis(100)); try (Connection conn = ds.getConnection()) { assertEquals(1, ds.getNumActive()); Thread.sleep(500); } assertEquals(0, ds.getNumIdle()); final String message = StackMessageLog.popMessage(); Assertions.assertNotNull(message); assertTrue(message.indexOf("exceeds the maximum permitted value") > 0); } finally { StackMessageLog.clear(); StackMessageLog.unLock(); } } @Test public void testMaxConnLifetimeExceededMutedLog() throws Exception { try { StackMessageLog.lock(); StackMessageLog.clear(); ds.setMaxConn(Duration.ofMillis(100)); ds.setLogExpiredConnections(false); try (final Connection conn = ds.getConnection()) { assertEquals(1, ds.getNumActive()); Thread.sleep(500); } assertEquals(0, ds.getNumIdle()); assertTrue(StackMessageLog.isEmpty(), StackMessageLog.getAll().toString()); } finally { StackMessageLog.clear(); StackMessageLog.unLock(); } } /** * Bugzilla Bug 29832: Broken behavior for BasicDataSource.setMaxTotal(0) * MaxTotal == 0 should throw SQLException on getConnection. * Results from Bug 29863 in commons-pool. */ @Test public void testMaxTotalZero() throws Exception { ds.setMaxTotal(0); assertThrows(SQLException.class, ds::getConnection); } /** * JIRA: DBCP-457 * Verify that changes made to abandoned config are passed to the underlying * pool. */ @Test public void testMutateAbandonedConfig() throws Exception { final Properties properties = new Properties(); properties.put("initialSize", "1"); properties.put("driverClassName", "org.apache.commons.dbcp2.TesterDriver"); properties.put("url", "jdbc:apache:commons:testdriver"); properties.put("username", "foo"); properties.put("password", "bar"); try (BasicDataSource ds = BasicDataSourceFactory.createDataSource(properties)) { final boolean original = ds.getConnectionPool().getLogAbandoned(); ds.setLogAbandoned(!original); Assertions.assertNotEquals(original, ds.getConnectionPool().getLogAbandoned()); } } @Test public void testNoAccessToUnderlyingConnectionAllowed() throws Exception { // default: false assertFalse(ds.isAccessToUnderlyingConnectionAllowed()); try (Connection conn = getConnection()) { Connection dconn = ((DelegatingConnection) conn).getDelegate(); assertNull(dconn); dconn = ((DelegatingConnection) conn).getInnermostDelegate(); assertNull(dconn); } } /** * Verifies correct handling of exceptions generated by the underlying pool as it closes * connections in response to BDS#close. Exceptions have to be either swallowed by the * underlying pool and logged, or propagated and wrapped. */ @Test public void testPoolCloseCheckedException() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); // Allow dirty tricks final TesterConnection tc; // Get an idle connection into the pool try (Connection conn = ds.getConnection()) { tc = (TesterConnection) ((DelegatingConnection) conn).getInnermostDelegate(); } // After returning the connection to the pool, bork it. // Don't try this at home - bad violation of pool contract! tc.setFailure(new SQLException("bang")); // Now close Datasource, which will cause tc to be closed, triggering SQLE // Pool 2.x swallows and logs exceptions on pool close. Below verifies that // Either exceptions get logged or wrapped appropriately. try { StackMessageLog.lock(); StackMessageLog.clear(); ds.close(); // Exception must have been swallowed by the pool - verify it is logged final String message = StackMessageLog.popMessage(); Assertions.assertNotNull(message); assertTrue(message.indexOf("bang") > 0); } catch (final SQLException ex) { assertTrue(ex.getMessage().indexOf("Cannot close") > 0); assertTrue(ex.getCause().getMessage().indexOf("bang") > 0); } finally { StackMessageLog.unLock(); } } @Test public void testPoolCloseRTE() throws Exception { // RTE version of testPoolCloseCheckedException - see comments there. ds.setAccessToUnderlyingConnectionAllowed(true); final TesterConnection tc; try (Connection conn = ds.getConnection()) { tc = (TesterConnection) ((DelegatingConnection) conn).getInnermostDelegate(); } tc.setFailure(new IllegalStateException("boom")); try { StackMessageLog.lock(); StackMessageLog.clear(); ds.close(); final String message = StackMessageLog.popMessage(); Assertions.assertNotNull(message); assertTrue(message.indexOf("boom") > 0); } catch (final IllegalStateException ex) { assertTrue(ex.getMessage().indexOf("boom") > 0); // RTE is not wrapped by BDS#close } finally { StackMessageLog.unLock(); } } @Override @Test public void testPooling() throws Exception { // this also needs access to the underlying connection ds.setAccessToUnderlyingConnectionAllowed(true); super.testPooling(); } /** * Bugzilla Bug 29054: * The BasicDataSource.setTestOnReturn(boolean) is not carried through to * the GenericObjectPool variable _testOnReturn. */ @Test public void testPropertyTestOnReturn() throws Exception { ds.setValidationQuery("select 1 from dual"); ds.setTestOnBorrow(false); ds.setTestWhileIdle(false); ds.setTestOnReturn(true); try (Connection conn = ds.getConnection()) { assertNotNull(conn); assertFalse(ds.getConnectionPool().getTestOnBorrow()); assertFalse(ds.getConnectionPool().getTestWhileIdle()); assertTrue(ds.getConnectionPool().getTestOnReturn()); } } @Test public void testRestart() throws Exception { ds.setMaxTotal(2); ds.setDurationBetweenEvictionRuns(Duration.ofMillis(100)); ds.setNumTestsPerEvictionRun(2); ds.setMinEvictableIdle(Duration.ofMinutes(1)); ds.setInitialSize(2); ds.setDefaultCatalog("foo"); try (Connection conn1 = ds.getConnection()) { Thread.sleep(200); // Now set some property that will not have effect until restart ds.setDefaultCatalog("bar"); ds.setInitialSize(1); // restart will load new properties ds.restart(); assertEquals("bar", ds.getDefaultCatalog()); assertEquals(1, ds.getInitialSize()); ds.getLogWriter(); // side effect is to init assertEquals(0, ds.getNumActive()); assertEquals(1, ds.getNumIdle()); } // verify old pool connection is not returned to pool assertEquals(1, ds.getNumIdle()); ds.close(); } /** * Bugzilla Bug 29055: AutoCommit and ReadOnly * The DaffodilDB driver throws an SQLException if * trying to commit or rollback a readOnly connection. */ @Test public void testRollbackReadOnly() throws Exception { ds.setDefaultReadOnly(Boolean.TRUE); ds.setDefaultAutoCommit(Boolean.FALSE); try (Connection conn = ds.getConnection()) { assertNotNull(conn); } } @Test public void testSetAutoCommitTrueOnClose() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); ds.setDefaultAutoCommit(Boolean.FALSE); final Connection dconn; try (Connection conn = getConnection()) { assertNotNull(conn); assertFalse(conn.getAutoCommit()); dconn = ((DelegatingConnection) conn).getInnermostDelegate(); assertNotNull(dconn); assertFalse(dconn.getAutoCommit()); } assertTrue(dconn.getAutoCommit()); } @Test public void testSetProperties() throws Exception { // normal ds.setConnectionProperties("name1=value1;name2=value2;name3=value3"); assertEquals(3, ds.getConnectionProperties().size()); assertEquals("value1", ds.getConnectionProperties().getProperty("name1")); assertEquals("value2", ds.getConnectionProperties().getProperty("name2")); assertEquals("value3", ds.getConnectionProperties().getProperty("name3")); // make sure all properties are replaced ds.setConnectionProperties("name1=value1;name2=value2"); assertEquals(2, ds.getConnectionProperties().size()); assertEquals("value1", ds.getConnectionProperties().getProperty("name1")); assertEquals("value2", ds.getConnectionProperties().getProperty("name2")); assertFalse(ds.getConnectionProperties().containsKey("name3")); // no value is empty string ds.setConnectionProperties("name1=value1;name2"); assertEquals(2, ds.getConnectionProperties().size()); assertEquals("value1", ds.getConnectionProperties().getProperty("name1")); assertEquals("", ds.getConnectionProperties().getProperty("name2")); // no value (with equals) is empty string ds.setConnectionProperties("name1=value1;name2="); assertEquals(2, ds.getConnectionProperties().size()); assertEquals("value1", ds.getConnectionProperties().getProperty("name1")); assertEquals("", ds.getConnectionProperties().getProperty("name2")); // single value ds.setConnectionProperties("name1=value1"); assertEquals(1, ds.getConnectionProperties().size()); assertEquals("value1", ds.getConnectionProperties().getProperty("name1")); // single value with trailing ; ds.setConnectionProperties("name1=value1;"); assertEquals(1, ds.getConnectionProperties().size()); assertEquals("value1", ds.getConnectionProperties().getProperty("name1")); // single value wit no value ds.setConnectionProperties("name1"); assertEquals(1, ds.getConnectionProperties().size()); assertEquals("", ds.getConnectionProperties().getProperty("name1")); // null should throw a NullPointerException assertThrows(NullPointerException.class, () -> ds.setConnectionProperties(null)); } @Test public void testSetValidationTestProperties() { // defaults assertTrue(ds.getTestOnBorrow()); assertFalse(ds.getTestOnReturn()); assertFalse(ds.getTestWhileIdle()); ds.setTestOnBorrow(true); ds.setTestOnReturn(true); ds.setTestWhileIdle(true); assertTrue(ds.getTestOnBorrow()); assertTrue(ds.getTestOnReturn()); assertTrue(ds.getTestWhileIdle()); ds.setTestOnBorrow(false); ds.setTestOnReturn(false); ds.setTestWhileIdle(false); assertFalse(ds.getTestOnBorrow()); assertFalse(ds.getTestOnReturn()); assertFalse(ds.getTestWhileIdle()); } @Test public void testStart() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); ds.setMaxTotal(2); final DelegatingConnection conn1 = (DelegatingConnection) ds.getConnection(); final DelegatingConnection conn2 = (DelegatingConnection) ds.getConnection(); final Connection inner1 = conn1.getInnermostDelegate(); final Connection inner2 = conn2.getInnermostDelegate(); assertFalse(inner2.isClosed()); conn2.close(); assertFalse(inner2.isClosed()); // One active, one idle in the pool ds.close(); // Idle connection should be physically closed, checked out unaffected assertFalse(conn1.isClosed()); assertTrue(inner2.isClosed()); assertEquals(0, ds.getNumIdle()); // Reopen creates a new pool, so we can have three out ds.start(); final Connection conn3 = ds.getConnection(); final Connection conn4 = ds.getConnection(); conn3.close(); conn4.close(); // Old pool's orphan should get physically closed on return conn1.close(); assertTrue(inner1.isClosed()); } @Test public void testStartInitializes() throws Exception { ds.setInitialSize(2); // Note: if we ever move away from lazy init, next two will fail assertEquals(0, ds.getNumIdle()); assertNull(ds.getRegisteredJmxName()); // Start forces init ds.start(); assertEquals(2, ds.getNumIdle()); assertNotNull(ds.getRegisteredJmxName()); } @Test public void testTransactionIsolationBehavior() throws Exception { try (final Connection conn = getConnection()) { assertNotNull(conn); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); } final Connection conn2 = getConnection(); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation()); final Connection conn3 = getConnection(); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation()); conn2.close(); conn3.close(); } @Test public void testUnwrap() throws Exception { assertSame(ds.unwrap(BasicDataSource.class), ds); assertSame(ds.unwrap(AutoCloseable.class), ds); assertThrows(SQLException.class, () -> ds.unwrap(String.class)); assertThrows(SQLException.class, () -> ds.unwrap(null)); } @Test public void testValidationQueryTimeoutNegative() throws Exception { ds.setTestOnBorrow(true); ds.setTestOnReturn(true); ds.setValidationQueryTimeout(Duration.ofSeconds(-1)); try (final Connection con = ds.getConnection()) { // close right away. } } @Test public void testValidationQueryTimeoutSucceed() throws Exception { ds.setTestOnBorrow(true); ds.setTestOnReturn(true); ds.setValidationQueryTimeout(Duration.ofMillis(100)); // Works for TesterStatement try (final Connection con = ds.getConnection()) { // close right away. } } @Test public void testValidationQueryTimeoutZero() throws Exception { ds.setTestOnBorrow(true); ds.setTestOnReturn(true); ds.setValidationQueryTimeout(Duration.ZERO); try (final Connection con = ds.getConnection()) { // close right away. } } @Test public void testValidationQueryTimoutFail() { ds.setTestOnBorrow(true); ds.setValidationQueryTimeout(Duration.ofSeconds(3)); // Too fast for TesterStatement final SQLException e = assertThrows(SQLException.class, ds::getConnection); assertTrue(e.toString().contains("timeout")); } } /** * TesterDriver that adds latency to connection requests. Latency (in ms) is the * last component of the URL. */ class TesterConnectionDelayDriver extends TesterDriver { private static final String CONNECT_STRING = "jdbc:apache:commons:testerConnectionDelayDriver"; public TesterConnectionDelayDriver() { // DBCP expects an explicit no-arg constructor } @Override public boolean acceptsURL(final String url) throws SQLException { return url.startsWith(CONNECT_STRING); } @Override public Connection connect(final String url, final Properties info) throws SQLException { final String[] parsedUrl = url.split(":"); final int delay = Integer.parseInt(parsedUrl[parsedUrl.length - 1]); try { Thread.sleep(delay); } catch (final InterruptedException ex) { Thread.currentThread().interrupt(); } return super.connect(url, info); } } /** * TesterDriver that keeps a static count of connection requests. */ class TesterConnRequestCountDriver extends TesterDriver { private static final String CONNECT_STRING = "jdbc:apache:commons:testerConnRequestCountDriver"; private static final AtomicInteger connectionRequestCount = new AtomicInteger(0); public static int getConnectionRequestCount() { return connectionRequestCount.get(); } public static void initConnRequestCount() { connectionRequestCount.set(0); } public TesterConnRequestCountDriver() { // DBCP expects an explicit no-arg constructor } @Override public boolean acceptsURL(final String url) throws SQLException { return CONNECT_STRING.startsWith(url); } @Override public Connection connect(final String url, final Properties info) throws SQLException { connectionRequestCount.incrementAndGet(); return super.connect(url, info); } } TestBasicDataSourceFactory.java000066400000000000000000000251201447311732500344350ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.management.ManagementFactory; import java.sql.Connection; import java.time.Duration; import java.util.List; import java.util.Map.Entry; import java.util.Properties; import javax.management.MBeanServer; import javax.naming.Reference; import javax.naming.StringRefAddr; import org.apache.commons.pool2.impl.GenericObjectPool; import org.junit.jupiter.api.Test; /** * TestSuite for BasicDataSourceFactory */ public class TestBasicDataSourceFactory { private void checkConnectionPoolProperties(final GenericObjectPool cp) { assertEquals(10, cp.getMaxTotal()); assertEquals(8, cp.getMaxIdle()); assertEquals(0, cp.getMinIdle()); assertEquals(Duration.ofMillis(500), cp.getMaxWaitDuration()); assertEquals(5, cp.getNumIdle()); assertTrue(cp.getTestOnBorrow()); assertFalse(cp.getTestOnReturn()); assertEquals(Duration.ofSeconds(1), cp.getDurationBetweenEvictionRuns()); assertEquals(Duration.ofSeconds(2), cp.getMinEvictableIdleDuration()); assertEquals(Duration.ofSeconds(3), cp.getSoftMinEvictableIdleDuration()); assertEquals(2, cp.getNumTestsPerEvictionRun()); assertTrue(cp.getTestWhileIdle()); assertTrue(cp.getRemoveAbandonedOnBorrow()); assertTrue(cp.getRemoveAbandonedOnMaintenance()); assertEquals(Duration.ofSeconds(3000), cp.getRemoveAbandonedTimeoutDuration()); assertTrue(cp.getLogAbandoned()); assertTrue(cp.getLifo()); } private void checkDataSourceProperties(final BasicDataSource ds) throws Exception { assertEquals("org.apache.commons.dbcp2.TesterDriver", ds.getDriverClassName()); assertEquals("jdbc:apache:commons:testdriver", ds.getUrl()); assertEquals(10, ds.getMaxTotal()); assertEquals(8, ds.getMaxIdle()); assertEquals(0, ds.getMinIdle()); assertEquals(Duration.ofMillis(500), ds.getMaxWaitDuration()); assertEquals(5, ds.getInitialSize()); assertEquals(5, ds.getNumIdle()); assertEquals(Boolean.TRUE, ds.getDefaultAutoCommit()); assertEquals(Boolean.FALSE, ds.getDefaultReadOnly()); assertEquals(Connection.TRANSACTION_READ_COMMITTED, ds.getDefaultTransactionIsolation()); assertEquals("test", ds.getDefaultCatalog()); assertEquals("testSchema", ds.getDefaultSchema()); assertTrue(ds.getTestOnBorrow()); assertFalse(ds.getTestOnReturn()); assertEquals("userName", ds.getUsername()); assertEquals("password", ds.getPassword()); assertEquals("SELECT DUMMY FROM DUAL", ds.getValidationQuery()); assertEquals(Duration.ofSeconds(100), ds.getValidationQueryTimeoutDuration()); assertEquals(2, ds.getConnectionInitSqls().size()); assertEquals("SELECT 1", ds.getConnectionInitSqls().get(0)); assertEquals("SELECT 2", ds.getConnectionInitSqls().get(1)); assertEquals(Duration.ofMillis(1000), ds.getDurationBetweenEvictionRuns()); assertEquals(Duration.ofMillis(2000), ds.getMinEvictableIdleDuration()); assertEquals(Duration.ofMillis(3000), ds.getSoftMinEvictableIdleDuration()); assertEquals(2, ds.getNumTestsPerEvictionRun()); assertTrue(ds.getTestWhileIdle()); assertTrue(ds.isAccessToUnderlyingConnectionAllowed()); assertTrue(ds.getRemoveAbandonedOnBorrow()); assertTrue(ds.getRemoveAbandonedOnMaintenance()); assertEquals(Duration.ofSeconds(3000), ds.getRemoveAbandonedTimeoutDuration()); assertTrue(ds.getLogAbandoned()); assertTrue(ds.getAbandonedUsageTracking()); assertTrue(ds.isPoolPreparedStatements()); assertTrue(ds.isClearStatementPoolOnReturn()); assertEquals(10, ds.getMaxOpenPreparedStatements()); assertTrue(ds.getLifo()); assertTrue(ds.getFastFailValidation()); assertTrue(ds.getDisconnectionSqlCodes().contains("XXX")); assertTrue(ds.getDisconnectionSqlCodes().contains("YYY")); assertEquals("org.apache.commons.dbcp2:name=test", ds.getJmxName()); // Unregister so subsequent calls to getTestProperties can re-register final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); mbs.unregisterMBean(ds.getRegisteredJmxName()); } private Properties getTestProperties() { final Properties properties = new Properties(); properties.setProperty("driverClassName", "org.apache.commons.dbcp2.TesterDriver"); properties.setProperty("url", "jdbc:apache:commons:testdriver"); properties.setProperty("maxTotal", "10"); properties.setProperty("maxIdle", "8"); properties.setProperty("minIdle", "0"); properties.setProperty("maxWaitMillis", "500"); properties.setProperty("initialSize", "5"); properties.setProperty("defaultAutoCommit", "true"); properties.setProperty("defaultReadOnly", "false"); properties.setProperty("defaultTransactionIsolation", "READ_COMMITTED"); properties.setProperty("defaultCatalog", "test"); properties.setProperty("defaultSchema", "testSchema"); properties.setProperty("testOnBorrow", "true"); properties.setProperty("testOnReturn", "false"); properties.setProperty("username", "userName"); properties.setProperty("password", "password"); properties.setProperty("validationQuery", "SELECT DUMMY FROM DUAL"); properties.setProperty("validationQueryTimeout", "100"); properties.setProperty("connectionInitSqls", "SELECT 1;SELECT 2"); properties.setProperty("timeBetweenEvictionRunsMillis", "1000"); properties.setProperty("minEvictableIdleTimeMillis", "2000"); properties.setProperty("softMinEvictableIdleTimeMillis", "3000"); properties.setProperty("numTestsPerEvictionRun", "2"); properties.setProperty("testWhileIdle", "true"); properties.setProperty("accessToUnderlyingConnectionAllowed", "true"); properties.setProperty("removeAbandonedOnBorrow", "true"); properties.setProperty("removeAbandonedOnMaintenance", "true"); properties.setProperty("removeAbandonedTimeout", "3000"); properties.setProperty("logAbandoned", "true"); properties.setProperty("abandonedUsageTracking", "true"); properties.setProperty("poolPreparedStatements", "true"); properties.setProperty("clearStatementPoolOnReturn", "true"); properties.setProperty("maxOpenPreparedStatements", "10"); properties.setProperty("lifo", "true"); properties.setProperty("fastFailValidation", "true"); properties.setProperty("disconnectionSqlCodes", "XXX,YYY"); properties.setProperty("jmxName", "org.apache.commons.dbcp2:name=test"); return properties; } @Test public void testAllProperties() throws Exception { try { StackMessageLog.lock(); StackMessageLog.clear(); final Reference ref = new Reference("javax.sql.DataSource", BasicDataSourceFactory.class.getName(), null); final Properties properties = getTestProperties(); for (final Entry entry : properties.entrySet()) { ref.add(new StringRefAddr((String) entry.getKey(), (String) entry.getValue())); } final BasicDataSourceFactory basicDataSourceFactory = new BasicDataSourceFactory(); try (final BasicDataSource ds = (BasicDataSource) basicDataSourceFactory.getObjectInstance(ref, null, null, null)) { checkDataSourceProperties(ds); checkConnectionPoolProperties(ds.getConnectionPool()); final List messages = StackMessageLog.getAll(); assertEquals(0, messages.size()); } } finally { StackMessageLog.clear(); StackMessageLog.unLock(); } } @Test public void testNoProperties() throws Exception { final Properties properties = new Properties(); try (final BasicDataSource ds = BasicDataSourceFactory.createDataSource(properties)) { assertNotNull(ds); } } @Test public void testProperties() throws Exception { try (final BasicDataSource ds = BasicDataSourceFactory.createDataSource(getTestProperties())) { checkDataSourceProperties(ds); } } @Test public void testValidateProperties() throws Exception { try { StackMessageLog.lock(); StackMessageLog.clear(); final Reference ref = new Reference("javax.sql.DataSource", BasicDataSourceFactory.class.getName(), null); ref.add(new StringRefAddr("foo", "bar")); // Unknown ref.add(new StringRefAddr("maxWait", "100")); // Changed ref.add(new StringRefAddr("driverClassName", "org.apache.commons.dbcp2.TesterDriver")); // OK final BasicDataSourceFactory basicDataSourceFactory = new BasicDataSourceFactory(); basicDataSourceFactory.getObjectInstance(ref, null, null, null); final List messages = StackMessageLog.getAll(); assertEquals(2, messages.size(), messages.toString()); for (final String message : messages) { if (message.contains("maxWait")) { assertTrue(message.contains("use maxWaitMillis")); } else { assertTrue(message.contains("foo")); assertTrue(message.contains("Ignoring unknown property")); } } } finally { StackMessageLog.clear(); StackMessageLog.unLock(); } } } TestBasicDataSourceMXBean.java000066400000000000000000000141551447311732500341460ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.management.ManagementFactory; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.OperationsException; import org.junit.jupiter.api.Test; /** * Tests for BasicDataSourceMXBean. */ public class TestBasicDataSourceMXBean { private final BasicDataSourceMXBean bean = new BasicDataSourceMXBean() { @Override public boolean getAbandonedUsageTracking() { return false; } @Override public boolean getCacheState() { return false; } @Override public String[] getConnectionInitSqlsAsArray() { return null; } @Override public Boolean getDefaultAutoCommit() { return null; } @Override public String getDefaultCatalog() { return null; } @Override public Boolean getDefaultReadOnly() { return null; } @Override public int getDefaultTransactionIsolation() { return 0; } @Override public String[] getDisconnectionSqlCodesAsArray() { return null; } @Override public String getDriverClassName() { return null; } @Override public boolean getFastFailValidation() { return false; } @Override public int getInitialSize() { return 0; } @Override public boolean getLifo() { return false; } @Override public boolean getLogAbandoned() { return false; } @Override public boolean getLogExpiredConnections() { return false; } @Override public long getMaxConnLifetimeMillis() { return 0; } @Override public int getMaxIdle() { return 0; } @Override public int getMaxOpenPreparedStatements() { return 0; } @Override public int getMaxTotal() { return 0; } @Override public long getMaxWaitMillis() { return 0; } @Override public long getMinEvictableIdleTimeMillis() { return 0; } @Override public int getMinIdle() { return 0; } @Override public int getNumActive() { return 0; } @Override public int getNumIdle() { return 0; } @Override public int getNumTestsPerEvictionRun() { return 0; } @Override public String getPassword() { return null; } @Override public boolean getRemoveAbandonedOnBorrow() { return false; } @Override public boolean getRemoveAbandonedOnMaintenance() { return false; } @Override public int getRemoveAbandonedTimeout() { return 0; } @Override public long getSoftMinEvictableIdleTimeMillis() { return 0; } @Override public boolean getTestOnBorrow() { return false; } @Override public boolean getTestOnCreate() { return false; } @Override public boolean getTestWhileIdle() { return false; } @Override public long getTimeBetweenEvictionRunsMillis() { return 0; } @Override public String getUrl() { return null; } @Override public String getUsername() { return null; } @Override public String getValidationQuery() { return null; } @Override public int getValidationQueryTimeout() { return 0; } @Override public boolean isAccessToUnderlyingConnectionAllowed() { return false; } @Override public boolean isClearStatementPoolOnReturn() { return false; } @Override public boolean isClosed() { return false; } @Override public boolean isPoolPreparedStatements() { return false; } }; /** * Tests the interface defined default method. */ @Test public void testDefaultSchema() { assertNull(bean.getDefaultSchema()); } /** * Tests if the {@link BasicDataSourceMXBean} interface is a valid MXBean interface. */ @Test public void testMXBeanCompliance() throws OperationsException { testMXBeanCompliance(BasicDataSourceMXBean.class); } public static void testMXBeanCompliance(Class clazz) throws OperationsException { assertTrue(JMX.isMXBeanInterface(clazz)); final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); final ObjectName objectName = ObjectName.getInstance("com.sun.management:type=DiagnosticCommand"); JMX.newMBeanProxy(server, objectName, clazz, true); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestConnectionPool.java000066400000000000000000001107161447311732500331270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import java.util.Hashtable; import java.util.Random; import java.util.Stack; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; // XXX FIX ME XXX // this class still needs some cleanup, but at least // this consolidates most of the relevant test code // in a fairly re-usable fashion // XXX FIX ME XXX /** * Base test suite for DBCP pools. */ public abstract class TestConnectionPool { private static final Duration MAX_WAIT_DURATION = Duration.ofMillis(100); protected class PoolTest implements Runnable { /** * The number of milliseconds to hold onto a database connection */ private final Duration connHoldDuration; private final int numStatements; private volatile boolean isRun; private String state; // No need to be volatile if it is read after the thread finishes private final Thread thread; private Throwable thrown; private final Random random = new Random(); // Debug for DBCP-318 private final long createdMillis; // When object was created private long started; // when thread started private long ended; // when thread ended private long preconnected; // just before connect private long connected; // when thread last connected private long postconnected; // when thread released connection private int loops; private int connHash; // Connection identity hashCode (to see which one is reused) private final boolean stopOnException; // If true, don't rethrow Exception private final boolean loopOnce; // If true, don't repeat loop public PoolTest(final ThreadGroup threadGroup, final Duration connHoldDuration, final boolean isStopOnException) { this(threadGroup, connHoldDuration, isStopOnException, false, 1); } private PoolTest(final ThreadGroup threadGroup, final Duration connHoldDuration, final boolean isStopOnException, final boolean once, final int numStatements) { this.loopOnce = once; this.connHoldDuration = connHoldDuration; stopOnException = isStopOnException; isRun = true; // Must be done here so main thread is guaranteed to be able to set it false thrown = null; thread = new Thread(threadGroup, this, "Thread+" + currentThreadCount++); thread.setDaemon(false); createdMillis = timeStampMillis(); this.numStatements = numStatements; } public PoolTest(final ThreadGroup threadGroup, final Duration connHoldDuration, final boolean isStopOnException, final int numStatements) { this(threadGroup, connHoldDuration, isStopOnException, false, numStatements); } public Thread getThread() { return thread; } @Override public void run() { started = timeStampMillis(); try { while (isRun) { loops++; state = "Getting Connection"; preconnected = timeStampMillis(); try (Connection conn = getConnection()) { connHash = System.identityHashCode(((DelegatingConnection) conn).getInnermostDelegate()); connected = timeStampMillis(); state = "Using Connection"; assertNotNull(conn); final String sql = numStatements == 1 ? "select * from dual" : "select count " + random.nextInt(numStatements - 1); try (PreparedStatement stmt = conn.prepareStatement(sql)) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); state = "Holding Connection"; Thread.sleep(connHoldDuration.toMillis()); state = "Closing ResultSet"; } state = "Closing Statement"; } state = "Closing Connection"; } postconnected = timeStampMillis(); state = "Closed"; if (loopOnce) { break; // Or could set isRun=false } } state = DONE; } catch (final Throwable t) { thrown = t; if (!stopOnException) { throw new RuntimeException(); } } finally { ended = timeStampMillis(); } } public void start(){ thread.start(); } public void stop() { isRun = false; } } class TestThread implements Runnable { final java.util.Random _random = new java.util.Random(); boolean _complete; boolean _failed; int _iter = 100; int _delay = 50; public TestThread() { } public TestThread(final int iter) { _iter = iter; } public TestThread(final int iter, final int delay) { _iter = iter; _delay = delay; } public boolean complete() { return _complete; } public boolean failed() { return _failed; } @Override public void run() { for (int i = 0; i < _iter; i++) { try { Thread.sleep(_random.nextInt(_delay)); } catch (final Exception e) { // ignored } try (Connection conn = newConnection(); PreparedStatement stmt = conn.prepareStatement("select 'literal', SYSDATE from dual"); ResultSet rset = stmt.executeQuery()) { try { Thread.sleep(_random.nextInt(_delay)); } catch (final Exception ignore) { // ignored } } catch (final Exception e) { e.printStackTrace(); _failed = true; _complete = true; break; } } _complete = true; } } private static final boolean DISPLAY_THREAD_DETAILS= Boolean.parseBoolean(System.getProperty("TestConnectionPool.display.thread.details", "false")); // To pass this to a Maven test, use: // mvn test -DargLine="-DTestConnectionPool.display.thread.details=true" // @see https://issues.apache.org/jira/browse/SUREFIRE-121 private static int currentThreadCount; private static final String DONE = "Done"; /** Connections opened during the course of a test */ protected final Stack connectionStack = new Stack<>(); // ----------- Utility Methods --------------------------------- protected void assertBackPointers(final Connection conn, final Statement statement) throws SQLException { assertFalse(conn.isClosed()); assertFalse(isClosed(statement)); assertSame(conn, statement.getConnection(), "statement.getConnection() should return the exact same connection instance that was used to create the statement"); final ResultSet resultSet = statement.getResultSet(); assertFalse(isClosed(resultSet)); assertSame(statement, resultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); final ResultSet executeResultSet = statement.executeQuery("select * from dual"); assertFalse(isClosed(executeResultSet)); assertSame(statement, executeResultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); final ResultSet keysResultSet = statement.getGeneratedKeys(); assertFalse(isClosed(keysResultSet)); assertSame(statement, keysResultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); ResultSet preparedResultSet = null; if (statement instanceof PreparedStatement) { final PreparedStatement preparedStatement = (PreparedStatement) statement; preparedResultSet = preparedStatement.executeQuery(); assertFalse(isClosed(preparedResultSet)); assertSame(statement, preparedResultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); } resultSet.getStatement().getConnection().close(); assertTrue(conn.isClosed()); assertTrue(isClosed(statement)); assertTrue(isClosed(resultSet)); assertTrue(isClosed(executeResultSet)); assertTrue(isClosed(keysResultSet)); if (preparedResultSet != null) { assertTrue(isClosed(preparedResultSet)); } } protected abstract Connection getConnection() throws Exception; protected int getMaxTotal() { return 10; } protected Duration getMaxWaitDuration() { return MAX_WAIT_DURATION; } protected String getUsername(final Connection conn) throws SQLException { try (final Statement stmt = conn.createStatement(); final ResultSet rs = stmt.executeQuery("select username")) { if (rs.next()) { return rs.getString(1); } } return null; } protected boolean isClosed(final ResultSet resultSet) { try { resultSet.getWarnings(); return false; } catch (final SQLException e) { // getWarnings throws an exception if the statement is // closed, but could throw an exception for other reasons // in this case it is good enough to assume the result set // is closed return true; } } protected boolean isClosed(final Statement statement) { try { statement.getWarnings(); return false; } catch (final SQLException e) { // getWarnings throws an exception if the statement is // closed, but could throw an exception for other reasons // in this case it is good enough to assume the statement // is closed return true; } } /** * Launches a group of 2 * getMaxTotal() threads, each of which will attempt to obtain a connection * from the pool, hold it for {@code holdTime} ms, and then return it to the pool. If {@code loopOnce} is false, * threads will continue this process indefinitely. If {@code expectError} is true, exactly 1/2 of the * threads are expected to either throw exceptions or fail to complete. If {@code expectError} is false, * all threads are expected to complete successfully. * * @param holdDuration Duration that a thread holds a connection before returning it to the pool * @param expectError whether or not an error is expected * @param loopOnce whether threads should complete the borrow - hold - return cycle only once, or loop indefinitely * @param maxWaitDuration passed in by client - has no impact on the test itself, but does get reported * * @throws Exception */ protected void multipleThreads(final Duration holdDuration, final boolean expectError, final boolean loopOnce, final Duration maxWaitDuration) throws Exception { multipleThreads(holdDuration, expectError, loopOnce, maxWaitDuration, 1, 2 * getMaxTotal(), 300); } /** * Launches a group of {@code numThreads} threads, each of which will attempt to obtain a connection * from the pool, hold it for {@code holdTime} ms, and then return it to the pool. If {@code loopOnce} is false, * threads will continue this process indefinitely. If {@code expectError} is true, exactly 1/2 of the * threads are expected to either throw exceptions or fail to complete. If {@code expectError} is false, * all threads are expected to complete successfully. Threads are stopped after {@code duration} ms. * * @param holdDuration Duration that a thread holds a connection before returning it to the pool * @param expectError whether or not an error is expected * @param loopOnce whether threads should complete the borrow - hold - return cycle only once, or loop indefinitely * @param maxWaitDuration passed in by client - has no impact on the test itself, but does get reported * @param numThreads the number of threads * @param duration duration in ms of test * * @throws Exception */ protected void multipleThreads(final Duration holdDuration, final boolean expectError, final boolean loopOnce, final Duration maxWaitDuration, final int numStatements, final int numThreads, final long duration) throws Exception { final long startTimeMillis = timeStampMillis(); final PoolTest[] pts = new PoolTest[numThreads]; // Catch Exception so we can stop all threads if one fails final ThreadGroup threadGroup = new ThreadGroup("foo") { @Override public void uncaughtException(final Thread t, final Throwable e) { for (final PoolTest pt : pts) { pt.stop(); } } }; // Create all the threads for (int i = 0; i < pts.length; i++) { pts[i] = new PoolTest(threadGroup, holdDuration, expectError, loopOnce, numStatements); } // Start all the threads for (final PoolTest pt : pts) { pt.start(); } // Give all threads a chance to start and succeed Thread.sleep(duration); // Stop threads for (final PoolTest pt : pts) { pt.stop(); } /* * Wait for all threads to terminate. This is essential to ensure that all threads have a chance to update success[0] * and to ensure that the variable is published correctly. */ int done = 0; int failed = 0; int didNotRun = 0; int loops = 0; for (final PoolTest poolTest : pts) { poolTest.thread.join(); loops += poolTest.loops; final String state = poolTest.state; if (DONE.equals(state)) { done++; } if (poolTest.loops == 0) { didNotRun++; } final Throwable thrown = poolTest.thrown; if (thrown != null) { failed++; if (!expectError || !(thrown instanceof SQLException)) { System.err.println("Unexpected error: " + thrown.getMessage()); } } } final long timeMillis = timeStampMillis() - startTimeMillis; // @formatter:off println("Multithread test time = " + timeMillis + " ms. Threads: " + pts.length + ". Loops: " + loops + ". Hold time: " + holdDuration + ". maxWaitMillis: " + maxWaitDuration + ". Done: " + done + ". Did not run: " + didNotRun + ". Failed: " + failed + ". expectError: " + expectError); // @formatter:on if (expectError) { if (DISPLAY_THREAD_DETAILS || pts.length / 2 != failed) { final long offset = pts[0].createdMillis - 1000; // To reduce size of output numbers, but ensure they have 4 digits println("Offset: " + offset); for (int i = 0; i < pts.length; i++) { final PoolTest pt = pts[i]; // @formatter:off println("Pre: " + (pt.preconnected-offset) // First, so can sort on this easily + ". Post: " + (pt.postconnected != 0 ? Long.toString(pt.postconnected-offset): "-") + ". Hash: " + pt.connHash + ". Startup: " + (pt.started-pt.createdMillis) + ". getConn(): " + (pt.connected != 0 ? Long.toString(pt.connected-pt.preconnected) : "-") + ". Runtime: " + (pt.ended-pt.started) + ". IDX: " + i + ". Loops: " + pt.loops + ". State: " + pt.state + ". thrown: "+ pt.thrown + "."); // @formatter:on } } if (didNotRun > 0) { println("NOTE: some threads did not run the code: " + didNotRun); } // Perform initial sanity check: assertTrue(failed > 0, "Expected some of the threads to fail"); // Assume that threads that did not run would have timed out. assertEquals(pts.length / 2, failed + didNotRun, "WARNING: Expected half the threads to fail"); } else { assertEquals(0, failed, "Did not expect any threads to fail"); } } /** * Acquires a new connection and push it onto the connections stack. * * @return a new connection. * @throws Exception Defined in subclasses. */ @SuppressWarnings("resource") // Caller closes protected Connection newConnection() throws Exception { return connectionStack.push(getConnection()); } void println(final String string) { if (Boolean.getBoolean(getClass().getSimpleName() + ".debug")) { System.out.println(string); } } @AfterEach public void tearDown() throws Exception { // Close any connections opened by the test while (!connectionStack.isEmpty()) { Utils.closeQuietly((AutoCloseable) connectionStack.pop()); } } @Test public void testAutoCommitBehavior() throws Exception { final Connection conn0 = newConnection(); assertNotNull(conn0, "connection should not be null"); assertTrue(conn0.getAutoCommit(), "autocommit should be true for conn0"); final Connection conn1 = newConnection(); assertTrue(conn1.getAutoCommit(), "autocommit should be true for conn1"); conn1.close(); assertTrue(conn0.getAutoCommit(), "autocommit should be true for conn0"); conn0.setAutoCommit(false); assertFalse(conn0.getAutoCommit(), "autocommit should be false for conn0"); conn0.close(); final Connection conn2 = newConnection(); assertTrue(conn2.getAutoCommit(), "autocommit should be true for conn2"); final Connection conn3 = newConnection(); assertTrue(conn3.getAutoCommit(), "autocommit should be true for conn3"); conn2.close(); conn3.close(); } @Test public void testBackPointers() throws Exception { // normal statement Connection conn = newConnection(); assertBackPointers(conn, conn.createStatement()); conn = newConnection(); assertBackPointers(conn, conn.createStatement(0, 0)); conn = newConnection(); assertBackPointers(conn, conn.createStatement(0, 0, 0)); // prepared statement conn = newConnection(); assertBackPointers(conn, conn.prepareStatement("select * from dual")); conn = newConnection(); assertBackPointers(conn, conn.prepareStatement("select * from dual", 0)); conn = newConnection(); assertBackPointers(conn, conn.prepareStatement("select * from dual", 0, 0)); conn = newConnection(); assertBackPointers(conn, conn.prepareStatement("select * from dual", 0, 0, 0)); conn = newConnection(); assertBackPointers(conn, conn.prepareStatement("select * from dual", new int[0])); conn = newConnection(); assertBackPointers(conn, conn.prepareStatement("select * from dual", new String[0])); // callable statement conn = newConnection(); assertBackPointers(conn, conn.prepareCall("select * from dual")); conn = newConnection(); assertBackPointers(conn, conn.prepareCall("select * from dual", 0, 0)); conn = newConnection(); assertBackPointers(conn, conn.prepareCall("select * from dual", 0, 0, 0)); } @Test public void testCanCloseCallableStatementTwice() throws Exception { try (Connection conn = newConnection()) { assertNotNull(conn); assertFalse(conn.isClosed()); for (int i = 0; i < 2; i++) { // loop to show we *can* close again once we've borrowed it from the pool again final PreparedStatement stmt = conn.prepareCall("select * from dual"); assertNotNull(stmt); assertFalse(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); } } } /** * Verify the close method can be called multiple times on a single connection without * an exception being thrown. */ @Test public void testCanCloseConnectionTwice() throws Exception { for (int i = 0; i < getMaxTotal(); i++) { // loop to show we *can* close again once we've borrowed it from the pool again final Connection conn = newConnection(); assertNotNull(conn); assertFalse(conn.isClosed()); conn.close(); assertTrue(conn.isClosed()); conn.close(); assertTrue(conn.isClosed()); } } @Test public void testCanClosePreparedStatementTwice() throws Exception { try (Connection conn = newConnection()) { assertNotNull(conn); assertFalse(conn.isClosed()); for (int i = 0; i < 2; i++) { // loop to show we *can* close again once we've borrowed it from the pool again final PreparedStatement stmt = conn.prepareStatement("select * from dual"); assertNotNull(stmt); assertFalse(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); } } } @Test public void testCanCloseResultSetTwice() throws Exception { try (Connection conn = newConnection()) { assertNotNull(conn); assertFalse(conn.isClosed()); for (int i = 0; i < 2; i++) { // loop to show we *can* close again once we've borrowed it from the pool again final PreparedStatement stmt = conn.prepareStatement("select * from dual"); assertNotNull(stmt); final ResultSet rset = stmt.executeQuery(); assertNotNull(rset); assertFalse(isClosed(rset)); rset.close(); assertTrue(isClosed(rset)); rset.close(); assertTrue(isClosed(rset)); rset.close(); assertTrue(isClosed(rset)); } } } @Test public void testCanCloseStatementTwice() throws Exception { final Connection conn = newConnection(); assertNotNull(conn); assertFalse(conn.isClosed()); for (int i = 0; i < 2; i++) { // loop to show we *can* close again once we've borrowed it from the pool again final Statement stmt = conn.createStatement(); assertNotNull(stmt); assertFalse(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); stmt.close(); assertTrue(isClosed(stmt)); } conn.close(); } @Test public void testClearWarnings() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = newConnection(); assertNotNull(c[i]); // generate SQLWarning on connection try (CallableStatement cs = c[i].prepareCall("warning")) { // empty } } for (final Connection element : c) { assertNotNull(element.getWarnings()); } for (final Connection element : c) { element.close(); } for (int i = 0; i < c.length; i++) { c[i] = newConnection(); } for (final Connection element : c) { // warnings should have been cleared by putting the connection back in the pool assertNull(element.getWarnings()); } for (final Connection element : c) { element.close(); } } @Test public void testClosing() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; // open the maximum connections for (int i = 0; i < c.length; i++) { c[i] = newConnection(); } // close one of the connections c[0].close(); assertTrue(c[0].isClosed()); // get a new connection c[0] = newConnection(); for (final Connection element : c) { element.close(); } } /** "https://issues.apache.org/bugzilla/show_bug.cgi?id=12400" */ @Test public void testConnectionsAreDistinct() throws Exception { final Connection[] conn = new Connection[getMaxTotal()]; for(int i=0;i hash = new Hashtable<>(); hash.put(con, "test"); assertEquals("test", hash.get(con)); assertTrue(hash.containsKey(con)); assertTrue(hash.contains("test")); hash.clear(); con.close(); } @Test public void testIsClosed() throws Exception { for (int i = 0; i < getMaxTotal(); i++) { @SuppressWarnings("resource") final Connection conn = newConnection(); try { assertNotNull(conn); assertFalse(conn.isClosed()); try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } finally { conn.close(); } assertTrue(conn.isClosed()); } } @Test public void testMaxTotal() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = newConnection(); assertNotNull(c[i]); } // should only be able to open 10 connections, so this test should // throw an exception assertThrows(SQLException.class, this::newConnection); for (final Connection element : c) { element.close(); } } // Bugzilla Bug 24966: NullPointer with Oracle 9 driver // wrong order of passivate/close when a rset isn't closed @Test public void testNoRsetClose() throws Exception { try (Connection conn = newConnection()) { assertNotNull(conn); try (PreparedStatement stmt = conn.prepareStatement("test")) { assertNotNull(stmt); final ResultSet rset = stmt.getResultSet(); assertNotNull(rset); // forget to close the resultset: rset.close(); } } } @Test public void testOpening() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; // test that opening new connections is not closing previous for (int i = 0; i < c.length; i++) { c[i] = newConnection(); assertNotNull(c[i]); for (int j = 0; j <= i; j++) { assertFalse(c[j].isClosed()); } } for (final Connection element : c) { element.close(); } } @Test public void testPooling() throws Exception { // Grab a maximal set of open connections from the pool final Connection[] c = new Connection[getMaxTotal()]; final Connection[] u = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = newConnection(); if (!(c[i] instanceof DelegatingConnection)) { for (int j = 0; j <= i; j++) { c[j].close(); } return; // skip this test } u[i] = ((DelegatingConnection) c[i]).getInnermostDelegate(); } // Close connections one at a time and get new ones, making sure // the new ones come from the pool for (final Connection element : c) { element.close(); try (Connection con = newConnection()) { final Connection underCon = ((DelegatingConnection) con).getInnermostDelegate(); assertNotNull(underCon, "Failed to get connection"); boolean found = false; for (int j = 0; j < c.length; j++) { if (underCon == u[j]) { found = true; break; } } assertTrue(found, "New connection not from pool"); } } } // Bugzilla Bug 24328: PooledConnectionImpl ignores resultsetType // and Concurrency if statement pooling is not enabled // https://issues.apache.org/bugzilla/show_bug.cgi?id=24328 @Test public void testPrepareStatementOptions() throws Exception { try (Connection conn = newConnection()) { assertNotNull(conn); try (PreparedStatement stmt = conn.prepareStatement("select * from dual", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); assertEquals(ResultSet.TYPE_SCROLL_SENSITIVE, rset.getType()); assertEquals(ResultSet.CONCUR_UPDATABLE, rset.getConcurrency()); } } } } @Test public void testRepeatedBorrowAndReturn() throws Exception { for (int i = 0; i < 100; i++) { try (Connection conn = newConnection()) { assertNotNull(conn); try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } } @Test public void testSimple() throws Exception { try (Connection conn = newConnection()) { assertNotNull(conn); try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } @Test public void testSimple2() throws Exception { @SuppressWarnings("resource") final Connection conn = newConnection(); assertNotNull(conn); try { try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } finally { conn.close(); } assertThrows(SQLException.class, conn::createStatement, "Can't use closed connections"); try (Connection conn2 = newConnection()) { assertNotNull(conn2); { try (PreparedStatement stmt = conn2.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } { try (PreparedStatement stmt = conn2.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } } @Test public void testThreaded() { final TestThread[] threads = new TestThread[getMaxTotal()]; for (int i = 0; i < threads.length; i++) { threads[i] = new TestThread(50, 50); final Thread t = new Thread(threads[i]); t.start(); } for (int i = 0; i < threads.length; i++) { while (!threads[i].complete()) { try { Thread.sleep(100L); } catch (final Exception e) { // ignored } } if (threads[i] != null && threads[i].failed()) { fail("Thread failed: " + i); } } } long timeStampMillis() { return System.currentTimeMillis();// JVM 1.5+ System.nanoTime() / 1000000; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestConstants.java000066400000000000000000000031021447311732500321400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import org.junit.jupiter.api.Test; /** * Tests for Constants. */ public class TestConstants { @Test public void testConstants() { assertNotNull(new Constants()); assertEquals(",connectionpool=", Constants.JMX_CONNECTION_POOL_BASE_EXT); assertEquals("connections", Constants.JMX_CONNECTION_POOL_PREFIX); assertEquals(",connectionpool=connections,connection=", Constants.JMX_CONNECTION_BASE_EXT); assertEquals(",connectionpool=connections,connection=", Constants.JMX_STATEMENT_POOL_BASE_EXT); assertEquals(",statementpool=statements", Constants.JMX_STATEMENT_POOL_PREFIX); } } TestDataSourceConnectionFactory.java000066400000000000000000000077531447311732500355270ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.logging.Logger; import javax.sql.DataSource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Test for DataSourceConnectionFactory. */ public class TestDataSourceConnectionFactory { private static class TestDataSource implements DataSource { @Override public Connection getConnection() throws SQLException { return new TesterConnection(null, null); } @Override public Connection getConnection(final String username, final String password) throws SQLException { return new TesterConnection(username, password); } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { return false; } @Override public void setLoginTimeout(final int seconds) throws SQLException { // noop } @Override public void setLogWriter(final PrintWriter out) throws SQLException { // noop } @Override public T unwrap(final Class iface) throws SQLException { return null; } } private DataSource datasource; private DataSourceConnectionFactory factory; @BeforeEach public void setUp() { datasource = new TestDataSource(); factory = new DataSourceConnectionFactory(datasource); } @Test public void testCredentials() throws SQLException { final DataSourceConnectionFactory factory = new DataSourceConnectionFactory(datasource, "foo", "bar"); try (Connection conn = factory.createConnection()) { assertEquals("foo", ((TesterConnection) conn).getUserName()); } } @Test public void testDefaultValues() throws SQLException { try (Connection conn = factory.createConnection()) { assertNull(((TesterConnection) conn).getUserName()); } } @Test public void testEmptyPassword() throws SQLException { final DataSourceConnectionFactory factory = new DataSourceConnectionFactory(datasource, "foo", (char[]) null); try (Connection conn = factory.createConnection()) { assertEquals("foo", ((TesterConnection) conn).getUserName()); } } @Test public void testEmptyUser() throws SQLException { final DataSourceConnectionFactory factory = new DataSourceConnectionFactory(datasource, null, new char[] { 'a' }); try (Connection conn = factory.createConnection()) { assertNull(((TesterConnection) conn).getUserName()); } } } TestDelegatingCallableStatement.java000066400000000000000000001032011447311732500354560ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.SQLException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @SuppressWarnings({ "deprecation", "unchecked", "rawtypes" }) // BigDecimal methods, and casting for mocks public class TestDelegatingCallableStatement { private TesterConnection conn; private DelegatingCallableStatement delegate; private CallableStatement obj; @BeforeEach public void setUp() throws Exception { conn = new TesterConnection("test", "test"); obj = mock(CallableStatement.class); final DelegatingConnection delegatingConnection = new DelegatingConnection<>(conn); delegate = new DelegatingCallableStatement(delegatingConnection, obj); } @Test public void testExecuteQueryReturnsNotNull() throws Exception { final TesterCallableStatement delegateStmt = new TesterCallableStatement(conn,"select * from foo"); obj = new DelegatingCallableStatement(new DelegatingConnection<>(conn), delegateStmt); assertNotNull(obj.executeQuery()); } @Test public void testExecuteQueryReturnsNull() throws Exception { final TesterCallableStatement delegateStmt = new TesterCallableStatement(conn,"null"); obj = new DelegatingCallableStatement(new DelegatingConnection<>(conn), delegateStmt); assertNull(obj.executeQuery()); } @Test public void testGetArrayInteger() throws Exception { try { delegate.getArray(1); } catch (final SQLException e) { } verify(obj, times(1)).getArray(1); } @Test public void testGetArrayString() throws Exception { try { delegate.getArray("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getArray("foo"); } @Test public void testGetBigDecimalInteger() throws Exception { try { delegate.getBigDecimal(1); } catch (final SQLException e) { } verify(obj, times(1)).getBigDecimal(1); } @Test public void testGetBigDecimalIntegerInteger() throws Exception { try { delegate.getBigDecimal(1, 1); } catch (final SQLException e) { } verify(obj, times(1)).getBigDecimal(1, 1); } @Test public void testGetBigDecimalString() throws Exception { try { delegate.getBigDecimal("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getBigDecimal("foo"); } @Test public void testGetBlobInteger() throws Exception { try { delegate.getBlob(1); } catch (final SQLException e) { } verify(obj, times(1)).getBlob(1); } @Test public void testGetBlobString() throws Exception { try { delegate.getBlob("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getBlob("foo"); } @Test public void testGetBooleanInteger() throws Exception { try { delegate.getBoolean(1); } catch (final SQLException e) { } verify(obj, times(1)).getBoolean(1); } @Test public void testGetBooleanString() throws Exception { try { delegate.getBoolean("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getBoolean("foo"); } @Test public void testGetByteInteger() throws Exception { try { delegate.getByte(1); } catch (final SQLException e) { } verify(obj, times(1)).getByte(1); } @Test public void testGetBytesInteger() throws Exception { try { delegate.getBytes(1); } catch (final SQLException e) { } verify(obj, times(1)).getBytes(1); } @Test public void testGetBytesString() throws Exception { try { delegate.getBytes("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getBytes("foo"); } @Test public void testGetByteString() throws Exception { try { delegate.getByte("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getByte("foo"); } @Test public void testGetCharacterStreamInteger() throws Exception { try { delegate.getCharacterStream(1); } catch (final SQLException e) { } verify(obj, times(1)).getCharacterStream(1); } @Test public void testGetCharacterStreamString() throws Exception { try { delegate.getCharacterStream("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getCharacterStream("foo"); } @Test public void testGetClobInteger() throws Exception { try { delegate.getClob(1); } catch (final SQLException e) { } verify(obj, times(1)).getClob(1); } @Test public void testGetClobString() throws Exception { try { delegate.getClob("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getClob("foo"); } @Test public void testGetDateInteger() throws Exception { try { delegate.getDate(1); } catch (final SQLException e) { } verify(obj, times(1)).getDate(1); } @Test public void testGetDateIntegerCalendar() throws Exception { try { delegate.getDate(1, (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).getDate(1, (java.util.Calendar) null); } @Test public void testGetDateString() throws Exception { try { delegate.getDate("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getDate("foo"); } @Test public void testGetDateStringCalendar() throws Exception { try { delegate.getDate("foo", (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).getDate("foo", (java.util.Calendar) null); } @Test public void testGetDelegate() throws Exception { final TesterCallableStatement delegateStmt = new TesterCallableStatement(conn,"select * from foo"); obj = new DelegatingCallableStatement(new DelegatingConnection<>(conn), delegateStmt); assertEquals(delegateStmt,((DelegatingCallableStatement)obj).getDelegate()); } @Test public void testGetDoubleInteger() throws Exception { try { delegate.getDouble(1); } catch (final SQLException e) { } verify(obj, times(1)).getDouble(1); } @Test public void testGetDoubleString() throws Exception { try { delegate.getDouble("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getDouble("foo"); } @Test public void testGetFloatInteger() throws Exception { try { delegate.getFloat(1); } catch (final SQLException e) { } verify(obj, times(1)).getFloat(1); } @Test public void testGetFloatString() throws Exception { try { delegate.getFloat("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getFloat("foo"); } @Test public void testGetIntInteger() throws Exception { try { delegate.getInt(1); } catch (final SQLException e) { } verify(obj, times(1)).getInt(1); } @Test public void testGetIntString() throws Exception { try { delegate.getInt("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getInt("foo"); } @Test public void testGetLongInteger() throws Exception { try { delegate.getLong(1); } catch (final SQLException e) { } verify(obj, times(1)).getLong(1); } @Test public void testGetLongString() throws Exception { try { delegate.getLong("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getLong("foo"); } @Test public void testGetNCharacterStreamInteger() throws Exception { try { delegate.getNCharacterStream(1); } catch (final SQLException e) { } verify(obj, times(1)).getNCharacterStream(1); } @Test public void testGetNCharacterStreamString() throws Exception { try { delegate.getNCharacterStream("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getNCharacterStream("foo"); } @Test public void testGetNClobInteger() throws Exception { try { delegate.getNClob(1); } catch (final SQLException e) { } verify(obj, times(1)).getNClob(1); } @Test public void testGetNClobString() throws Exception { try { delegate.getNClob("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getNClob("foo"); } @Test public void testGetNStringInteger() throws Exception { try { delegate.getNString(1); } catch (final SQLException e) { } verify(obj, times(1)).getNString(1); } @Test public void testGetNStringString() throws Exception { try { delegate.getNString("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getNString("foo"); } @Test public void testGetObjectInteger() throws Exception { try { delegate.getObject(1); } catch (final SQLException e) { } verify(obj, times(1)).getObject(1); } @Test public void testGetObjectIntegerClass() throws Exception { try { delegate.getObject(1, Object.class); } catch (final SQLException e) { } verify(obj, times(1)).getObject(1, Object.class); } @Test public void testGetObjectIntegerMap() throws Exception { try { delegate.getObject(1, (java.util.Map) null); } catch (final SQLException e) { } verify(obj, times(1)).getObject(1, (java.util.Map) null); } @Test public void testGetObjectString() throws Exception { try { delegate.getObject("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getObject("foo"); } @Test public void testGetObjectStringClass() throws Exception { try { delegate.getObject("foo", Object.class); } catch (final SQLException e) { } verify(obj, times(1)).getObject("foo", Object.class); } @Test public void testGetObjectStringMap() throws Exception { try { delegate.getObject("foo", (java.util.Map) null); } catch (final SQLException e) { } verify(obj, times(1)).getObject("foo", (java.util.Map) null); } @Test public void testGetRefInteger() throws Exception { try { delegate.getRef(1); } catch (final SQLException e) { } verify(obj, times(1)).getRef(1); } @Test public void testGetRefString() throws Exception { try { delegate.getRef("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getRef("foo"); } @Test public void testGetRowIdInteger() throws Exception { try { delegate.getRowId(1); } catch (final SQLException e) { } verify(obj, times(1)).getRowId(1); } @Test public void testGetRowIdString() throws Exception { try { delegate.getRowId("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getRowId("foo"); } @Test public void testGetShortInteger() throws Exception { try { delegate.getShort(1); } catch (final SQLException e) { } verify(obj, times(1)).getShort(1); } @Test public void testGetShortString() throws Exception { try { delegate.getShort("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getShort("foo"); } @Test public void testGetSQLXMLInteger() throws Exception { try { delegate.getSQLXML(1); } catch (final SQLException e) { } verify(obj, times(1)).getSQLXML(1); } @Test public void testGetSQLXMLString() throws Exception { try { delegate.getSQLXML("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getSQLXML("foo"); } @Test public void testGetStringInteger() throws Exception { try { delegate.getString(1); } catch (final SQLException e) { } verify(obj, times(1)).getString(1); } @Test public void testGetStringString() throws Exception { try { delegate.getString("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getString("foo"); } @Test public void testGetTimeInteger() throws Exception { try { delegate.getTime(1); } catch (final SQLException e) { } verify(obj, times(1)).getTime(1); } @Test public void testGetTimeIntegerCalendar() throws Exception { try { delegate.getTime(1, (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).getTime(1, (java.util.Calendar) null); } @Test public void testGetTimestampInteger() throws Exception { try { delegate.getTimestamp(1); } catch (final SQLException e) { } verify(obj, times(1)).getTimestamp(1); } @Test public void testGetTimestampIntegerCalendar() throws Exception { try { delegate.getTimestamp(1, (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).getTimestamp(1, (java.util.Calendar) null); } @Test public void testGetTimestampString() throws Exception { try { delegate.getTimestamp("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getTimestamp("foo"); } @Test public void testGetTimestampStringCalendar() throws Exception { try { delegate.getTimestamp("foo", (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).getTimestamp("foo", (java.util.Calendar) null); } @Test public void testGetTimeString() throws Exception { try { delegate.getTime("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getTime("foo"); } @Test public void testGetTimeStringCalendar() throws Exception { try { delegate.getTime("foo", (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).getTime("foo", (java.util.Calendar) null); } @Test public void testGetURLInteger() throws Exception { try { delegate.getURL(1); } catch (final SQLException e) { } verify(obj, times(1)).getURL(1); } @Test public void testGetURLString() throws Exception { try { delegate.getURL("foo"); } catch (final SQLException e) { } verify(obj, times(1)).getURL("foo"); } @Test public void testRegisterOutParameterIntegerInteger() throws Exception { try { delegate.registerOutParameter(1, 1); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter(1, 1); } @Test public void testRegisterOutParameterIntegerIntegerInteger() throws Exception { try { delegate.registerOutParameter(1, 1, 1); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter(1, 1, 1); } @Test public void testRegisterOutParameterIntegerIntegerString() throws Exception { try { delegate.registerOutParameter(1, 1, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter(1, 1, "foo"); } @Test public void testRegisterOutParameterIntegerSQLType() throws Exception { try { delegate.registerOutParameter(1, (java.sql.SQLType) null); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter(1, (java.sql.SQLType) null); } @Test public void testRegisterOutParameterIntegerSQLTypeInteger() throws Exception { try { delegate.registerOutParameter(1, (java.sql.SQLType) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter(1, (java.sql.SQLType) null, 1); } @Test public void testRegisterOutParameterIntegerSQLTypeString() throws Exception { try { delegate.registerOutParameter(1, (java.sql.SQLType) null, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter(1, (java.sql.SQLType) null, "foo"); } @Test public void testRegisterOutParameterStringInteger() throws Exception { try { delegate.registerOutParameter("foo", 1); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter("foo", 1); } @Test public void testRegisterOutParameterStringIntegerInteger() throws Exception { try { delegate.registerOutParameter("foo", 1, 1); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter("foo", 1, 1); } @Test public void testRegisterOutParameterStringIntegerString() throws Exception { try { delegate.registerOutParameter("foo", 1, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter("foo", 1, "foo"); } @Test public void testRegisterOutParameterStringSQLType() throws Exception { try { delegate.registerOutParameter("foo", (java.sql.SQLType) null); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter("foo", (java.sql.SQLType) null); } @Test public void testRegisterOutParameterStringSQLTypeInteger() throws Exception { try { delegate.registerOutParameter("foo", (java.sql.SQLType) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter("foo", (java.sql.SQLType) null, 1); } @Test public void testRegisterOutParameterStringSQLTypeString() throws Exception { try { delegate.registerOutParameter("foo", (java.sql.SQLType) null, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).registerOutParameter("foo", (java.sql.SQLType) null, "foo"); } @Test public void testSetAsciiStreamStringInputStream() throws Exception { try { delegate.setAsciiStream("foo", (java.io.InputStream) null); } catch (final SQLException e) { } verify(obj, times(1)).setAsciiStream("foo", (java.io.InputStream) null); } @Test public void testSetAsciiStreamStringInputStreamInteger() throws Exception { try { delegate.setAsciiStream("foo", (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setAsciiStream("foo", (java.io.InputStream) null, 1); } @Test public void testSetAsciiStreamStringInputStreamLong() throws Exception { try { delegate.setAsciiStream("foo", (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setAsciiStream("foo", (java.io.InputStream) null, 1L); } @Test public void testSetBigDecimalStringBigDecimal() throws Exception { try { delegate.setBigDecimal("foo", java.math.BigDecimal.valueOf(1.0d)); } catch (final SQLException e) { } verify(obj, times(1)).setBigDecimal("foo", java.math.BigDecimal.valueOf(1.0d)); } @Test public void testSetBinaryStreamStringInputStream() throws Exception { try { delegate.setBinaryStream("foo", (java.io.InputStream) null); } catch (final SQLException e) { } verify(obj, times(1)).setBinaryStream("foo", (java.io.InputStream) null); } @Test public void testSetBinaryStreamStringInputStreamInteger() throws Exception { try { delegate.setBinaryStream("foo", (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setBinaryStream("foo", (java.io.InputStream) null, 1); } @Test public void testSetBinaryStreamStringInputStreamLong() throws Exception { try { delegate.setBinaryStream("foo", (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setBinaryStream("foo", (java.io.InputStream) null, 1L); } @Test public void testSetBlobStringBlob() throws Exception { try { delegate.setBlob("foo", (java.sql.Blob) null); } catch (final SQLException e) { } verify(obj, times(1)).setBlob("foo", (java.sql.Blob) null); } @Test public void testSetBlobStringInputStream() throws Exception { try { delegate.setBlob("foo", (java.io.InputStream) null); } catch (final SQLException e) { } verify(obj, times(1)).setBlob("foo", (java.io.InputStream) null); } @Test public void testSetBlobStringInputStreamLong() throws Exception { try { delegate.setBlob("foo", (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setBlob("foo", (java.io.InputStream) null, 1L); } @Test public void testSetBooleanStringBoolean() throws Exception { try { delegate.setBoolean("foo", Boolean.TRUE); } catch (final SQLException e) { } verify(obj, times(1)).setBoolean("foo", Boolean.TRUE); } @Test public void testSetBytesStringByteArray() throws Exception { try { delegate.setBytes("foo", new byte[] { 1 }); } catch (final SQLException e) { } verify(obj, times(1)).setBytes("foo", new byte[] { 1 }); } @Test public void testSetByteStringByte() throws Exception { try { delegate.setByte("foo", (byte) 1); } catch (final SQLException e) { } verify(obj, times(1)).setByte("foo", (byte) 1); } @Test public void testSetCharacterStreamStringReader() throws Exception { try { delegate.setCharacterStream("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setCharacterStream("foo", (java.io.StringReader) null); } @Test public void testSetCharacterStreamStringReaderInteger() throws Exception { try { delegate.setCharacterStream("foo", (java.io.StringReader) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setCharacterStream("foo", (java.io.StringReader) null, 1); } @Test public void testSetCharacterStreamStringReaderLong() throws Exception { try { delegate.setCharacterStream("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setCharacterStream("foo", (java.io.StringReader) null, 1L); } @Test public void testSetClobStringClob() throws Exception { try { delegate.setClob("foo", (java.sql.Clob) null); } catch (final SQLException e) { } verify(obj, times(1)).setClob("foo", (java.sql.Clob) null); } @Test public void testSetClobStringReader() throws Exception { try { delegate.setClob("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setClob("foo", (java.io.StringReader) null); } @Test public void testSetClobStringReaderLong() throws Exception { try { delegate.setClob("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setClob("foo", (java.io.StringReader) null, 1L); } @Test public void testSetDateStringSqlDate() throws Exception { try { delegate.setDate("foo", new java.sql.Date(1529827548745L)); } catch (final SQLException e) { } verify(obj, times(1)).setDate("foo", new java.sql.Date(1529827548745L)); } @Test public void testSetDateStringSqlDateCalendar() throws Exception { try { delegate.setDate("foo", new java.sql.Date(1529827548745L), (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).setDate("foo", new java.sql.Date(1529827548745L), (java.util.Calendar) null); } @Test public void testSetDoubleStringDouble() throws Exception { try { delegate.setDouble("foo", 1.0d); } catch (final SQLException e) { } verify(obj, times(1)).setDouble("foo", 1.0d); } @Test public void testSetFloatStringFloat() throws Exception { try { delegate.setFloat("foo", 1.0f); } catch (final SQLException e) { } verify(obj, times(1)).setFloat("foo", 1.0f); } @Test public void testSetIntStringInteger() throws Exception { try { delegate.setInt("foo", 1); } catch (final SQLException e) { } verify(obj, times(1)).setInt("foo", 1); } @Test public void testSetLongStringLong() throws Exception { try { delegate.setLong("foo", 1L); } catch (final SQLException e) { } verify(obj, times(1)).setLong("foo", 1L); } @Test public void testSetNCharacterStreamStringReader() throws Exception { try { delegate.setNCharacterStream("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setNCharacterStream("foo", (java.io.StringReader) null); } @Test public void testSetNCharacterStreamStringReaderLong() throws Exception { try { delegate.setNCharacterStream("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setNCharacterStream("foo", (java.io.StringReader) null, 1L); } @Test public void testSetNClobStringNClob() throws Exception { try { delegate.setNClob("foo", (java.sql.NClob) null); } catch (final SQLException e) { } verify(obj, times(1)).setNClob("foo", (java.sql.NClob) null); } @Test public void testSetNClobStringReader() throws Exception { try { delegate.setNClob("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setNClob("foo", (java.io.StringReader) null); } @Test public void testSetNClobStringReaderLong() throws Exception { try { delegate.setNClob("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setNClob("foo", (java.io.StringReader) null, 1L); } @Test public void testSetNStringStringString() throws Exception { try { delegate.setNString("foo", "foo"); } catch (final SQLException e) { } verify(obj, times(1)).setNString("foo", "foo"); } @Test public void testSetNullStringInteger() throws Exception { try { delegate.setNull("foo", 1); } catch (final SQLException e) { } verify(obj, times(1)).setNull("foo", 1); } @Test public void testSetNullStringIntegerString() throws Exception { try { delegate.setNull("foo", 1, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).setNull("foo", 1, "foo"); } @Test public void testSetObjectStringObject() throws Exception { try { delegate.setObject("foo", System.err); } catch (final SQLException e) { } verify(obj, times(1)).setObject("foo", System.err); } @Test public void testSetObjectStringObjectInteger() throws Exception { try { delegate.setObject("foo", System.err, 1); } catch (final SQLException e) { } verify(obj, times(1)).setObject("foo", System.err, 1); } @Test public void testSetObjectStringObjectIntegerInteger() throws Exception { try { delegate.setObject("foo", System.err, 1, 1); } catch (final SQLException e) { } verify(obj, times(1)).setObject("foo", System.err, 1, 1); } @Test public void testSetObjectStringObjectSQLType() throws Exception { try { delegate.setObject("foo", System.err, (java.sql.SQLType) null); } catch (final SQLException e) { } verify(obj, times(1)).setObject("foo", System.err, (java.sql.SQLType) null); } @Test public void testSetObjectStringObjectSQLTypeInteger() throws Exception { try { delegate.setObject("foo", System.err, (java.sql.SQLType) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setObject("foo", System.err, (java.sql.SQLType) null, 1); } @Test public void testSetRowIdStringRowId() throws Exception { try { delegate.setRowId("foo", (java.sql.RowId) null); } catch (final SQLException e) { } verify(obj, times(1)).setRowId("foo", (java.sql.RowId) null); } @Test public void testSetShortStringShort() throws Exception { try { delegate.setShort("foo", (short) 1); } catch (final SQLException e) { } verify(obj, times(1)).setShort("foo", (short) 1); } @Test public void testSetSQLXMLStringSQLXML() throws Exception { try { delegate.setSQLXML("foo", (java.sql.SQLXML) null); } catch (final SQLException e) { } verify(obj, times(1)).setSQLXML("foo", (java.sql.SQLXML) null); } @Test public void testSetStringStringString() throws Exception { try { delegate.setString("foo", "foo"); } catch (final SQLException e) { } verify(obj, times(1)).setString("foo", "foo"); } @Test public void testSetTimestampStringTimestamp() throws Exception { try { delegate.setTimestamp("foo", (java.sql.Timestamp) null); } catch (final SQLException e) { } verify(obj, times(1)).setTimestamp("foo", (java.sql.Timestamp) null); } @Test public void testSetTimestampStringTimestampCalendar() throws Exception { try { delegate.setTimestamp("foo", (java.sql.Timestamp) null, (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).setTimestamp("foo", (java.sql.Timestamp) null, (java.util.Calendar) null); } @Test public void testSetTimeStringTime() throws Exception { try { delegate.setTime("foo", (java.sql.Time) null); } catch (final SQLException e) { } verify(obj, times(1)).setTime("foo", (java.sql.Time) null); } @Test public void testSetTimeStringTimeCalendar() throws Exception { try { delegate.setTime("foo", (java.sql.Time) null, (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).setTime("foo", (java.sql.Time) null, (java.util.Calendar) null); } @Test public void testSetURLStringUrl() throws Exception { try { delegate.setURL("foo", (java.net.URL) null); } catch (final SQLException e) { } verify(obj, times(1)).setURL("foo", (java.net.URL) null); } @Test public void testWasNull() throws Exception { try { delegate.wasNull(); } catch (final SQLException e) { } verify(obj, times(1)).wasNull(); } }TestDelegatingConnection.java000066400000000000000000000212731447311732500342010ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** */ public class TestDelegatingConnection { /** * Delegate that doesn't support read-only or auto-commit. * It will merely take the input value of setReadOnly and * setAutoCommit and discard it, to keep false. */ static class NoReadOnlyOrAutoCommitConnection extends TesterConnection { private final boolean readOnly = false; private final boolean autoCommit = false; public NoReadOnlyOrAutoCommitConnection() { super("",""); } @Override public boolean getAutoCommit() { return autoCommit; } @Override public boolean isReadOnly() throws SQLException { return readOnly; } @Override public void setAutoCommit(final boolean autoCommit) { // Do nothing } @Override public void setReadOnly(final boolean readOnly) { // Do nothing } } /** * Delegate that will throw RTE on toString * Used to validate fix for DBCP-241 */ static class RTEGeneratingConnection extends TesterConnection { public RTEGeneratingConnection() { super("",""); } @Override public String toString() { throw new RuntimeException("bang!"); } } private DelegatingConnection delegatingConnection; private Connection connection; private Connection connection2; private TesterStatement testerStatement; private TesterResultSet testerResultSet; @BeforeEach public void setUp() throws Exception { connection = new TesterConnection("test", "test"); connection2 = new TesterConnection("test", "test"); delegatingConnection = new DelegatingConnection<>(connection); testerStatement = new TesterStatement(delegatingConnection); testerResultSet = new TesterResultSet(testerStatement); } @Test public void testAutoCommitCaching() throws SQLException { final Connection con = new NoReadOnlyOrAutoCommitConnection(); final DelegatingConnection delCon = new DelegatingConnection<>(con); delCon.setAutoCommit(true); assertFalse(con.getAutoCommit()); assertFalse(delCon.getAutoCommit()); } @Test public void testCheckOpen() throws Exception { delegatingConnection.checkOpen(); delegatingConnection.close(); try { delegatingConnection.checkOpen(); fail("Expecting SQLException"); } catch (final SQLException ex) { // expected } } /** * Verify fix for DBCP-241 */ @Test public void testCheckOpenNull() throws Exception { try { delegatingConnection.close(); delegatingConnection.checkOpen(); fail("Expecting SQLException"); } catch (final SQLException ex) { assertTrue(ex.getMessage().endsWith("is closed.")); } try { delegatingConnection = new DelegatingConnection<>(null); delegatingConnection.setClosedInternal(true); delegatingConnection.checkOpen(); fail("Expecting SQLException"); } catch (final SQLException ex) { assertTrue(ex.getMessage().endsWith("is null.")); } try { final PoolingConnection pc = new PoolingConnection(connection2); pc.setStatementPool(new GenericKeyedObjectPool<>(pc)); delegatingConnection = new DelegatingConnection<>(pc); pc.close(); delegatingConnection.close(); try (PreparedStatement ps = delegatingConnection.prepareStatement("")){} fail("Expecting SQLException"); } catch (final SQLException ex) { assertTrue(ex.getMessage().endsWith("is closed.")); } try { delegatingConnection = new DelegatingConnection<>(new RTEGeneratingConnection()); delegatingConnection.close(); delegatingConnection.checkOpen(); fail("Expecting SQLException"); } catch (final SQLException ex) { assertTrue(ex.getMessage().endsWith("is closed.")); } } @Test public void testConnectionToString() throws Exception { final String s = delegatingConnection.toString(); assertNotNull(s); assertFalse(s.isEmpty()); } @Test public void testGetDelegate() throws Exception { assertEquals(connection, delegatingConnection.getDelegate()); } @Test public void testIsClosed() throws Exception { delegatingConnection.checkOpen(); assertFalse(delegatingConnection.isClosed()); delegatingConnection.close(); assertTrue(delegatingConnection.isClosed()); } @Test public void testIsClosedNullDelegate() throws Exception { delegatingConnection.checkOpen(); assertFalse(delegatingConnection.isClosed()); delegatingConnection.setDelegate(null); assertTrue(delegatingConnection.isClosed()); } @Test public void testPassivateWithResultSetCloseException() { try { testerResultSet.setSqlExceptionOnClose(true); delegatingConnection.addTrace(testerResultSet); delegatingConnection.passivate(); Assertions.fail("Expected SQLExceptionList"); } catch (final SQLException e) { Assertions.assertTrue(e instanceof SQLExceptionList); Assertions.assertEquals(1, ((SQLExceptionList) e).getCauseList().size()); } finally { testerResultSet.setSqlExceptionOnClose(false); } } @Test public void testPassivateWithResultSetCloseExceptionAndStatementCloseException() { try { testerStatement.setSqlExceptionOnClose(true); testerResultSet.setSqlExceptionOnClose(true); delegatingConnection.addTrace(testerStatement); delegatingConnection.addTrace(testerResultSet); delegatingConnection.passivate(); Assertions.fail("Expected SQLExceptionList"); } catch (final SQLException e) { Assertions.assertTrue(e instanceof SQLExceptionList); Assertions.assertEquals(2, ((SQLExceptionList) e).getCauseList().size()); } finally { testerStatement.setSqlExceptionOnClose(false); testerResultSet.setSqlExceptionOnClose(false); } } @Test public void testPassivateWithStatementCloseException() { try { testerStatement.setSqlExceptionOnClose(true); delegatingConnection.addTrace(testerStatement); delegatingConnection.passivate(); Assertions.fail("Expected SQLExceptionList"); } catch (final SQLException e) { Assertions.assertTrue(e instanceof SQLExceptionList); Assertions.assertEquals(1, ((SQLExceptionList) e).getCauseList().size()); } finally { testerStatement.setSqlExceptionOnClose(false); } } @Test public void testReadOnlyCaching() throws SQLException { final Connection con = new NoReadOnlyOrAutoCommitConnection(); final DelegatingConnection delCon = new DelegatingConnection<>(con); delCon.setReadOnly(true); assertFalse(con.isReadOnly()); assertFalse(delCon.isReadOnly()); } } TestDelegatingDatabaseMetaData.java000066400000000000000000001337001447311732500352060ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Test suite for {@link DelegatingDatabaseMetaData}. */ public class TestDelegatingDatabaseMetaData { private TesterConnection testConn; private DelegatingConnection conn; private DelegatingDatabaseMetaData delegate; private DatabaseMetaData obj; @BeforeEach public void setUp() throws Exception { obj = mock(DatabaseMetaData.class); testConn = new TesterConnection("test", "test"); conn = new DelegatingConnection<>(testConn); delegate = new DelegatingDatabaseMetaData(conn, obj); } @Test public void testAllProceduresAreCallable() throws Exception { try { delegate.allProceduresAreCallable(); } catch (final SQLException e) {} verify(obj, times(1)).allProceduresAreCallable(); } @Test public void testAllTablesAreSelectable() throws Exception { try { delegate.allTablesAreSelectable(); } catch (final SQLException e) {} verify(obj, times(1)).allTablesAreSelectable(); } @Test public void testAutoCommitFailureClosesAllResultSets() throws Exception { try { delegate.autoCommitFailureClosesAllResultSets(); } catch (final SQLException e) {} verify(obj, times(1)).autoCommitFailureClosesAllResultSets(); } @Test public void testCheckOpen() throws Exception { delegate = new DelegatingDatabaseMetaData(conn, conn.getMetaData()); final ResultSet rst = delegate.getSchemas(); assertFalse(rst.isClosed()); conn.close(); assertTrue(rst.isClosed()); } @Test public void testDataDefinitionCausesTransactionCommit() throws Exception { try { delegate.dataDefinitionCausesTransactionCommit(); } catch (final SQLException e) {} verify(obj, times(1)).dataDefinitionCausesTransactionCommit(); } @Test public void testDataDefinitionIgnoredInTransactions() throws Exception { try { delegate.dataDefinitionIgnoredInTransactions(); } catch (final SQLException e) {} verify(obj, times(1)).dataDefinitionIgnoredInTransactions(); } @Test public void testDeletesAreDetectedInteger() throws Exception { try { delegate.deletesAreDetected(1); } catch (final SQLException e) {} verify(obj, times(1)).deletesAreDetected(1); } @Test public void testDoesMaxRowSizeIncludeBlobs() throws Exception { try { delegate.doesMaxRowSizeIncludeBlobs(); } catch (final SQLException e) {} verify(obj, times(1)).doesMaxRowSizeIncludeBlobs(); } @Test public void testGeneratedKeyAlwaysReturned() throws Exception { try { delegate.generatedKeyAlwaysReturned(); } catch (final SQLException e) {} verify(obj, times(1)).generatedKeyAlwaysReturned(); } @Test public void testGetAttributesStringStringStringString() throws Exception { try { delegate.getAttributes("foo","foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getAttributes("foo","foo","foo","foo"); } @Test public void testGetBestRowIdentifierStringStringStringIntegerBoolean() throws Exception { try { delegate.getBestRowIdentifier("foo","foo","foo",1,Boolean.TRUE); } catch (final SQLException e) {} verify(obj, times(1)).getBestRowIdentifier("foo","foo","foo",1,Boolean.TRUE); } @Test public void testGetCatalogs() throws Exception { try { delegate.getCatalogs(); } catch (final SQLException e) {} verify(obj, times(1)).getCatalogs(); } @Test public void testGetCatalogSeparator() throws Exception { try { delegate.getCatalogSeparator(); } catch (final SQLException e) {} verify(obj, times(1)).getCatalogSeparator(); } @Test public void testGetCatalogTerm() throws Exception { try { delegate.getCatalogTerm(); } catch (final SQLException e) {} verify(obj, times(1)).getCatalogTerm(); } @Test public void testGetClientInfoProperties() throws Exception { try { delegate.getClientInfoProperties(); } catch (final SQLException e) {} verify(obj, times(1)).getClientInfoProperties(); } @Test public void testGetColumnPrivilegesStringStringStringString() throws Exception { try { delegate.getColumnPrivileges("foo","foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getColumnPrivileges("foo","foo","foo","foo"); } @Test public void testGetColumnsStringStringStringString() throws Exception { try { delegate.getColumns("foo","foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getColumns("foo","foo","foo","foo"); } /** * This method is a bit special, and doesn't call the method on the wrapped object, * instead returning the connection from the delegate object itself. * @throws Exception */ @Test public void testGetConnection() throws Exception { try { delegate.getConnection(); } catch (final SQLException e) {} verify(obj, times(0)).getConnection(); } @Test public void testGetCrossReferenceStringStringStringStringStringString() throws Exception { try { delegate.getCrossReference("foo","foo","foo","foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getCrossReference("foo","foo","foo","foo","foo","foo"); } @Test public void testGetDatabaseMajorVersion() throws Exception { try { delegate.getDatabaseMajorVersion(); } catch (final SQLException e) {} verify(obj, times(1)).getDatabaseMajorVersion(); } @Test public void testGetDatabaseMinorVersion() throws Exception { try { delegate.getDatabaseMinorVersion(); } catch (final SQLException e) {} verify(obj, times(1)).getDatabaseMinorVersion(); } @Test public void testGetDatabaseProductName() throws Exception { try { delegate.getDatabaseProductName(); } catch (final SQLException e) {} verify(obj, times(1)).getDatabaseProductName(); } @Test public void testGetDatabaseProductVersion() throws Exception { try { delegate.getDatabaseProductVersion(); } catch (final SQLException e) {} verify(obj, times(1)).getDatabaseProductVersion(); } @Test public void testGetDefaultTransactionIsolation() throws Exception { try { delegate.getDefaultTransactionIsolation(); } catch (final SQLException e) {} verify(obj, times(1)).getDefaultTransactionIsolation(); } @Test public void testGetDelegate() throws Exception { assertEquals(obj ,delegate.getDelegate()); } @Test public void testGetDriverMajorVersion() throws Exception { delegate.getDriverMajorVersion(); verify(obj, times(1)).getDriverMajorVersion(); } @Test public void testGetDriverMinorVersion() throws Exception { delegate.getDriverMinorVersion(); verify(obj, times(1)).getDriverMinorVersion(); } @Test public void testGetDriverName() throws Exception { try { delegate.getDriverName(); } catch (final SQLException e) {} verify(obj, times(1)).getDriverName(); } @Test public void testGetDriverVersion() throws Exception { try { delegate.getDriverVersion(); } catch (final SQLException e) {} verify(obj, times(1)).getDriverVersion(); } @Test public void testGetExportedKeysStringStringString() throws Exception { try { delegate.getExportedKeys("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getExportedKeys("foo","foo","foo"); } @Test public void testGetExtraNameCharacters() throws Exception { try { delegate.getExtraNameCharacters(); } catch (final SQLException e) {} verify(obj, times(1)).getExtraNameCharacters(); } @Test public void testGetFunctionColumnsStringStringStringString() throws Exception { try { delegate.getFunctionColumns("foo","foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getFunctionColumns("foo","foo","foo","foo"); } @Test public void testGetFunctionsStringStringString() throws Exception { try { delegate.getFunctions("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getFunctions("foo","foo","foo"); } @Test public void testGetIdentifierQuoteString() throws Exception { try { delegate.getIdentifierQuoteString(); } catch (final SQLException e) {} verify(obj, times(1)).getIdentifierQuoteString(); } @Test public void testGetImportedKeysStringStringString() throws Exception { try { delegate.getImportedKeys("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getImportedKeys("foo","foo","foo"); } @Test public void testGetIndexInfoStringStringStringBooleanBoolean() throws Exception { try { delegate.getIndexInfo("foo","foo","foo",Boolean.TRUE,Boolean.TRUE); } catch (final SQLException e) {} verify(obj, times(1)).getIndexInfo("foo","foo","foo",Boolean.TRUE,Boolean.TRUE); } @Test public void testGetJDBCMajorVersion() throws Exception { try { delegate.getJDBCMajorVersion(); } catch (final SQLException e) {} verify(obj, times(1)).getJDBCMajorVersion(); } @Test public void testGetJDBCMinorVersion() throws Exception { try { delegate.getJDBCMinorVersion(); } catch (final SQLException e) {} verify(obj, times(1)).getJDBCMinorVersion(); } @Test public void testGetMaxBinaryLiteralLength() throws Exception { try { delegate.getMaxBinaryLiteralLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxBinaryLiteralLength(); } @Test public void testGetMaxCatalogNameLength() throws Exception { try { delegate.getMaxCatalogNameLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxCatalogNameLength(); } @Test public void testGetMaxCharLiteralLength() throws Exception { try { delegate.getMaxCharLiteralLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxCharLiteralLength(); } @Test public void testGetMaxColumnNameLength() throws Exception { try { delegate.getMaxColumnNameLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxColumnNameLength(); } @Test public void testGetMaxColumnsInGroupBy() throws Exception { try { delegate.getMaxColumnsInGroupBy(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxColumnsInGroupBy(); } @Test public void testGetMaxColumnsInIndex() throws Exception { try { delegate.getMaxColumnsInIndex(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxColumnsInIndex(); } @Test public void testGetMaxColumnsInOrderBy() throws Exception { try { delegate.getMaxColumnsInOrderBy(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxColumnsInOrderBy(); } @Test public void testGetMaxColumnsInSelect() throws Exception { try { delegate.getMaxColumnsInSelect(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxColumnsInSelect(); } @Test public void testGetMaxColumnsInTable() throws Exception { try { delegate.getMaxColumnsInTable(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxColumnsInTable(); } @Test public void testGetMaxConnections() throws Exception { try { delegate.getMaxConnections(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxConnections(); } @Test public void testGetMaxCursorNameLength() throws Exception { try { delegate.getMaxCursorNameLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxCursorNameLength(); } @Test public void testGetMaxIndexLength() throws Exception { try { delegate.getMaxIndexLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxIndexLength(); } @Test public void testGetMaxLogicalLobSize() throws Exception { try { delegate.getMaxLogicalLobSize(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxLogicalLobSize(); } @Test public void testGetMaxProcedureNameLength() throws Exception { try { delegate.getMaxProcedureNameLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxProcedureNameLength(); } @Test public void testGetMaxRowSize() throws Exception { try { delegate.getMaxRowSize(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxRowSize(); } @Test public void testGetMaxSchemaNameLength() throws Exception { try { delegate.getMaxSchemaNameLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxSchemaNameLength(); } @Test public void testGetMaxStatementLength() throws Exception { try { delegate.getMaxStatementLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxStatementLength(); } @Test public void testGetMaxStatements() throws Exception { try { delegate.getMaxStatements(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxStatements(); } @Test public void testGetMaxTableNameLength() throws Exception { try { delegate.getMaxTableNameLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxTableNameLength(); } @Test public void testGetMaxTablesInSelect() throws Exception { try { delegate.getMaxTablesInSelect(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxTablesInSelect(); } @Test public void testGetMaxUserNameLength() throws Exception { try { delegate.getMaxUserNameLength(); } catch (final SQLException e) {} verify(obj, times(1)).getMaxUserNameLength(); } @Test public void testGetNumericFunctions() throws Exception { try { delegate.getNumericFunctions(); } catch (final SQLException e) {} verify(obj, times(1)).getNumericFunctions(); } @Test public void testGetPrimaryKeysStringStringString() throws Exception { try { delegate.getPrimaryKeys("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getPrimaryKeys("foo","foo","foo"); } @Test public void testGetProcedureColumnsStringStringStringString() throws Exception { try { delegate.getProcedureColumns("foo","foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getProcedureColumns("foo","foo","foo","foo"); } @Test public void testGetProceduresStringStringString() throws Exception { try { delegate.getProcedures("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getProcedures("foo","foo","foo"); } @Test public void testGetProcedureTerm() throws Exception { try { delegate.getProcedureTerm(); } catch (final SQLException e) {} verify(obj, times(1)).getProcedureTerm(); } @Test public void testGetPseudoColumnsStringStringStringString() throws Exception { try { delegate.getPseudoColumns("foo","foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getPseudoColumns("foo","foo","foo","foo"); } @Test public void testGetResultSetHoldability() throws Exception { try { delegate.getResultSetHoldability(); } catch (final SQLException e) {} verify(obj, times(1)).getResultSetHoldability(); } @Test public void testGetRowIdLifetime() throws Exception { try { delegate.getRowIdLifetime(); } catch (final SQLException e) {} verify(obj, times(1)).getRowIdLifetime(); } @Test public void testGetSchemas() throws Exception { try { delegate.getSchemas(); } catch (final SQLException e) {} verify(obj, times(1)).getSchemas(); } @Test public void testGetSchemasStringString() throws Exception { try { delegate.getSchemas("foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getSchemas("foo","foo"); } @Test public void testGetSchemaTerm() throws Exception { try { delegate.getSchemaTerm(); } catch (final SQLException e) {} verify(obj, times(1)).getSchemaTerm(); } @Test public void testGetSearchStringEscape() throws Exception { try { delegate.getSearchStringEscape(); } catch (final SQLException e) {} verify(obj, times(1)).getSearchStringEscape(); } @Test public void testGetSQLKeywords() throws Exception { try { delegate.getSQLKeywords(); } catch (final SQLException e) {} verify(obj, times(1)).getSQLKeywords(); } @Test public void testGetSQLStateType() throws Exception { try { delegate.getSQLStateType(); } catch (final SQLException e) {} verify(obj, times(1)).getSQLStateType(); } @Test public void testGetStringFunctions() throws Exception { try { delegate.getStringFunctions(); } catch (final SQLException e) {} verify(obj, times(1)).getStringFunctions(); } @Test public void testGetSuperTablesStringStringString() throws Exception { try { delegate.getSuperTables("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getSuperTables("foo","foo","foo"); } @Test public void testGetSuperTypesStringStringString() throws Exception { try { delegate.getSuperTypes("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getSuperTypes("foo","foo","foo"); } @Test public void testGetSystemFunctions() throws Exception { try { delegate.getSystemFunctions(); } catch (final SQLException e) {} verify(obj, times(1)).getSystemFunctions(); } @Test public void testGetTablePrivilegesStringStringString() throws Exception { try { delegate.getTablePrivileges("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getTablePrivileges("foo","foo","foo"); } @Test public void testGetTablesStringStringStringStringArray() throws Exception { try { delegate.getTables("foo","foo","foo",(String[]) null); } catch (final SQLException e) {} verify(obj, times(1)).getTables("foo","foo","foo",(String[]) null); } @Test public void testGetTableTypes() throws Exception { try { delegate.getTableTypes(); } catch (final SQLException e) {} verify(obj, times(1)).getTableTypes(); } @Test public void testGetTimeDateFunctions() throws Exception { try { delegate.getTimeDateFunctions(); } catch (final SQLException e) {} verify(obj, times(1)).getTimeDateFunctions(); } @Test public void testGetTypeInfo() throws Exception { try { delegate.getTypeInfo(); } catch (final SQLException e) {} verify(obj, times(1)).getTypeInfo(); } @Test public void testGetUDTsStringStringStringIntegerArray() throws Exception { try { delegate.getUDTs("foo","foo","foo",(int[]) null); } catch (final SQLException e) {} verify(obj, times(1)).getUDTs("foo","foo","foo",(int[]) null); } @Test public void testGetURL() throws Exception { try { delegate.getURL(); } catch (final SQLException e) {} verify(obj, times(1)).getURL(); } @Test public void testGetUserName() throws Exception { try { delegate.getUserName(); } catch (final SQLException e) {} verify(obj, times(1)).getUserName(); } @Test public void testGetVersionColumnsStringStringString() throws Exception { try { delegate.getVersionColumns("foo","foo","foo"); } catch (final SQLException e) {} verify(obj, times(1)).getVersionColumns("foo","foo","foo"); } @Test public void testInsertsAreDetectedInteger() throws Exception { try { delegate.insertsAreDetected(1); } catch (final SQLException e) {} verify(obj, times(1)).insertsAreDetected(1); } @Test public void testIsCatalogAtStart() throws Exception { try { delegate.isCatalogAtStart(); } catch (final SQLException e) {} verify(obj, times(1)).isCatalogAtStart(); } @Test public void testIsReadOnly() throws Exception { try { delegate.isReadOnly(); } catch (final SQLException e) {} verify(obj, times(1)).isReadOnly(); } @Test public void testLocatorsUpdateCopy() throws Exception { try { delegate.locatorsUpdateCopy(); } catch (final SQLException e) {} verify(obj, times(1)).locatorsUpdateCopy(); } @Test public void testNullPlusNonNullIsNull() throws Exception { try { delegate.nullPlusNonNullIsNull(); } catch (final SQLException e) {} verify(obj, times(1)).nullPlusNonNullIsNull(); } @Test public void testNullsAreSortedAtEnd() throws Exception { try { delegate.nullsAreSortedAtEnd(); } catch (final SQLException e) {} verify(obj, times(1)).nullsAreSortedAtEnd(); } @Test public void testNullsAreSortedAtStart() throws Exception { try { delegate.nullsAreSortedAtStart(); } catch (final SQLException e) {} verify(obj, times(1)).nullsAreSortedAtStart(); } @Test public void testNullsAreSortedHigh() throws Exception { try { delegate.nullsAreSortedHigh(); } catch (final SQLException e) {} verify(obj, times(1)).nullsAreSortedHigh(); } @Test public void testNullsAreSortedLow() throws Exception { try { delegate.nullsAreSortedLow(); } catch (final SQLException e) {} verify(obj, times(1)).nullsAreSortedLow(); } @Test public void testOthersDeletesAreVisibleInteger() throws Exception { try { delegate.othersDeletesAreVisible(1); } catch (final SQLException e) {} verify(obj, times(1)).othersDeletesAreVisible(1); } @Test public void testOthersInsertsAreVisibleInteger() throws Exception { try { delegate.othersInsertsAreVisible(1); } catch (final SQLException e) {} verify(obj, times(1)).othersInsertsAreVisible(1); } @Test public void testOthersUpdatesAreVisibleInteger() throws Exception { try { delegate.othersUpdatesAreVisible(1); } catch (final SQLException e) {} verify(obj, times(1)).othersUpdatesAreVisible(1); } @Test public void testOwnDeletesAreVisibleInteger() throws Exception { try { delegate.ownDeletesAreVisible(1); } catch (final SQLException e) {} verify(obj, times(1)).ownDeletesAreVisible(1); } @Test public void testOwnInsertsAreVisibleInteger() throws Exception { try { delegate.ownInsertsAreVisible(1); } catch (final SQLException e) {} verify(obj, times(1)).ownInsertsAreVisible(1); } @Test public void testOwnUpdatesAreVisibleInteger() throws Exception { try { delegate.ownUpdatesAreVisible(1); } catch (final SQLException e) {} verify(obj, times(1)).ownUpdatesAreVisible(1); } @Test public void testStoresLowerCaseIdentifiers() throws Exception { try { delegate.storesLowerCaseIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).storesLowerCaseIdentifiers(); } @Test public void testStoresLowerCaseQuotedIdentifiers() throws Exception { try { delegate.storesLowerCaseQuotedIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).storesLowerCaseQuotedIdentifiers(); } @Test public void testStoresMixedCaseIdentifiers() throws Exception { try { delegate.storesMixedCaseIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).storesMixedCaseIdentifiers(); } @Test public void testStoresMixedCaseQuotedIdentifiers() throws Exception { try { delegate.storesMixedCaseQuotedIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).storesMixedCaseQuotedIdentifiers(); } @Test public void testStoresUpperCaseIdentifiers() throws Exception { try { delegate.storesUpperCaseIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).storesUpperCaseIdentifiers(); } @Test public void testStoresUpperCaseQuotedIdentifiers() throws Exception { try { delegate.storesUpperCaseQuotedIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).storesUpperCaseQuotedIdentifiers(); } @Test public void testSupportsAlterTableWithAddColumn() throws Exception { try { delegate.supportsAlterTableWithAddColumn(); } catch (final SQLException e) {} verify(obj, times(1)).supportsAlterTableWithAddColumn(); } @Test public void testSupportsAlterTableWithDropColumn() throws Exception { try { delegate.supportsAlterTableWithDropColumn(); } catch (final SQLException e) {} verify(obj, times(1)).supportsAlterTableWithDropColumn(); } @Test public void testSupportsANSI92EntryLevelSQL() throws Exception { try { delegate.supportsANSI92EntryLevelSQL(); } catch (final SQLException e) {} verify(obj, times(1)).supportsANSI92EntryLevelSQL(); } @Test public void testSupportsANSI92FullSQL() throws Exception { try { delegate.supportsANSI92FullSQL(); } catch (final SQLException e) {} verify(obj, times(1)).supportsANSI92FullSQL(); } @Test public void testSupportsANSI92IntermediateSQL() throws Exception { try { delegate.supportsANSI92IntermediateSQL(); } catch (final SQLException e) {} verify(obj, times(1)).supportsANSI92IntermediateSQL(); } @Test public void testSupportsBatchUpdates() throws Exception { try { delegate.supportsBatchUpdates(); } catch (final SQLException e) {} verify(obj, times(1)).supportsBatchUpdates(); } @Test public void testSupportsCatalogsInDataManipulation() throws Exception { try { delegate.supportsCatalogsInDataManipulation(); } catch (final SQLException e) {} verify(obj, times(1)).supportsCatalogsInDataManipulation(); } @Test public void testSupportsCatalogsInIndexDefinitions() throws Exception { try { delegate.supportsCatalogsInIndexDefinitions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsCatalogsInIndexDefinitions(); } @Test public void testSupportsCatalogsInPrivilegeDefinitions() throws Exception { try { delegate.supportsCatalogsInPrivilegeDefinitions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsCatalogsInPrivilegeDefinitions(); } @Test public void testSupportsCatalogsInProcedureCalls() throws Exception { try { delegate.supportsCatalogsInProcedureCalls(); } catch (final SQLException e) {} verify(obj, times(1)).supportsCatalogsInProcedureCalls(); } @Test public void testSupportsCatalogsInTableDefinitions() throws Exception { try { delegate.supportsCatalogsInTableDefinitions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsCatalogsInTableDefinitions(); } @Test public void testSupportsColumnAliasing() throws Exception { try { delegate.supportsColumnAliasing(); } catch (final SQLException e) {} verify(obj, times(1)).supportsColumnAliasing(); } @Test public void testSupportsConvert() throws Exception { try { delegate.supportsConvert(); } catch (final SQLException e) {} verify(obj, times(1)).supportsConvert(); } @Test public void testSupportsConvertIntegerInteger() throws Exception { try { delegate.supportsConvert(1,1); } catch (final SQLException e) {} verify(obj, times(1)).supportsConvert(1,1); } @Test public void testSupportsCoreSQLGrammar() throws Exception { try { delegate.supportsCoreSQLGrammar(); } catch (final SQLException e) {} verify(obj, times(1)).supportsCoreSQLGrammar(); } @Test public void testSupportsCorrelatedSubqueries() throws Exception { try { delegate.supportsCorrelatedSubqueries(); } catch (final SQLException e) {} verify(obj, times(1)).supportsCorrelatedSubqueries(); } @Test public void testSupportsDataDefinitionAndDataManipulationTransactions() throws Exception { try { delegate.supportsDataDefinitionAndDataManipulationTransactions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsDataDefinitionAndDataManipulationTransactions(); } @Test public void testSupportsDataManipulationTransactionsOnly() throws Exception { try { delegate.supportsDataManipulationTransactionsOnly(); } catch (final SQLException e) {} verify(obj, times(1)).supportsDataManipulationTransactionsOnly(); } @Test public void testSupportsDifferentTableCorrelationNames() throws Exception { try { delegate.supportsDifferentTableCorrelationNames(); } catch (final SQLException e) {} verify(obj, times(1)).supportsDifferentTableCorrelationNames(); } @Test public void testSupportsExpressionsInOrderBy() throws Exception { try { delegate.supportsExpressionsInOrderBy(); } catch (final SQLException e) {} verify(obj, times(1)).supportsExpressionsInOrderBy(); } @Test public void testSupportsExtendedSQLGrammar() throws Exception { try { delegate.supportsExtendedSQLGrammar(); } catch (final SQLException e) {} verify(obj, times(1)).supportsExtendedSQLGrammar(); } @Test public void testSupportsFullOuterJoins() throws Exception { try { delegate.supportsFullOuterJoins(); } catch (final SQLException e) {} verify(obj, times(1)).supportsFullOuterJoins(); } @Test public void testSupportsGetGeneratedKeys() throws Exception { try { delegate.supportsGetGeneratedKeys(); } catch (final SQLException e) {} verify(obj, times(1)).supportsGetGeneratedKeys(); } @Test public void testSupportsGroupBy() throws Exception { try { delegate.supportsGroupBy(); } catch (final SQLException e) {} verify(obj, times(1)).supportsGroupBy(); } @Test public void testSupportsGroupByBeyondSelect() throws Exception { try { delegate.supportsGroupByBeyondSelect(); } catch (final SQLException e) {} verify(obj, times(1)).supportsGroupByBeyondSelect(); } @Test public void testSupportsGroupByUnrelated() throws Exception { try { delegate.supportsGroupByUnrelated(); } catch (final SQLException e) {} verify(obj, times(1)).supportsGroupByUnrelated(); } @Test public void testSupportsIntegrityEnhancementFacility() throws Exception { try { delegate.supportsIntegrityEnhancementFacility(); } catch (final SQLException e) {} verify(obj, times(1)).supportsIntegrityEnhancementFacility(); } @Test public void testSupportsLikeEscapeClause() throws Exception { try { delegate.supportsLikeEscapeClause(); } catch (final SQLException e) {} verify(obj, times(1)).supportsLikeEscapeClause(); } @Test public void testSupportsLimitedOuterJoins() throws Exception { try { delegate.supportsLimitedOuterJoins(); } catch (final SQLException e) {} verify(obj, times(1)).supportsLimitedOuterJoins(); } @Test public void testSupportsMinimumSQLGrammar() throws Exception { try { delegate.supportsMinimumSQLGrammar(); } catch (final SQLException e) {} verify(obj, times(1)).supportsMinimumSQLGrammar(); } @Test public void testSupportsMixedCaseIdentifiers() throws Exception { try { delegate.supportsMixedCaseIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).supportsMixedCaseIdentifiers(); } @Test public void testSupportsMixedCaseQuotedIdentifiers() throws Exception { try { delegate.supportsMixedCaseQuotedIdentifiers(); } catch (final SQLException e) {} verify(obj, times(1)).supportsMixedCaseQuotedIdentifiers(); } @Test public void testSupportsMultipleOpenResults() throws Exception { try { delegate.supportsMultipleOpenResults(); } catch (final SQLException e) {} verify(obj, times(1)).supportsMultipleOpenResults(); } @Test public void testSupportsMultipleResultSets() throws Exception { try { delegate.supportsMultipleResultSets(); } catch (final SQLException e) {} verify(obj, times(1)).supportsMultipleResultSets(); } @Test public void testSupportsMultipleTransactions() throws Exception { try { delegate.supportsMultipleTransactions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsMultipleTransactions(); } @Test public void testSupportsNamedParameters() throws Exception { try { delegate.supportsNamedParameters(); } catch (final SQLException e) {} verify(obj, times(1)).supportsNamedParameters(); } @Test public void testSupportsNonNullableColumns() throws Exception { try { delegate.supportsNonNullableColumns(); } catch (final SQLException e) {} verify(obj, times(1)).supportsNonNullableColumns(); } @Test public void testSupportsOpenCursorsAcrossCommit() throws Exception { try { delegate.supportsOpenCursorsAcrossCommit(); } catch (final SQLException e) {} verify(obj, times(1)).supportsOpenCursorsAcrossCommit(); } @Test public void testSupportsOpenCursorsAcrossRollback() throws Exception { try { delegate.supportsOpenCursorsAcrossRollback(); } catch (final SQLException e) {} verify(obj, times(1)).supportsOpenCursorsAcrossRollback(); } @Test public void testSupportsOpenStatementsAcrossCommit() throws Exception { try { delegate.supportsOpenStatementsAcrossCommit(); } catch (final SQLException e) {} verify(obj, times(1)).supportsOpenStatementsAcrossCommit(); } @Test public void testSupportsOpenStatementsAcrossRollback() throws Exception { try { delegate.supportsOpenStatementsAcrossRollback(); } catch (final SQLException e) {} verify(obj, times(1)).supportsOpenStatementsAcrossRollback(); } @Test public void testSupportsOrderByUnrelated() throws Exception { try { delegate.supportsOrderByUnrelated(); } catch (final SQLException e) {} verify(obj, times(1)).supportsOrderByUnrelated(); } @Test public void testSupportsOuterJoins() throws Exception { try { delegate.supportsOuterJoins(); } catch (final SQLException e) {} verify(obj, times(1)).supportsOuterJoins(); } @Test public void testSupportsPositionedDelete() throws Exception { try { delegate.supportsPositionedDelete(); } catch (final SQLException e) {} verify(obj, times(1)).supportsPositionedDelete(); } @Test public void testSupportsPositionedUpdate() throws Exception { try { delegate.supportsPositionedUpdate(); } catch (final SQLException e) {} verify(obj, times(1)).supportsPositionedUpdate(); } @Test public void testSupportsRefCursors() throws Exception { try { delegate.supportsRefCursors(); } catch (final SQLException e) {} verify(obj, times(1)).supportsRefCursors(); } @Test public void testSupportsResultSetConcurrencyIntegerInteger() throws Exception { try { delegate.supportsResultSetConcurrency(1,1); } catch (final SQLException e) {} verify(obj, times(1)).supportsResultSetConcurrency(1,1); } @Test public void testSupportsResultSetHoldabilityInteger() throws Exception { try { delegate.supportsResultSetHoldability(1); } catch (final SQLException e) {} verify(obj, times(1)).supportsResultSetHoldability(1); } @Test public void testSupportsResultSetTypeInteger() throws Exception { try { delegate.supportsResultSetType(1); } catch (final SQLException e) {} verify(obj, times(1)).supportsResultSetType(1); } @Test public void testSupportsSavepoints() throws Exception { try { delegate.supportsSavepoints(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSavepoints(); } @Test public void testSupportsSchemasInDataManipulation() throws Exception { try { delegate.supportsSchemasInDataManipulation(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSchemasInDataManipulation(); } @Test public void testSupportsSchemasInIndexDefinitions() throws Exception { try { delegate.supportsSchemasInIndexDefinitions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSchemasInIndexDefinitions(); } @Test public void testSupportsSchemasInPrivilegeDefinitions() throws Exception { try { delegate.supportsSchemasInPrivilegeDefinitions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSchemasInPrivilegeDefinitions(); } @Test public void testSupportsSchemasInProcedureCalls() throws Exception { try { delegate.supportsSchemasInProcedureCalls(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSchemasInProcedureCalls(); } @Test public void testSupportsSchemasInTableDefinitions() throws Exception { try { delegate.supportsSchemasInTableDefinitions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSchemasInTableDefinitions(); } @Test public void testSupportsSelectForUpdate() throws Exception { try { delegate.supportsSelectForUpdate(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSelectForUpdate(); } @Test public void testSupportsStatementPooling() throws Exception { try { delegate.supportsStatementPooling(); } catch (final SQLException e) {} verify(obj, times(1)).supportsStatementPooling(); } @Test public void testSupportsStoredFunctionsUsingCallSyntax() throws Exception { try { delegate.supportsStoredFunctionsUsingCallSyntax(); } catch (final SQLException e) {} verify(obj, times(1)).supportsStoredFunctionsUsingCallSyntax(); } @Test public void testSupportsStoredProcedures() throws Exception { try { delegate.supportsStoredProcedures(); } catch (final SQLException e) {} verify(obj, times(1)).supportsStoredProcedures(); } @Test public void testSupportsSubqueriesInComparisons() throws Exception { try { delegate.supportsSubqueriesInComparisons(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSubqueriesInComparisons(); } @Test public void testSupportsSubqueriesInExists() throws Exception { try { delegate.supportsSubqueriesInExists(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSubqueriesInExists(); } @Test public void testSupportsSubqueriesInIns() throws Exception { try { delegate.supportsSubqueriesInIns(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSubqueriesInIns(); } @Test public void testSupportsSubqueriesInQuantifieds() throws Exception { try { delegate.supportsSubqueriesInQuantifieds(); } catch (final SQLException e) {} verify(obj, times(1)).supportsSubqueriesInQuantifieds(); } @Test public void testSupportsTableCorrelationNames() throws Exception { try { delegate.supportsTableCorrelationNames(); } catch (final SQLException e) {} verify(obj, times(1)).supportsTableCorrelationNames(); } @Test public void testSupportsTransactionIsolationLevelInteger() throws Exception { try { delegate.supportsTransactionIsolationLevel(1); } catch (final SQLException e) {} verify(obj, times(1)).supportsTransactionIsolationLevel(1); } @Test public void testSupportsTransactions() throws Exception { try { delegate.supportsTransactions(); } catch (final SQLException e) {} verify(obj, times(1)).supportsTransactions(); } @Test public void testSupportsUnion() throws Exception { try { delegate.supportsUnion(); } catch (final SQLException e) {} verify(obj, times(1)).supportsUnion(); } @Test public void testSupportsUnionAll() throws Exception { try { delegate.supportsUnionAll(); } catch (final SQLException e) {} verify(obj, times(1)).supportsUnionAll(); } @Test public void testUpdatesAreDetectedInteger() throws Exception { try { delegate.updatesAreDetected(1); } catch (final SQLException e) {} verify(obj, times(1)).updatesAreDetected(1); } @Test public void testUsesLocalFilePerTable() throws Exception { try { delegate.usesLocalFilePerTable(); } catch (final SQLException e) {} verify(obj, times(1)).usesLocalFilePerTable(); } @Test public void testUsesLocalFiles() throws Exception { try { delegate.usesLocalFiles(); } catch (final SQLException e) {} verify(obj, times(1)).usesLocalFiles(); } @Test public void testWrap() throws SQLException { assertEquals(delegate, delegate.unwrap(DatabaseMetaData.class)); assertEquals(delegate, delegate.unwrap(DelegatingDatabaseMetaData.class)); assertEquals(obj, delegate.unwrap(obj.getClass())); assertNull(delegate.unwrap(String.class)); assertTrue(delegate.isWrapperFor(DatabaseMetaData.class)); assertTrue(delegate.isWrapperFor(DelegatingDatabaseMetaData.class)); assertTrue(delegate.isWrapperFor(obj.getClass())); assertFalse(delegate.isWrapperFor(String.class)); } } TestDelegatingPreparedStatement.java000066400000000000000000000441541447311732500355340ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.sql.PreparedStatement; import java.sql.SQLException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @SuppressWarnings({ "deprecation", "rawtypes" }) // BigDecimal methods, and casting for mocks public class TestDelegatingPreparedStatement { private TesterConnection testerConn; private DelegatingConnection connection; private PreparedStatement obj; private DelegatingPreparedStatement delegate; @BeforeEach public void setUp() throws Exception { testerConn = new TesterConnection("test", "test"); connection = new DelegatingConnection<>(testerConn); obj = mock(PreparedStatement.class); delegate = new DelegatingPreparedStatement(connection, obj); } @Test public void testAddBatch() throws Exception { try { delegate.addBatch(); } catch (final SQLException e) { } verify(obj, times(1)).addBatch(); } @Test public void testClearParameters() throws Exception { try { delegate.clearParameters(); } catch (final SQLException e) { } verify(obj, times(1)).clearParameters(); } @Test public void testExecute() throws Exception { try { delegate.execute(); } catch (final SQLException e) { } verify(obj, times(1)).execute(); } @Test public void testExecuteLargeUpdate() throws Exception { try { delegate.executeLargeUpdate(); } catch (final SQLException e) { } verify(obj, times(1)).executeLargeUpdate(); } @Test public void testExecuteQuery() throws Exception { try { delegate.executeQuery(); } catch (final SQLException e) { } verify(obj, times(1)).executeQuery(); } @Test public void testExecuteQueryReturnsNotNull() throws Exception { obj = new TesterPreparedStatement(testerConn, "select * from foo"); delegate = new DelegatingPreparedStatement(connection, obj); assertNotNull(delegate.executeQuery()); } @Test public void testExecuteQueryReturnsNull() throws Exception { obj = new TesterPreparedStatement(testerConn, "null"); delegate = new DelegatingPreparedStatement(connection, obj); assertNull(delegate.executeQuery()); } @Test public void testExecuteUpdate() throws Exception { try { delegate.executeUpdate(); } catch (final SQLException e) { } verify(obj, times(1)).executeUpdate(); } @Test public void testGetDelegate() throws Exception { obj = new TesterPreparedStatement(testerConn, "select * from foo"); delegate = new DelegatingPreparedStatement(connection, obj); assertEquals(obj, delegate.getDelegate()); } @Test public void testGetMetaData() throws Exception { try { delegate.getMetaData(); } catch (final SQLException e) { } verify(obj, times(1)).getMetaData(); } @Test public void testGetParameterMetaData() throws Exception { try { delegate.getParameterMetaData(); } catch (final SQLException e) { } verify(obj, times(1)).getParameterMetaData(); } @Test public void testSetArrayIntegerArray() throws Exception { try { delegate.setArray(1, (java.sql.Array) null); } catch (final SQLException e) { } verify(obj, times(1)).setArray(1, (java.sql.Array) null); } @Test public void testSetAsciiStreamIntegerInputStream() throws Exception { try { delegate.setAsciiStream(1, (java.io.InputStream) null); } catch (final SQLException e) { } verify(obj, times(1)).setAsciiStream(1, (java.io.InputStream) null); } @Test public void testSetAsciiStreamIntegerInputStreamInteger() throws Exception { try { delegate.setAsciiStream(1, (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setAsciiStream(1, (java.io.InputStream) null, 1); } @Test public void testSetAsciiStreamIntegerInputStreamLong() throws Exception { try { delegate.setAsciiStream(1, (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setAsciiStream(1, (java.io.InputStream) null, 1L); } @Test public void testSetBigDecimalIntegerBigDecimal() throws Exception { try { delegate.setBigDecimal(1, java.math.BigDecimal.valueOf(1.0d)); } catch (final SQLException e) { } verify(obj, times(1)).setBigDecimal(1, java.math.BigDecimal.valueOf(1.0d)); } @Test public void testSetBinaryStreamIntegerInputStream() throws Exception { try { delegate.setBinaryStream(1, (java.io.InputStream) null); } catch (final SQLException e) { } verify(obj, times(1)).setBinaryStream(1, (java.io.InputStream) null); } @Test public void testSetBinaryStreamIntegerInputStreamInteger() throws Exception { try { delegate.setBinaryStream(1, (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setBinaryStream(1, (java.io.InputStream) null, 1); } @Test public void testSetBinaryStreamIntegerInputStreamLong() throws Exception { try { delegate.setBinaryStream(1, (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setBinaryStream(1, (java.io.InputStream) null, 1L); } @Test public void testSetBlobIntegerBlob() throws Exception { try { delegate.setBlob(1, (java.sql.Blob) null); } catch (final SQLException e) { } verify(obj, times(1)).setBlob(1, (java.sql.Blob) null); } @Test public void testSetBlobIntegerInputStream() throws Exception { try { delegate.setBlob(1, (java.io.InputStream) null); } catch (final SQLException e) { } verify(obj, times(1)).setBlob(1, (java.io.InputStream) null); } @Test public void testSetBlobIntegerInputStreamLong() throws Exception { try { delegate.setBlob(1, (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setBlob(1, (java.io.InputStream) null, 1L); } @Test public void testSetBooleanIntegerBoolean() throws Exception { try { delegate.setBoolean(1, Boolean.TRUE); } catch (final SQLException e) { } verify(obj, times(1)).setBoolean(1, Boolean.TRUE); } @Test public void testSetByteIntegerByte() throws Exception { try { delegate.setByte(1, (byte) 1); } catch (final SQLException e) { } verify(obj, times(1)).setByte(1, (byte) 1); } @Test public void testSetBytesIntegerByteArray() throws Exception { try { delegate.setBytes(1, new byte[] { 1 }); } catch (final SQLException e) { } verify(obj, times(1)).setBytes(1, new byte[] { 1 }); } @Test public void testSetCharacterStreamIntegerReader() throws Exception { try { delegate.setCharacterStream(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setCharacterStream(1, (java.io.StringReader) null); } @Test public void testSetCharacterStreamIntegerReaderInteger() throws Exception { try { delegate.setCharacterStream(1, (java.io.StringReader) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setCharacterStream(1, (java.io.StringReader) null, 1); } @Test public void testSetCharacterStreamIntegerReaderLong() throws Exception { try { delegate.setCharacterStream(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setCharacterStream(1, (java.io.StringReader) null, 1L); } @Test public void testSetClobIntegerClob() throws Exception { try { delegate.setClob(1, (java.sql.Clob) null); } catch (final SQLException e) { } verify(obj, times(1)).setClob(1, (java.sql.Clob) null); } @Test public void testSetClobIntegerReader() throws Exception { try { delegate.setClob(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setClob(1, (java.io.StringReader) null); } @Test public void testSetClobIntegerReaderLong() throws Exception { try { delegate.setClob(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setClob(1, (java.io.StringReader) null, 1L); } @Test public void testSetDateIntegerSqlDate() throws Exception { try { delegate.setDate(1, new java.sql.Date(1529827548745L)); } catch (final SQLException e) { } verify(obj, times(1)).setDate(1, new java.sql.Date(1529827548745L)); } @Test public void testSetDateIntegerSqlDateCalendar() throws Exception { try { delegate.setDate(1, new java.sql.Date(1529827548745L), (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).setDate(1, new java.sql.Date(1529827548745L), (java.util.Calendar) null); } @Test public void testSetDoubleIntegerDouble() throws Exception { try { delegate.setDouble(1, 1.0d); } catch (final SQLException e) { } verify(obj, times(1)).setDouble(1, 1.0d); } @Test public void testSetFloatIntegerFloat() throws Exception { try { delegate.setFloat(1, 1.0f); } catch (final SQLException e) { } verify(obj, times(1)).setFloat(1, 1.0f); } @Test public void testSetIntIntegerInteger() throws Exception { try { delegate.setInt(1, 1); } catch (final SQLException e) { } verify(obj, times(1)).setInt(1, 1); } @Test public void testSetLongIntegerLong() throws Exception { try { delegate.setLong(1, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setLong(1, 1L); } @Test public void testSetNCharacterStreamIntegerReader() throws Exception { try { delegate.setNCharacterStream(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setNCharacterStream(1, (java.io.StringReader) null); } @Test public void testSetNCharacterStreamIntegerReaderLong() throws Exception { try { delegate.setNCharacterStream(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setNCharacterStream(1, (java.io.StringReader) null, 1L); } @Test public void testSetNClobIntegerNClob() throws Exception { try { delegate.setNClob(1, (java.sql.NClob) null); } catch (final SQLException e) { } verify(obj, times(1)).setNClob(1, (java.sql.NClob) null); } @Test public void testSetNClobIntegerReader() throws Exception { try { delegate.setNClob(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(obj, times(1)).setNClob(1, (java.io.StringReader) null); } @Test public void testSetNClobIntegerReaderLong() throws Exception { try { delegate.setNClob(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(obj, times(1)).setNClob(1, (java.io.StringReader) null, 1L); } @Test public void testSetNStringIntegerString() throws Exception { try { delegate.setNString(1, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).setNString(1, "foo"); } @Test public void testSetNullIntegerInteger() throws Exception { try { delegate.setNull(1, 1); } catch (final SQLException e) { } verify(obj, times(1)).setNull(1, 1); } @Test public void testSetNullIntegerIntegerString() throws Exception { try { delegate.setNull(1, 1, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).setNull(1, 1, "foo"); } @Test public void testSetObjectIntegerObject() throws Exception { try { delegate.setObject(1, System.err); } catch (final SQLException e) { } verify(obj, times(1)).setObject(1, System.err); } @Test public void testSetObjectIntegerObjectInteger() throws Exception { try { delegate.setObject(1, System.err, 1); } catch (final SQLException e) { } verify(obj, times(1)).setObject(1, System.err, 1); } @Test public void testSetObjectIntegerObjectIntegerInteger() throws Exception { try { delegate.setObject(1, System.err, 1, 1); } catch (final SQLException e) { } verify(obj, times(1)).setObject(1, System.err, 1, 1); } @Test public void testSetObjectIntegerObjectSQLType() throws Exception { try { delegate.setObject(1, System.err, (java.sql.SQLType) null); } catch (final SQLException e) { } verify(obj, times(1)).setObject(1, System.err, (java.sql.SQLType) null); } @Test public void testSetObjectIntegerObjectSQLTypeInteger() throws Exception { try { delegate.setObject(1, System.err, (java.sql.SQLType) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setObject(1, System.err, (java.sql.SQLType) null, 1); } @Test public void testSetRefIntegerRef() throws Exception { try { delegate.setRef(1, (java.sql.Ref) null); } catch (final SQLException e) { } verify(obj, times(1)).setRef(1, (java.sql.Ref) null); } @Test public void testSetRowIdIntegerRowId() throws Exception { try { delegate.setRowId(1, (java.sql.RowId) null); } catch (final SQLException e) { } verify(obj, times(1)).setRowId(1, (java.sql.RowId) null); } @Test public void testSetShortIntegerShort() throws Exception { try { delegate.setShort(1, (short) 1); } catch (final SQLException e) { } verify(obj, times(1)).setShort(1, (short) 1); } @Test public void testSetSQLXMLIntegerSQLXML() throws Exception { try { delegate.setSQLXML(1, (java.sql.SQLXML) null); } catch (final SQLException e) { } verify(obj, times(1)).setSQLXML(1, (java.sql.SQLXML) null); } @Test public void testSetStringIntegerString() throws Exception { try { delegate.setString(1, "foo"); } catch (final SQLException e) { } verify(obj, times(1)).setString(1, "foo"); } @Test public void testSetTimeIntegerTime() throws Exception { try { delegate.setTime(1, (java.sql.Time) null); } catch (final SQLException e) { } verify(obj, times(1)).setTime(1, (java.sql.Time) null); } @Test public void testSetTimeIntegerTimeCalendar() throws Exception { try { delegate.setTime(1, (java.sql.Time) null, (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).setTime(1, (java.sql.Time) null, (java.util.Calendar) null); } @Test public void testSetTimestampIntegerTimestamp() throws Exception { try { delegate.setTimestamp(1, (java.sql.Timestamp) null); } catch (final SQLException e) { } verify(obj, times(1)).setTimestamp(1, (java.sql.Timestamp) null); } @Test public void testSetTimestampIntegerTimestampCalendar() throws Exception { try { delegate.setTimestamp(1, (java.sql.Timestamp) null, (java.util.Calendar) null); } catch (final SQLException e) { } verify(obj, times(1)).setTimestamp(1, (java.sql.Timestamp) null, (java.util.Calendar) null); } @Test public void testSetUnicodeStreamIntegerInputStreamInteger() throws Exception { try { delegate.setUnicodeStream(1, (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(obj, times(1)).setUnicodeStream(1, (java.io.InputStream) null, 1); } @Test public void testSetURLIntegerUrl() throws Exception { try { delegate.setURL(1, (java.net.URL) null); } catch (final SQLException e) { } verify(obj, times(1)).setURL(1, (java.net.URL) null); } } TestDelegatingResultSet.java000066400000000000000000001464371447311732500340460ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; /** * Tests for DelegatingResultSet. */ @SuppressWarnings({ "deprecation", "unchecked", "rawtypes" }) // BigDecimal methods, and casting for mocks public class TestDelegatingResultSet { private TesterConnection testConn; private DelegatingConnection conn; private ResultSet rs; private DelegatingResultSet delegate; @BeforeEach public void setUp() { testConn = new TesterConnection("foo", "bar"); conn = new DelegatingConnection<>(testConn); rs = mock(ResultSet.class); delegate = (DelegatingResultSet) DelegatingResultSet.wrapResultSet(conn, rs); } @Test public void testAbsoluteInteger() throws Exception { try { delegate.absolute(1); } catch (final SQLException e) { } verify(rs, times(1)).absolute(1); } @Test public void testAbsolutes() throws Exception { try { delegate.absolute(1); } catch (final SQLException e) { } verify(rs, times(1)).absolute(1); } @Test public void testAfterLast() throws Exception { try { delegate.afterLast(); } catch (final SQLException e) { } verify(rs, times(1)).afterLast(); } @Test public void testBeforeFirst() throws Exception { try { delegate.beforeFirst(); } catch (final SQLException e) { } verify(rs, times(1)).beforeFirst(); } @Test public void testCancelRowUpdates() throws Exception { try { delegate.cancelRowUpdates(); } catch (final SQLException e) { } verify(rs, times(1)).cancelRowUpdates(); } @Test public void testClearWarnings() throws Exception { try { delegate.clearWarnings(); } catch (final SQLException e) { } verify(rs, times(1)).clearWarnings(); } @Test public void testClose() throws Exception { try { delegate.close(); } catch (final SQLException e) { } verify(rs, times(1)).close(); } @Test public void testDeleteRow() throws Exception { try { delegate.deleteRow(); } catch (final SQLException e) { } verify(rs, times(1)).deleteRow(); } @Test public void testFindColumnString() throws Exception { try { delegate.findColumn("foo"); } catch (final SQLException e) { } verify(rs, times(1)).findColumn("foo"); } @Test public void testFirst() throws Exception { try { delegate.first(); } catch (final SQLException e) { } verify(rs, times(1)).first(); } @Test public void testGetArrayInteger() throws Exception { try { delegate.getArray(1); } catch (final SQLException e) { } verify(rs, times(1)).getArray(1); } @Test public void testGetArrayString() throws Exception { try { delegate.getArray("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getArray("foo"); } @Test public void testGetAsciiStreamInteger() throws Exception { try { delegate.getAsciiStream(1); } catch (final SQLException e) { } verify(rs, times(1)).getAsciiStream(1); } @Test public void testGetAsciiStreamString() throws Exception { try { delegate.getAsciiStream("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getAsciiStream("foo"); } @Test public void testGetBigDecimalInteger() throws Exception { try { delegate.getBigDecimal(1); } catch (final SQLException e) { } verify(rs, times(1)).getBigDecimal(1); } // FIXME: this appears to be a bug @Disabled @Test public void testGetBigDecimalIntegerInteger() throws Exception { try { delegate.getBigDecimal(1, 1); } catch (final SQLException e) { } verify(rs, times(1)).getBigDecimal(1, 1); } @Test public void testGetBigDecimalString() throws Exception { try { delegate.getBigDecimal("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getBigDecimal("foo"); } // FIXME: this appears to be a bug @Disabled @Test public void testGetBigDecimalStringInteger() throws Exception { try { delegate.getBigDecimal("foo", 1); } catch (final SQLException e) { } verify(rs, times(1)).getBigDecimal("foo", 1); } @Test public void testGetBinaryStreamInteger() throws Exception { try { delegate.getBinaryStream(1); } catch (final SQLException e) { } verify(rs, times(1)).getBinaryStream(1); } @Test public void testGetBinaryStreamString() throws Exception { try { delegate.getBinaryStream("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getBinaryStream("foo"); } @Test public void testGetBlobInteger() throws Exception { try { delegate.getBlob(1); } catch (final SQLException e) { } verify(rs, times(1)).getBlob(1); } @Test public void testGetBlobString() throws Exception { try { delegate.getBlob("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getBlob("foo"); } @Test public void testGetBooleanInteger() throws Exception { try { delegate.getBoolean(1); } catch (final SQLException e) { } verify(rs, times(1)).getBoolean(1); } @Test public void testGetBooleanString() throws Exception { try { delegate.getBoolean("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getBoolean("foo"); } @Test public void testGetByteInteger() throws Exception { try { delegate.getByte(1); } catch (final SQLException e) { } verify(rs, times(1)).getByte(1); } @Test public void testGetBytesInteger() throws Exception { try { delegate.getBytes(1); } catch (final SQLException e) { } verify(rs, times(1)).getBytes(1); } @Test public void testGetBytesString() throws Exception { try { delegate.getBytes("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getBytes("foo"); } @Test public void testGetByteString() throws Exception { try { delegate.getByte("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getByte("foo"); } @Test public void testGetCharacterStreamInteger() throws Exception { try { delegate.getCharacterStream(1); } catch (final SQLException e) { } verify(rs, times(1)).getCharacterStream(1); } @Test public void testGetCharacterStreamString() throws Exception { try { delegate.getCharacterStream("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getCharacterStream("foo"); } @Test public void testGetClobInteger() throws Exception { try { delegate.getClob(1); } catch (final SQLException e) { } verify(rs, times(1)).getClob(1); } @Test public void testGetClobString() throws Exception { try { delegate.getClob("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getClob("foo"); } @Test public void testGetConcurrency() throws Exception { try { delegate.getConcurrency(); } catch (final SQLException e) { } verify(rs, times(1)).getConcurrency(); } @Test public void testGetCursorName() throws Exception { try { delegate.getCursorName(); } catch (final SQLException e) { } verify(rs, times(1)).getCursorName(); } @Test public void testGetDateInteger() throws Exception { try { delegate.getDate(1); } catch (final SQLException e) { } verify(rs, times(1)).getDate(1); } @Test public void testGetDateIntegerCalendar() throws Exception { try { delegate.getDate(1, (java.util.Calendar) null); } catch (final SQLException e) { } verify(rs, times(1)).getDate(1, (java.util.Calendar) null); } @Test public void testGetDateString() throws Exception { try { delegate.getDate("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getDate("foo"); } @Test public void testGetDateStringCalendar() throws Exception { try { delegate.getDate("foo", (java.util.Calendar) null); } catch (final SQLException e) { } verify(rs, times(1)).getDate("foo", (java.util.Calendar) null); } @Test public void testGetDoubleInteger() throws Exception { try { delegate.getDouble(1); } catch (final SQLException e) { } verify(rs, times(1)).getDouble(1); } @Test public void testGetDoubleString() throws Exception { try { delegate.getDouble("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getDouble("foo"); } @Test public void testGetFetchDirection() throws Exception { try { delegate.getFetchDirection(); } catch (final SQLException e) { } verify(rs, times(1)).getFetchDirection(); } @Test public void testGetFetchSize() throws Exception { try { delegate.getFetchSize(); } catch (final SQLException e) { } verify(rs, times(1)).getFetchSize(); } @Test public void testGetFloatInteger() throws Exception { try { delegate.getFloat(1); } catch (final SQLException e) { } verify(rs, times(1)).getFloat(1); } @Test public void testGetFloatString() throws Exception { try { delegate.getFloat("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getFloat("foo"); } @Test public void testGetHoldability() throws Exception { try { delegate.getHoldability(); } catch (final SQLException e) { } verify(rs, times(1)).getHoldability(); } @Test public void testGetIntInteger() throws Exception { try { delegate.getInt(1); } catch (final SQLException e) { } verify(rs, times(1)).getInt(1); } @Test public void testGetIntString() throws Exception { try { delegate.getInt("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getInt("foo"); } @Test public void testGetLongInteger() throws Exception { try { delegate.getLong(1); } catch (final SQLException e) { } verify(rs, times(1)).getLong(1); } @Test public void testGetLongString() throws Exception { try { delegate.getLong("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getLong("foo"); } @Test public void testGetMetaData() throws Exception { try { delegate.getMetaData(); } catch (final SQLException e) { } verify(rs, times(1)).getMetaData(); } @Test public void testGetNCharacterStreamInteger() throws Exception { try { delegate.getNCharacterStream(1); } catch (final SQLException e) { } verify(rs, times(1)).getNCharacterStream(1); } @Test public void testGetNCharacterStreamString() throws Exception { try { delegate.getNCharacterStream("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getNCharacterStream("foo"); } @Test public void testGetNClobInteger() throws Exception { try { delegate.getNClob(1); } catch (final SQLException e) { } verify(rs, times(1)).getNClob(1); } @Test public void testGetNClobString() throws Exception { try { delegate.getNClob("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getNClob("foo"); } @Test public void testGetNStringInteger() throws Exception { try { delegate.getNString(1); } catch (final SQLException e) { } verify(rs, times(1)).getNString(1); } @Test public void testGetNStringString() throws Exception { try { delegate.getNString("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getNString("foo"); } @Test public void testGetObjectInteger() throws Exception { try { delegate.getObject(1); } catch (final SQLException e) { } verify(rs, times(1)).getObject(1); } @Test public void testGetObjectIntegerClass() throws Exception { try { delegate.getObject(1, Object.class); } catch (final SQLException e) { } verify(rs, times(1)).getObject(1, Object.class); } @Test public void testGetObjectIntegerMap() throws Exception { try { delegate.getObject(1, (java.util.Map) null); } catch (final SQLException e) { } verify(rs, times(1)).getObject(1, (java.util.Map) null); } @Test public void testGetObjectString() throws Exception { try { delegate.getObject("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getObject("foo"); } @Test public void testGetObjectStringClass() throws Exception { try { delegate.getObject("foo", Object.class); } catch (final SQLException e) { } verify(rs, times(1)).getObject("foo", Object.class); } @Test public void testGetObjectStringMap() throws Exception { try { delegate.getObject("foo", (java.util.Map) null); } catch (final SQLException e) { } verify(rs, times(1)).getObject("foo", (java.util.Map) null); } @Test public void testGetRefInteger() throws Exception { try { delegate.getRef(1); } catch (final SQLException e) { } verify(rs, times(1)).getRef(1); } @Test public void testGetRefString() throws Exception { try { delegate.getRef("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getRef("foo"); } @Test public void testGetRow() throws Exception { try { delegate.getRow(); } catch (final SQLException e) { } verify(rs, times(1)).getRow(); } @Test public void testGetRowIdInteger() throws Exception { try { delegate.getRowId(1); } catch (final SQLException e) { } verify(rs, times(1)).getRowId(1); } @Test public void testGetRowIdString() throws Exception { try { delegate.getRowId("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getRowId("foo"); } @Test public void testGetShortInteger() throws Exception { try { delegate.getShort(1); } catch (final SQLException e) { } verify(rs, times(1)).getShort(1); } @Test public void testGetShortString() throws Exception { try { delegate.getShort("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getShort("foo"); } @Test public void testGetSQLXMLInteger() throws Exception { try { delegate.getSQLXML(1); } catch (final SQLException e) { } verify(rs, times(1)).getSQLXML(1); } @Test public void testGetSQLXMLString() throws Exception { try { delegate.getSQLXML("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getSQLXML("foo"); } /** * This method is a bit special. It actually calls statement in the * {@link DelegatingResultSet} object itself, instead of calling in the * underlying {@link ResultSet}. * * @throws Exception */ @Test public void testGetStatement() throws Exception { try { delegate.getStatement(); } catch (final SQLException e) { } verify(rs, times(0)).getStatement(); } @Test public void testGetStringInteger() throws Exception { try { delegate.getString(1); } catch (final SQLException e) { } verify(rs, times(1)).getString(1); } @Test public void testGetStringString() throws Exception { try { delegate.getString("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getString("foo"); } @Test public void testGetTimeInteger() throws Exception { try { delegate.getTime(1); } catch (final SQLException e) { } verify(rs, times(1)).getTime(1); } @Test public void testGetTimeIntegerCalendar() throws Exception { try { delegate.getTime(1, (java.util.Calendar) null); } catch (final SQLException e) { } verify(rs, times(1)).getTime(1, (java.util.Calendar) null); } @Test public void testGetTimestampInteger() throws Exception { try { delegate.getTimestamp(1); } catch (final SQLException e) { } verify(rs, times(1)).getTimestamp(1); } @Test public void testGetTimestampIntegerCalendar() throws Exception { try { delegate.getTimestamp(1, (java.util.Calendar) null); } catch (final SQLException e) { } verify(rs, times(1)).getTimestamp(1, (java.util.Calendar) null); } @Test public void testGetTimestampString() throws Exception { try { delegate.getTimestamp("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getTimestamp("foo"); } @Test public void testGetTimestampStringCalendar() throws Exception { try { delegate.getTimestamp("foo", (java.util.Calendar) null); } catch (final SQLException e) { } verify(rs, times(1)).getTimestamp("foo", (java.util.Calendar) null); } @Test public void testGetTimeString() throws Exception { try { delegate.getTime("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getTime("foo"); } @Test public void testGetTimeStringCalendar() throws Exception { try { delegate.getTime("foo", (java.util.Calendar) null); } catch (final SQLException e) { } verify(rs, times(1)).getTime("foo", (java.util.Calendar) null); } @Test public void testGetType() throws Exception { try { delegate.getType(); } catch (final SQLException e) { } verify(rs, times(1)).getType(); } @Test public void testGetUnicodeStreamInteger() throws Exception { try { delegate.getUnicodeStream(1); } catch (final SQLException e) { } verify(rs, times(1)).getUnicodeStream(1); } @Test public void testGetUnicodeStreamString() throws Exception { try { delegate.getUnicodeStream("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getUnicodeStream("foo"); } @Test public void testGetURLInteger() throws Exception { try { delegate.getURL(1); } catch (final SQLException e) { } verify(rs, times(1)).getURL(1); } @Test public void testGetURLString() throws Exception { try { delegate.getURL("foo"); } catch (final SQLException e) { } verify(rs, times(1)).getURL("foo"); } @Test public void testGetWarnings() throws Exception { try { delegate.getWarnings(); } catch (final SQLException e) { } verify(rs, times(1)).getWarnings(); } @Test public void testInsertRow() throws Exception { try { delegate.insertRow(); } catch (final SQLException e) { } verify(rs, times(1)).insertRow(); } @Test public void testIsAfterLast() throws Exception { try { delegate.isAfterLast(); } catch (final SQLException e) { } verify(rs, times(1)).isAfterLast(); } @Test public void testIsBeforeFirst() throws Exception { try { delegate.isBeforeFirst(); } catch (final SQLException e) { } verify(rs, times(1)).isBeforeFirst(); } @Test public void testIsClosed() throws Exception { try { delegate.isClosed(); } catch (final SQLException e) { } verify(rs, times(1)).isClosed(); } @Test public void testIsFirst() throws Exception { try { delegate.isFirst(); } catch (final SQLException e) { } verify(rs, times(1)).isFirst(); } @Test public void testIsLast() throws Exception { try { delegate.isLast(); } catch (final SQLException e) { } verify(rs, times(1)).isLast(); } @Test public void testLast() throws Exception { try { delegate.last(); } catch (final SQLException e) { } verify(rs, times(1)).last(); } @Test public void testMoveToCurrentRow() throws Exception { try { delegate.moveToCurrentRow(); } catch (final SQLException e) { } verify(rs, times(1)).moveToCurrentRow(); } @Test public void testMoveToInsertRow() throws Exception { try { delegate.moveToInsertRow(); } catch (final SQLException e) { } verify(rs, times(1)).moveToInsertRow(); } @Test public void testNext() throws Exception { try { delegate.next(); } catch (final SQLException e) { } verify(rs, times(1)).next(); } @Test public void testPrevious() throws Exception { try { delegate.previous(); } catch (final SQLException e) { } verify(rs, times(1)).previous(); } @Test public void testRefreshRow() throws Exception { try { delegate.refreshRow(); } catch (final SQLException e) { } verify(rs, times(1)).refreshRow(); } @Test public void testRelativeInteger() throws Exception { try { delegate.relative(1); } catch (final SQLException e) { } verify(rs, times(1)).relative(1); } @Test public void testRowDeleted() throws Exception { try { delegate.rowDeleted(); } catch (final SQLException e) { } verify(rs, times(1)).rowDeleted(); } @Test public void testRowInserted() throws Exception { try { delegate.rowInserted(); } catch (final SQLException e) { } verify(rs, times(1)).rowInserted(); } @Test public void testRowUpdated() throws Exception { try { delegate.rowUpdated(); } catch (final SQLException e) { } verify(rs, times(1)).rowUpdated(); } @Test public void testSetFetchDirectionInteger() throws Exception { try { delegate.setFetchDirection(1); } catch (final SQLException e) { } verify(rs, times(1)).setFetchDirection(1); } @Test public void testSetFetchSizeInteger() throws Exception { try { delegate.setFetchSize(1); } catch (final SQLException e) { } verify(rs, times(1)).setFetchSize(1); } @Test public void testToString() { final String toString = delegate.toString(); assertTrue(toString.contains("DelegatingResultSet")); assertTrue(toString.contains("Mock for ResultSet")); } @Test public void testUpdateArrayIntegerArray() throws Exception { try { delegate.updateArray(1, (java.sql.Array) null); } catch (final SQLException e) { } verify(rs, times(1)).updateArray(1, (java.sql.Array) null); } @Test public void testUpdateArrayStringArray() throws Exception { try { delegate.updateArray("foo", (java.sql.Array) null); } catch (final SQLException e) { } verify(rs, times(1)).updateArray("foo", (java.sql.Array) null); } @Test public void testUpdateAsciiStreamIntegerInputStream() throws Exception { try { delegate.updateAsciiStream(1, (java.io.InputStream) null); } catch (final SQLException e) { } verify(rs, times(1)).updateAsciiStream(1, (java.io.InputStream) null); } @Test public void testUpdateAsciiStreamIntegerInputStreamInteger() throws Exception { try { delegate.updateAsciiStream(1, (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateAsciiStream(1, (java.io.InputStream) null, 1); } @Test public void testUpdateAsciiStreamIntegerInputStreamLong() throws Exception { try { delegate.updateAsciiStream(1, (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateAsciiStream(1, (java.io.InputStream) null, 1L); } @Test public void testUpdateAsciiStreamStringInputStream() throws Exception { try { delegate.updateAsciiStream("foo", (java.io.InputStream) null); } catch (final SQLException e) { } verify(rs, times(1)).updateAsciiStream("foo", (java.io.InputStream) null); } @Test public void testUpdateAsciiStreamStringInputStreamInteger() throws Exception { try { delegate.updateAsciiStream("foo", (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateAsciiStream("foo", (java.io.InputStream) null, 1); } @Test public void testUpdateAsciiStreamStringInputStreamLong() throws Exception { try { delegate.updateAsciiStream("foo", (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateAsciiStream("foo", (java.io.InputStream) null, 1L); } @Test public void testUpdateBigDecimalIntegerBigDecimal() throws Exception { try { delegate.updateBigDecimal(1, java.math.BigDecimal.valueOf(1.0d)); } catch (final SQLException e) { } verify(rs, times(1)).updateBigDecimal(1, java.math.BigDecimal.valueOf(1.0d)); } @Test public void testUpdateBigDecimalStringBigDecimal() throws Exception { try { delegate.updateBigDecimal("foo", java.math.BigDecimal.valueOf(1.0d)); } catch (final SQLException e) { } verify(rs, times(1)).updateBigDecimal("foo", java.math.BigDecimal.valueOf(1.0d)); } @Test public void testUpdateBinaryStreamIntegerInputStream() throws Exception { try { delegate.updateBinaryStream(1, (java.io.InputStream) null); } catch (final SQLException e) { } verify(rs, times(1)).updateBinaryStream(1, (java.io.InputStream) null); } @Test public void testUpdateBinaryStreamIntegerInputStreamInteger() throws Exception { try { delegate.updateBinaryStream(1, (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateBinaryStream(1, (java.io.InputStream) null, 1); } @Test public void testUpdateBinaryStreamIntegerInputStreamLong() throws Exception { try { delegate.updateBinaryStream(1, (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateBinaryStream(1, (java.io.InputStream) null, 1L); } @Test public void testUpdateBinaryStreamStringInputStream() throws Exception { try { delegate.updateBinaryStream("foo", (java.io.InputStream) null); } catch (final SQLException e) { } verify(rs, times(1)).updateBinaryStream("foo", (java.io.InputStream) null); } @Test public void testUpdateBinaryStreamStringInputStreamInteger() throws Exception { try { delegate.updateBinaryStream("foo", (java.io.InputStream) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateBinaryStream("foo", (java.io.InputStream) null, 1); } @Test public void testUpdateBinaryStreamStringInputStreamLong() throws Exception { try { delegate.updateBinaryStream("foo", (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateBinaryStream("foo", (java.io.InputStream) null, 1L); } @Test public void testUpdateBlobIntegerBlob() throws Exception { try { delegate.updateBlob(1, (java.sql.Blob) null); } catch (final SQLException e) { } verify(rs, times(1)).updateBlob(1, (java.sql.Blob) null); } @Test public void testUpdateBlobIntegerInputStream() throws Exception { try { delegate.updateBlob(1, (java.io.InputStream) null); } catch (final SQLException e) { } verify(rs, times(1)).updateBlob(1, (java.io.InputStream) null); } @Test public void testUpdateBlobIntegerInputStreamLong() throws Exception { try { delegate.updateBlob(1, (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateBlob(1, (java.io.InputStream) null, 1L); } @Test public void testUpdateBlobStringBlob() throws Exception { try { delegate.updateBlob("foo", (java.sql.Blob) null); } catch (final SQLException e) { } verify(rs, times(1)).updateBlob("foo", (java.sql.Blob) null); } @Test public void testUpdateBlobStringInputStream() throws Exception { try { delegate.updateBlob("foo", (java.io.InputStream) null); } catch (final SQLException e) { } verify(rs, times(1)).updateBlob("foo", (java.io.InputStream) null); } @Test public void testUpdateBlobStringInputStreamLong() throws Exception { try { delegate.updateBlob("foo", (java.io.InputStream) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateBlob("foo", (java.io.InputStream) null, 1L); } @Test public void testUpdateBooleanIntegerBoolean() throws Exception { try { delegate.updateBoolean(1, Boolean.TRUE); } catch (final SQLException e) { } verify(rs, times(1)).updateBoolean(1, Boolean.TRUE); } @Test public void testUpdateBooleanStringBoolean() throws Exception { try { delegate.updateBoolean("foo", Boolean.TRUE); } catch (final SQLException e) { } verify(rs, times(1)).updateBoolean("foo", Boolean.TRUE); } @Test public void testUpdateByteIntegerByte() throws Exception { try { delegate.updateByte(1, (byte) 1); } catch (final SQLException e) { } verify(rs, times(1)).updateByte(1, (byte) 1); } @Test public void testUpdateBytesIntegerByteArray() throws Exception { try { delegate.updateBytes(1, new byte[] { 1 }); } catch (final SQLException e) { } verify(rs, times(1)).updateBytes(1, new byte[] { 1 }); } @Test public void testUpdateBytesStringByteArray() throws Exception { try { delegate.updateBytes("foo", new byte[] { 1 }); } catch (final SQLException e) { } verify(rs, times(1)).updateBytes("foo", new byte[] { 1 }); } @Test public void testUpdateByteStringByte() throws Exception { try { delegate.updateByte("foo", (byte) 1); } catch (final SQLException e) { } verify(rs, times(1)).updateByte("foo", (byte) 1); } @Test public void testUpdateCharacterStreamIntegerReader() throws Exception { try { delegate.updateCharacterStream(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateCharacterStream(1, (java.io.StringReader) null); } @Test public void testUpdateCharacterStreamIntegerReaderInteger() throws Exception { try { delegate.updateCharacterStream(1, (java.io.StringReader) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateCharacterStream(1, (java.io.StringReader) null, 1); } @Test public void testUpdateCharacterStreamIntegerReaderLong() throws Exception { try { delegate.updateCharacterStream(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateCharacterStream(1, (java.io.StringReader) null, 1L); } @Test public void testUpdateCharacterStreamStringReader() throws Exception { try { delegate.updateCharacterStream("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateCharacterStream("foo", (java.io.StringReader) null); } @Test public void testUpdateCharacterStreamStringReaderInteger() throws Exception { try { delegate.updateCharacterStream("foo", (java.io.StringReader) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateCharacterStream("foo", (java.io.StringReader) null, 1); } @Test public void testUpdateCharacterStreamStringReaderLong() throws Exception { try { delegate.updateCharacterStream("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateCharacterStream("foo", (java.io.StringReader) null, 1L); } @Test public void testUpdateClobIntegerClob() throws Exception { try { delegate.updateClob(1, (java.sql.Clob) null); } catch (final SQLException e) { } verify(rs, times(1)).updateClob(1, (java.sql.Clob) null); } @Test public void testUpdateClobIntegerReader() throws Exception { try { delegate.updateClob(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateClob(1, (java.io.StringReader) null); } @Test public void testUpdateClobIntegerReaderLong() throws Exception { try { delegate.updateClob(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateClob(1, (java.io.StringReader) null, 1L); } @Test public void testUpdateClobStringClob() throws Exception { try { delegate.updateClob("foo", (java.sql.Clob) null); } catch (final SQLException e) { } verify(rs, times(1)).updateClob("foo", (java.sql.Clob) null); } @Test public void testUpdateClobStringReader() throws Exception { try { delegate.updateClob("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateClob("foo", (java.io.StringReader) null); } @Test public void testUpdateClobStringReaderLong() throws Exception { try { delegate.updateClob("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateClob("foo", (java.io.StringReader) null, 1L); } @Test public void testUpdateDateIntegerSqlDate() throws Exception { try { delegate.updateDate(1, new java.sql.Date(1529827548745L)); } catch (final SQLException e) { } verify(rs, times(1)).updateDate(1, new java.sql.Date(1529827548745L)); } @Test public void testUpdateDateStringSqlDate() throws Exception { try { delegate.updateDate("foo", new java.sql.Date(1529827548745L)); } catch (final SQLException e) { } verify(rs, times(1)).updateDate("foo", new java.sql.Date(1529827548745L)); } @Test public void testUpdateDoubleIntegerDouble() throws Exception { try { delegate.updateDouble(1, 1.0d); } catch (final SQLException e) { } verify(rs, times(1)).updateDouble(1, 1.0d); } @Test public void testUpdateDoubleStringDouble() throws Exception { try { delegate.updateDouble("foo", 1.0d); } catch (final SQLException e) { } verify(rs, times(1)).updateDouble("foo", 1.0d); } @Test public void testUpdateFloatIntegerFloat() throws Exception { try { delegate.updateFloat(1, 1.0f); } catch (final SQLException e) { } verify(rs, times(1)).updateFloat(1, 1.0f); } @Test public void testUpdateFloatStringFloat() throws Exception { try { delegate.updateFloat("foo", 1.0f); } catch (final SQLException e) { } verify(rs, times(1)).updateFloat("foo", 1.0f); } @Test public void testUpdateIntIntegerInteger() throws Exception { try { delegate.updateInt(1, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateInt(1, 1); } @Test public void testUpdateIntStringInteger() throws Exception { try { delegate.updateInt("foo", 1); } catch (final SQLException e) { } verify(rs, times(1)).updateInt("foo", 1); } @Test public void testUpdateLongIntegerLong() throws Exception { try { delegate.updateLong(1, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateLong(1, 1L); } @Test public void testUpdateLongStringLong() throws Exception { try { delegate.updateLong("foo", 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateLong("foo", 1L); } @Test public void testUpdateNCharacterStreamIntegerReader() throws Exception { try { delegate.updateNCharacterStream(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateNCharacterStream(1, (java.io.StringReader) null); } @Test public void testUpdateNCharacterStreamIntegerReaderLong() throws Exception { try { delegate.updateNCharacterStream(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateNCharacterStream(1, (java.io.StringReader) null, 1L); } @Test public void testUpdateNCharacterStreamStringReader() throws Exception { try { delegate.updateNCharacterStream("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateNCharacterStream("foo", (java.io.StringReader) null); } @Test public void testUpdateNCharacterStreamStringReaderLong() throws Exception { try { delegate.updateNCharacterStream("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateNCharacterStream("foo", (java.io.StringReader) null, 1L); } @Test public void testUpdateNClobIntegerNClob() throws Exception { try { delegate.updateNClob(1, (java.sql.NClob) null); } catch (final SQLException e) { } verify(rs, times(1)).updateNClob(1, (java.sql.NClob) null); } @Test public void testUpdateNClobIntegerReader() throws Exception { try { delegate.updateNClob(1, (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateNClob(1, (java.io.StringReader) null); } @Test public void testUpdateNClobIntegerReaderLong() throws Exception { try { delegate.updateNClob(1, (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateNClob(1, (java.io.StringReader) null, 1L); } @Test public void testUpdateNClobStringNClob() throws Exception { try { delegate.updateNClob("foo", (java.sql.NClob) null); } catch (final SQLException e) { } verify(rs, times(1)).updateNClob("foo", (java.sql.NClob) null); } @Test public void testUpdateNClobStringReader() throws Exception { try { delegate.updateNClob("foo", (java.io.StringReader) null); } catch (final SQLException e) { } verify(rs, times(1)).updateNClob("foo", (java.io.StringReader) null); } @Test public void testUpdateNClobStringReaderLong() throws Exception { try { delegate.updateNClob("foo", (java.io.StringReader) null, 1L); } catch (final SQLException e) { } verify(rs, times(1)).updateNClob("foo", (java.io.StringReader) null, 1L); } @Test public void testUpdateNStringIntegerString() throws Exception { try { delegate.updateNString(1, "foo"); } catch (final SQLException e) { } verify(rs, times(1)).updateNString(1, "foo"); } @Test public void testUpdateNStringStringString() throws Exception { try { delegate.updateNString("foo", "foo"); } catch (final SQLException e) { } verify(rs, times(1)).updateNString("foo", "foo"); } @Test public void testUpdateNullInteger() throws Exception { try { delegate.updateNull(1); } catch (final SQLException e) { } verify(rs, times(1)).updateNull(1); } @Test public void testUpdateNullString() throws Exception { try { delegate.updateNull("foo"); } catch (final SQLException e) { } verify(rs, times(1)).updateNull("foo"); } @Test public void testUpdateObjectIntegerObject() throws Exception { try { delegate.updateObject(1, System.err); } catch (final SQLException e) { } verify(rs, times(1)).updateObject(1, System.err); } // FIXME: this appears to be a bug @Disabled @Test public void testUpdateObjectIntegerObjectInteger() throws Exception { try { delegate.updateObject(1, System.err, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateObject(1, System.err, 1); } @Test public void testUpdateObjectIntegerObjectSQLType() throws Exception { try { delegate.updateObject(1, System.err, (java.sql.SQLType) null); } catch (final SQLException e) { } verify(rs, times(1)).updateObject(1, System.err, (java.sql.SQLType) null); } @Test public void testUpdateObjectIntegerObjectSQLTypeInteger() throws Exception { try { delegate.updateObject(1, System.err, (java.sql.SQLType) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateObject(1, System.err, (java.sql.SQLType) null, 1); } @Test public void testUpdateObjectStringObject() throws Exception { try { delegate.updateObject("foo", System.err); } catch (final SQLException e) { } verify(rs, times(1)).updateObject("foo", System.err); } // FIXME this appears to be a bug @Disabled @Test public void testUpdateObjectStringObjectInteger() throws Exception { try { delegate.updateObject("foo", System.err, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateObject("foo", System.err, 1); } @Test public void testUpdateObjectStringObjectSQLType() throws Exception { try { delegate.updateObject("foo", System.err, (java.sql.SQLType) null); } catch (final SQLException e) { } verify(rs, times(1)).updateObject("foo", System.err, (java.sql.SQLType) null); } @Test public void testUpdateObjectStringObjectSQLTypeInteger() throws Exception { try { delegate.updateObject("foo", System.err, (java.sql.SQLType) null, 1); } catch (final SQLException e) { } verify(rs, times(1)).updateObject("foo", System.err, (java.sql.SQLType) null, 1); } @Test public void testUpdateRefIntegerRef() throws Exception { try { delegate.updateRef(1, (java.sql.Ref) null); } catch (final SQLException e) { } verify(rs, times(1)).updateRef(1, (java.sql.Ref) null); } @Test public void testUpdateRefStringRef() throws Exception { try { delegate.updateRef("foo", (java.sql.Ref) null); } catch (final SQLException e) { } verify(rs, times(1)).updateRef("foo", (java.sql.Ref) null); } @Test public void testUpdateRow() throws Exception { try { delegate.updateRow(); } catch (final SQLException e) { } verify(rs, times(1)).updateRow(); } @Test public void testUpdateRowIdIntegerRowId() throws Exception { try { delegate.updateRowId(1, (java.sql.RowId) null); } catch (final SQLException e) { } verify(rs, times(1)).updateRowId(1, (java.sql.RowId) null); } @Test public void testUpdateRowIdStringRowId() throws Exception { try { delegate.updateRowId("foo", (java.sql.RowId) null); } catch (final SQLException e) { } verify(rs, times(1)).updateRowId("foo", (java.sql.RowId) null); } @Test public void testUpdateShortIntegerShort() throws Exception { try { delegate.updateShort(1, (short) 1); } catch (final SQLException e) { } verify(rs, times(1)).updateShort(1, (short) 1); } @Test public void testUpdateShortStringShort() throws Exception { try { delegate.updateShort("foo", (short) 1); } catch (final SQLException e) { } verify(rs, times(1)).updateShort("foo", (short) 1); } @Test public void testUpdateSQLXMLIntegerSQLXML() throws Exception { try { delegate.updateSQLXML(1, (java.sql.SQLXML) null); } catch (final SQLException e) { } verify(rs, times(1)).updateSQLXML(1, (java.sql.SQLXML) null); } @Test public void testUpdateSQLXMLStringSQLXML() throws Exception { try { delegate.updateSQLXML("foo", (java.sql.SQLXML) null); } catch (final SQLException e) { } verify(rs, times(1)).updateSQLXML("foo", (java.sql.SQLXML) null); } @Test public void testUpdateStringIntegerString() throws Exception { try { delegate.updateString(1, "foo"); } catch (final SQLException e) { } verify(rs, times(1)).updateString(1, "foo"); } @Test public void testUpdateStringStringString() throws Exception { try { delegate.updateString("foo", "foo"); } catch (final SQLException e) { } verify(rs, times(1)).updateString("foo", "foo"); } @Test public void testUpdateTimeIntegerTime() throws Exception { try { delegate.updateTime(1, (java.sql.Time) null); } catch (final SQLException e) { } verify(rs, times(1)).updateTime(1, (java.sql.Time) null); } @Test public void testUpdateTimestampIntegerTimestamp() throws Exception { try { delegate.updateTimestamp(1, (java.sql.Timestamp) null); } catch (final SQLException e) { } verify(rs, times(1)).updateTimestamp(1, (java.sql.Timestamp) null); } @Test public void testUpdateTimestampStringTimestamp() throws Exception { try { delegate.updateTimestamp("foo", (java.sql.Timestamp) null); } catch (final SQLException e) { } verify(rs, times(1)).updateTimestamp("foo", (java.sql.Timestamp) null); } @Test public void testUpdateTimeStringTime() throws Exception { try { delegate.updateTime("foo", (java.sql.Time) null); } catch (final SQLException e) { } verify(rs, times(1)).updateTime("foo", (java.sql.Time) null); } @Test public void testWasNull() throws Exception { try { delegate.wasNull(); } catch (final SQLException e) { } verify(rs, times(1)).wasNull(); } @Test public void testWrap() throws SQLException { final DelegatingResultSet delegate = (DelegatingResultSet) DelegatingResultSet.wrapResultSet(conn, rs); assertEquals(delegate, delegate.unwrap(ResultSet.class)); assertEquals(delegate, delegate.unwrap(DelegatingResultSet.class)); assertEquals(rs, delegate.unwrap(rs.getClass())); assertNull(delegate.unwrap(String.class)); assertTrue(delegate.isWrapperFor(ResultSet.class)); assertTrue(delegate.isWrapperFor(DelegatingResultSet.class)); assertTrue(delegate.isWrapperFor(rs.getClass())); assertFalse(delegate.isWrapperFor(String.class)); } } TestDelegatingStatement.java000066400000000000000000000454561447311732500340570ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class TestDelegatingStatement { private static class TesterStatementNonWrapping extends TesterStatement { public TesterStatementNonWrapping(final Connection conn) { super(conn); } @Override public boolean isWrapperFor(final Class iface) throws SQLException { return false; } } private DelegatingConnection delegatingConnection; private TesterConnection testerConnection; private Statement mockedStatement; private DelegatingStatement delegatingStatement; private DelegatingStatement delegatingTesterStatement; private TesterResultSet testerResultSet; private TesterStatement testerStatement; @BeforeEach public void setUp() throws Exception { testerConnection = new TesterConnection("test", "test"); delegatingConnection = new DelegatingConnection<>(testerConnection); mockedStatement = mock(Statement.class); testerStatement = new TesterStatement(testerConnection); delegatingStatement = new DelegatingStatement(delegatingConnection, mockedStatement); delegatingTesterStatement = new DelegatingStatement(delegatingConnection, testerStatement); testerResultSet = new TesterResultSet(mockedStatement); } @Test public void testAddBatchString() throws Exception { try { delegatingStatement.addBatch("foo"); } catch (final SQLException e) { } verify(mockedStatement, times(1)).addBatch("foo"); } @Test public void testCancel() throws Exception { try { delegatingStatement.cancel(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).cancel(); } @Test public void testCheckOpen() throws Exception { delegatingStatement.checkOpen(); delegatingStatement.close(); try { delegatingStatement.checkOpen(); fail("Expecting SQLException"); } catch (final SQLException ex) { // expected } } @Test public void testClearBatch() throws Exception { try { delegatingStatement.clearBatch(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).clearBatch(); } @Test public void testClearWarnings() throws Exception { try { delegatingStatement.clearWarnings(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).clearWarnings(); } @Test public void testClose() throws Exception { try { delegatingStatement.close(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).close(); } @Test public void testCloseOnCompletion() throws Exception { try { delegatingStatement.closeOnCompletion(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).closeOnCompletion(); } @Test public void testCloseWithResultSetCloseException() throws Exception { try { testerResultSet.setSqlExceptionOnClose(true); delegatingStatement.addTrace(testerResultSet); delegatingStatement.close(); Assertions.fail("Excpected a SQLExceptionList"); } catch (final SQLException e) { Assertions.assertTrue(e instanceof SQLExceptionList); } finally { testerResultSet.setSqlExceptionOnClose(false); } verify(mockedStatement, times(1)).close(); } @Test public void testCloseWithStatementCloseException() throws Exception { try { testerStatement.setSqlExceptionOnClose(true); delegatingTesterStatement.close(); Assertions.fail("Excpected a SQLExceptionList"); } catch (final SQLException e) { Assertions.assertTrue(e instanceof SQLExceptionList); } finally { testerStatement.setSqlExceptionOnClose(false); } } @Test public void testExecuteBatch() throws Exception { try { delegatingStatement.executeBatch(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeBatch(); } @Test public void testExecuteLargeBatch() throws Exception { try { delegatingStatement.executeLargeBatch(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeLargeBatch(); } @Test public void testExecuteLargeUpdateString() throws Exception { try { delegatingStatement.executeLargeUpdate("foo"); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeLargeUpdate("foo"); } @Test public void testExecuteLargeUpdateStringInteger() throws Exception { try { delegatingStatement.executeLargeUpdate("foo", 1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeLargeUpdate("foo", 1); } @Test public void testExecuteLargeUpdateStringIntegerArray() throws Exception { try { delegatingStatement.executeLargeUpdate("foo", (int[]) null); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeLargeUpdate("foo", (int[]) null); } @Test public void testExecuteLargeUpdateStringStringArray() throws Exception { try { delegatingStatement.executeLargeUpdate("foo", (String[]) null); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeLargeUpdate("foo", (String[]) null); } @Test public void testExecuteQueryReturnsNull() throws Exception { assertNull(delegatingStatement.executeQuery("null")); } @Test public void testExecuteQueryString() throws Exception { try { delegatingStatement.executeQuery("foo"); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeQuery("foo"); } @Test public void testExecuteString() throws Exception { try { delegatingStatement.execute("foo"); } catch (final SQLException e) { } verify(mockedStatement, times(1)).execute("foo"); } @Test public void testExecuteStringInteger() throws Exception { try { delegatingStatement.execute("foo", 1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).execute("foo", 1); } @Test public void testExecuteStringIntegerArray() throws Exception { try { delegatingStatement.execute("foo", (int[]) null); } catch (final SQLException e) { } verify(mockedStatement, times(1)).execute("foo", (int[]) null); } @Test public void testExecuteStringStringArray() throws Exception { try { delegatingStatement.execute("foo", (String[]) null); } catch (final SQLException e) { } verify(mockedStatement, times(1)).execute("foo", (String[]) null); } @Test public void testExecuteUpdateString() throws Exception { try { delegatingStatement.executeUpdate("foo"); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeUpdate("foo"); } @Test public void testExecuteUpdateStringInteger() throws Exception { try { delegatingStatement.executeUpdate("foo", 1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeUpdate("foo", 1); } @Test public void testExecuteUpdateStringIntegerArray() throws Exception { try { delegatingStatement.executeUpdate("foo", (int[]) null); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeUpdate("foo", (int[]) null); } @Test public void testExecuteUpdateStringStringArray() throws Exception { try { delegatingStatement.executeUpdate("foo", (String[]) null); } catch (final SQLException e) { } verify(mockedStatement, times(1)).executeUpdate("foo", (String[]) null); } /** * This method is a bit special, and return the delegate connection, not the * wrapped statement's connection. * * @throws Exception */ @Test public void testGetConnection() throws Exception { try { delegatingStatement.getConnection(); } catch (final SQLException e) { } verify(mockedStatement, times(0)).getConnection(); } @Test public void testGetDelegate() throws Exception { assertEquals(mockedStatement, delegatingStatement.getDelegate()); } @Test public void testGetFetchDirection() throws Exception { try { delegatingStatement.getFetchDirection(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getFetchDirection(); } @Test public void testGetFetchSize() throws Exception { try { delegatingStatement.getFetchSize(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getFetchSize(); } @Test public void testGetGeneratedKeys() throws Exception { try { delegatingStatement.getGeneratedKeys(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getGeneratedKeys(); } @Test public void testGetLargeMaxRows() throws Exception { try { delegatingStatement.getLargeMaxRows(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getLargeMaxRows(); } @Test public void testGetLargeUpdateCount() throws Exception { try { delegatingStatement.getLargeUpdateCount(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getLargeUpdateCount(); } @Test public void testGetMaxFieldSize() throws Exception { try { delegatingStatement.getMaxFieldSize(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getMaxFieldSize(); } @Test public void testGetMaxRows() throws Exception { try { delegatingStatement.getMaxRows(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getMaxRows(); } @Test public void testGetMoreResults() throws Exception { try { delegatingStatement.getMoreResults(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getMoreResults(); } @Test public void testGetMoreResultsInteger() throws Exception { try { delegatingStatement.getMoreResults(1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getMoreResults(1); } @Test public void testGetQueryTimeout() throws Exception { try { delegatingStatement.getQueryTimeout(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getQueryTimeout(); } @Test public void testGetResultSet() throws Exception { try { delegatingStatement.getResultSet(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getResultSet(); } @Test public void testGetResultSetConcurrency() throws Exception { try { delegatingStatement.getResultSetConcurrency(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getResultSetConcurrency(); } @Test public void testGetResultSetHoldability() throws Exception { try { delegatingStatement.getResultSetHoldability(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getResultSetHoldability(); } @Test public void testGetResultSetType() throws Exception { try { delegatingStatement.getResultSetType(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getResultSetType(); } @Test public void testGetUpdateCount() throws Exception { try { delegatingStatement.getUpdateCount(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getUpdateCount(); } @Test public void testGetWarnings() throws Exception { try { delegatingStatement.getWarnings(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).getWarnings(); } /** * This method is a bit special, and call isClosed in the delegate object * itself, not in the wrapped statement. * * @throws Exception */ @Test public void testIsClosed() throws Exception { try { delegatingStatement.isClosed(); } catch (final SQLException e) { } verify(mockedStatement, times(0)).isClosed(); } @Test public void testIsCloseOnCompletion() throws Exception { try { delegatingStatement.isCloseOnCompletion(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).isCloseOnCompletion(); } @Test public void testIsPoolable() throws Exception { try { delegatingStatement.isPoolable(); } catch (final SQLException e) { } verify(mockedStatement, times(1)).isPoolable(); } @Test public void testIsWrapperFor() throws Exception { final TesterConnection tstConn = new TesterConnection("test", "test"); final TesterStatement tstStmt = new TesterStatementNonWrapping(tstConn); final DelegatingConnection dconn = new DelegatingConnection<>(tstConn); final DelegatingStatement stamt = new DelegatingStatement(dconn, tstStmt); final Class stmtProxyClass = Proxy.getProxyClass( this.getClass().getClassLoader(), Statement.class); assertTrue(stamt.isWrapperFor(DelegatingStatement.class)); assertTrue(stamt.isWrapperFor(TesterStatement.class)); assertFalse(stamt.isWrapperFor(stmtProxyClass)); stamt.close(); } @Test public void testSetCursorNameString() throws Exception { try { delegatingStatement.setCursorName("foo"); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setCursorName("foo"); } @Test public void testSetEscapeProcessingBoolean() throws Exception { try { delegatingStatement.setEscapeProcessing(Boolean.TRUE); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setEscapeProcessing(Boolean.TRUE); } @Test public void testSetFetchDirectionInteger() throws Exception { try { delegatingStatement.setFetchDirection(1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setFetchDirection(1); } @Test public void testSetFetchSizeInteger() throws Exception { try { delegatingStatement.setFetchSize(1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setFetchSize(1); } @Test public void testSetLargeMaxRowsLong() throws Exception { try { delegatingStatement.setLargeMaxRows(1L); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setLargeMaxRows(1L); } @Test public void testSetMaxFieldSizeInteger() throws Exception { try { delegatingStatement.setMaxFieldSize(1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setMaxFieldSize(1); } @Test public void testSetMaxRowsInteger() throws Exception { try { delegatingStatement.setMaxRows(1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setMaxRows(1); } @Test public void testSetPoolableBoolean() throws Exception { try { delegatingStatement.setPoolable(Boolean.TRUE); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setPoolable(Boolean.TRUE); } @Test public void testSetQueryTimeoutInteger() throws Exception { try { delegatingStatement.setQueryTimeout(1); } catch (final SQLException e) { } verify(mockedStatement, times(1)).setQueryTimeout(1); } @Test public void testWrap() throws SQLException { assertEquals(delegatingStatement, delegatingStatement.unwrap(Statement.class)); assertEquals(delegatingStatement, delegatingStatement.unwrap(DelegatingStatement.class)); assertEquals(mockedStatement, delegatingStatement.unwrap(mockedStatement.getClass())); assertNull(delegatingStatement.unwrap(String.class)); assertTrue(delegatingStatement.isWrapperFor(Statement.class)); assertTrue(delegatingStatement.isWrapperFor(DelegatingStatement.class)); assertTrue(delegatingStatement.isWrapperFor(mockedStatement.getClass())); assertFalse(delegatingStatement.isWrapperFor(String.class)); } } TestDriverConnectionFactory.java000066400000000000000000000034571447311732500347250ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Connection; import java.sql.SQLException; import org.junit.jupiter.api.Test; /** * Tests for DriverConnectionFactory. */ public class TestDriverConnectionFactory { @Test public void testCreateConnection() throws SQLException { final DriverConnectionFactory cf = new DriverConnectionFactory( new TesterDriver(), "jdbc:apache:commons:testdriver", null); final Connection conn = cf.createConnection(); assertEquals(0, conn.getMetaData().getDriverMajorVersion()); } @Test public void testDriverConnectionFactoryToString() { final DriverConnectionFactory cf = new DriverConnectionFactory( new TesterDriver(), "jdbc:apache:commons:testdriver", null); final String toString = cf.toString(); assertTrue(toString.contains("jdbc:apache:commons:testdriver")); } } TestDriverManagerConnectionFactory.java000066400000000000000000000156471447311732500362240ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; /** * This test *must* execute before all other tests to be effective as it tests * the initialization of DriverManager. * Based on the test case for DBCP-212 written by Marcos Sanz */ public class TestDriverManagerConnectionFactory { private static final class ConnectionThread implements Runnable { private final DataSource ds; private volatile boolean result = true; private ConnectionThread(final DataSource ds) { this.ds = ds; } public boolean getResult() { return result; } @Override public void run() { Connection conn = null; try { conn = ds.getConnection(); } catch (final Exception e) { e.printStackTrace(); result = false; } finally { if (conn != null) { try { conn.close(); } catch (final Exception e) { e.printStackTrace(); result = false; } } } } @Override public String toString() { return "ConnectionThread [ds=" + ds + ", result=" + result + "]"; } } private static final String KEY_JDBC_DRIVERS = "jdbc.drivers"; @AfterAll public static void afterClass() { System.clearProperty(KEY_JDBC_DRIVERS); } @BeforeAll public static void beforeClass() { System.setProperty(KEY_JDBC_DRIVERS, "org.apache.commons.dbcp2.TesterDriver"); } @Test public void testDriverManagerCredentialsInUrl() throws SQLException { final DriverManagerConnectionFactory cf = new DriverManagerConnectionFactory("jdbc:apache:commons:testdriver;user=foo;password=bar", null, (char[]) null); cf.createConnection(); } public void testDriverManagerInit(final boolean withProperties) throws Exception { final GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(10); config.setMaxIdle(0); final Properties properties = new Properties(); // The names "user" and "password" are specified in java.sql.DriverManager.getConnection(String, String, String) properties.setProperty(Constants.KEY_USER, "foo"); properties.setProperty(Constants.KEY_PASSWORD, "bar"); final ConnectionFactory connectionFactory = withProperties ? new DriverManagerConnectionFactory("jdbc:apache:commons:testdriver", properties) : new DriverManagerConnectionFactory("jdbc:apache:commons:testdriver", "foo", "bar"); final PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null); poolableConnectionFactory.setDefaultReadOnly(Boolean.FALSE); poolableConnectionFactory.setDefaultAutoCommit(Boolean.TRUE); final GenericObjectPool connectionPool = new GenericObjectPool<>(poolableConnectionFactory, config); poolableConnectionFactory.setPool(connectionPool); final PoolingDataSource dataSource = new PoolingDataSource<>(connectionPool); final ConnectionThread[] connectionThreads = new ConnectionThread[10]; final Thread[] threads = new Thread[10]; for (int i = 0; i < 10; i++) { connectionThreads[i] = new ConnectionThread(dataSource); threads[i] = new Thread(connectionThreads[i]); } for (int i = 0; i < 10; i++) { threads[i].start(); } for (int i = 0; i < 10; i++) { while (threads[i].isAlive()){//JDK1.5: getState() != Thread.State.TERMINATED) { Thread.sleep(100); } if (!connectionThreads[i].getResult()) { fail("Exception during getConnection(): " + connectionThreads[i]); } } } @Test public void testDriverManagerInitWithCredentials() throws Exception { testDriverManagerInit(false); } @Test public void testDriverManagerInitWithEmptyProperties() throws Exception { final ConnectionFactory connectionFactory = new DriverManagerConnectionFactory( "jdbc:apache:commons:testdriver;user=foo;password=bar"); connectionFactory.createConnection(); } @Test public void testDriverManagerInitWithProperties() throws Exception { testDriverManagerInit(true); } @Test public void testDriverManagerWithoutCredentials() { final DriverManagerConnectionFactory cf = new DriverManagerConnectionFactory("jdbc:apache:commons:testdriver", null, (char[]) null); assertThrows(ArrayIndexOutOfBoundsException.class, cf::createConnection); // thrown by TestDriver due to missing user } @Test public void testDriverManagerWithoutPassword() { final DriverManagerConnectionFactory cf = new DriverManagerConnectionFactory("jdbc:apache:commons:testdriver", "user", (char[]) null); assertThrows(SQLException.class, cf::createConnection); // thrown by TestDriver due to invalid password } @Test public void testDriverManagerWithoutUser() { final DriverManagerConnectionFactory cf = new DriverManagerConnectionFactory("jdbc:apache:commons:testdriver", null, "pass"); assertThrows(IndexOutOfBoundsException.class, cf::createConnection); // thrown by TestDriver due to missing user } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestJndi.java000066400000000000000000000107661447311732500310660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.fail; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import org.apache.commons.dbcp2.datasources.PerUserPoolDataSource; import org.apache.commons.dbcp2.datasources.SharedPoolDataSource; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests JNID bind and lookup for DataSource implementations. * Demonstrates problem indicated in BZ #38073. */ public class TestJndi { /** * The subcontext where the data source is bound. */ protected static final String JNDI_SUBCONTEXT = "jdbc"; /** * the full JNDI path to the data source. */ protected static final String JNDI_PATH = JNDI_SUBCONTEXT + "/" + "jndiTestDataSource"; /** JNDI context to use in tests **/ protected Context context; /** * Binds a DataSource into JNDI. * * @throws Exception if creation or binding fails. */ protected void bindDataSource(final DataSource dataSource) throws Exception { context.bind(JNDI_PATH, dataSource); } /** * Binds a DataSource to the JNDI and checks that we have successfully * bound it by looking it up again. * * @throws Exception if the bind, lookup or connect fails */ protected void checkBind(final DataSource dataSource) throws Exception { bindDataSource(dataSource); retrieveDataSource(); } /** * Retrieves (or creates if it does not exist) an InitialContext. * * @return the InitialContext. * @throws NamingException if the InitialContext cannot be retrieved * or created. */ protected InitialContext getInitialContext() throws NamingException { final Hashtable environment = new Hashtable<>(); environment.put(Context.INITIAL_CONTEXT_FACTORY, org.apache.naming.java.javaURLContextFactory.class.getName()); return new InitialContext(environment); } /** * Retrieves a DataSource from JNDI. * * @throws Exception if the JNDI lookup fails or no DataSource is bound. */ protected DataSource retrieveDataSource() throws Exception { final Context ctx = getInitialContext(); final DataSource dataSource = (DataSource) ctx.lookup(JNDI_PATH); if (dataSource == null) { fail("DataSource should not be null"); } return dataSource; } @BeforeEach public void setUp() throws Exception { context = getInitialContext(); context.createSubcontext(JNDI_SUBCONTEXT); } @AfterEach public void tearDown() throws Exception { context.unbind(JNDI_PATH); context.destroySubcontext(JNDI_SUBCONTEXT); } /** * Test BasicDatasource bind and lookup * * @throws Exception */ @Test public void testBasicDataSourceBind() throws Exception { final BasicDataSource dataSource = new BasicDataSource(); checkBind(dataSource); } /** * Test PerUserPoolDataSource bind and lookup * * @throws Exception */ @Test public void testPerUserPoolDataSourceBind() throws Exception { final PerUserPoolDataSource dataSource = new PerUserPoolDataSource(); checkBind(dataSource); } /** * Test SharedPoolDataSource bind and lookup * * @throws Exception */ @Test public void testSharedPoolDataSourceBind() throws Exception { final SharedPoolDataSource dataSource = new SharedPoolDataSource(); checkBind(dataSource); } } TestLifetimeExceededException.java000066400000000000000000000027421447311732500351620ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.Test; /** * Tests for LifetimeExceededException. */ public class TestLifetimeExceededException { @Test public void testLifetimeExceededException() { final LifetimeExceededException exception = new LifetimeExceededException("car"); assertEquals("car", exception.getMessage()); } @Test public void testLifetimeExceededExceptionNoMessage() { final LifetimeExceededException exception = new LifetimeExceededException(); assertNull(exception.getMessage()); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestListException.java000066400000000000000000000033531447311732500327660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; /** * Tests for ListException. */ public class TestListException { @Test public void testExceptionList() { final List exceptions = Arrays.asList(new NullPointerException(), new RuntimeException()); final ListException list = new ListException("Internal Error", exceptions); assertEquals("Internal Error", list.getMessage()); assertArrayEquals(exceptions.toArray(), list.getExceptionList().toArray()); } @Test public void testNulls() { final ListException list = new ListException(null, null); assertNull(list.getMessage()); assertNull(list.getExceptionList()); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestPStmtKey.java000066400000000000000000000355141447311732500317200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.ResultSet; import java.sql.Statement; import java.util.Arrays; import org.apache.commons.dbcp2.PoolingConnection.StatementType; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link PStmtKey}. * * @since 2.4.0 */ public class TestPStmtKey { /** * Tests constructors with different catalog. */ @Test public void testCtorDifferentCatalog() { Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1"), new PStmtKey("sql", "catalog2", "schema1")); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0), new PStmtKey("sql", "catalog2", "schema1", 0)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0), new PStmtKey("sql", "catalog2", "schema1", 0, 0)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0), new PStmtKey("sql", "catalog2", "schema1", 0, 0, 0)); // Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.CALLABLE_STATEMENT), new PStmtKey("sql", "catalog2", "schema1", 0, 0, 0, StatementType.CALLABLE_STATEMENT)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog2", "schema1", 0, 0, 0, StatementType.PREPARED_STATEMENT)); // Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.CALLABLE_STATEMENT), new PStmtKey("sql", "catalog2", "schema1", 0, 0, StatementType.CALLABLE_STATEMENT)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog2", "schema1", 0, 0, StatementType.PREPARED_STATEMENT)); // Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", (int[]) null), new PStmtKey("sql", "catalog2", "schema1", (int[]) null)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", new int[1]), new PStmtKey("sql", "catalog2", "schema1", new int[1])); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", (String[]) null), new PStmtKey("sql", "catalog2", "schema1", (String[]) null)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", new String[] {"A" }), new PStmtKey("sql", "catalog2", "schema1", new String[] {"A" })); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog2", "schema1", StatementType.PREPARED_STATEMENT)); Assertions.assertNotEquals( new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT, Integer.MAX_VALUE), new PStmtKey("sql", "catalog2", "schema1", StatementType.PREPARED_STATEMENT, Integer.MAX_VALUE)); } /** * Tests constructors with different schemas. */ @Test public void testCtorDifferentSchema() { Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1"), new PStmtKey("sql", "catalog1", "schema2")); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0), new PStmtKey("sql", "catalog1", "schema2", 0)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0), new PStmtKey("sql", "catalog1", "schema2", 0, 0)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0), new PStmtKey("sql", "catalog1", "schema2", 0, 0, 0)); // Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.CALLABLE_STATEMENT), new PStmtKey("sql", "catalog1", "schema2", 0, 0, 0, StatementType.CALLABLE_STATEMENT)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog1", "schema2", 0, 0, 0, StatementType.PREPARED_STATEMENT)); // Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.CALLABLE_STATEMENT), new PStmtKey("sql", "catalog1", "schema2", 0, 0, StatementType.CALLABLE_STATEMENT)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog1", "schema2", 0, 0, StatementType.PREPARED_STATEMENT)); // Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", (int[]) null), new PStmtKey("sql", "catalog1", "schema2", (int[]) null)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", new int[1]), new PStmtKey("sql", "catalog1", "schema2", new int[1])); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", (String[]) null), new PStmtKey("sql", "catalog1", "schema2", (String[]) null)); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", new String[] {"A" }), new PStmtKey("sql", "catalog1", "schema2", new String[] {"A" })); Assertions.assertNotEquals(new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog1", "schema2", StatementType.PREPARED_STATEMENT)); Assertions.assertNotEquals( new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT, Integer.MAX_VALUE), new PStmtKey("sql", "catalog1", "schema2", StatementType.PREPARED_STATEMENT, Integer.MAX_VALUE)); } /** * Tests constructors with different catalog. */ @Test public void testCtorEquals() { Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1"), new PStmtKey("sql", "catalog1", "schema1")); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", 0), new PStmtKey("sql", "catalog1", "schema1", 0)); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0), new PStmtKey("sql", "catalog1", "schema1", 0, 0)); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0), new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0)); // Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.CALLABLE_STATEMENT), new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.CALLABLE_STATEMENT)); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog1", "schema1", 0, 0, 0, StatementType.PREPARED_STATEMENT)); // Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.CALLABLE_STATEMENT), new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.CALLABLE_STATEMENT)); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog1", "schema1", 0, 0, StatementType.PREPARED_STATEMENT)); // Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", (int[]) null), new PStmtKey("sql", "catalog1", "schema1", (int[]) null)); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", new int[1]), new PStmtKey("sql", "catalog1", "schema1", new int[1])); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", (String[]) null), new PStmtKey("sql", "catalog1", "schema1", (String[]) null)); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", new String[] {"A" }), new PStmtKey("sql", "catalog1", "schema1", new String[] {"A" })); Assertions.assertEquals(new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT), new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT)); Assertions.assertEquals( new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT, Integer.MAX_VALUE), new PStmtKey("sql", "catalog1", "schema1", StatementType.PREPARED_STATEMENT, Integer.MAX_VALUE)); } /** * Tests {@link org.apache.commons.dbcp2.PStmtKey#PStmtKey(String, String, String, int[])}. * * See https://issues.apache.org/jira/browse/DBCP-494 */ @Test public void testCtorStringStringArrayOfInts() { final int[] input = {0, 0}; final PStmtKey pStmtKey = new PStmtKey("", "", "", input); Assertions.assertArrayEquals(input, pStmtKey.getColumnIndexes()); input[0] = 1; input[1] = 1; Assertions.assertFalse(Arrays.equals(input, pStmtKey.getColumnIndexes())); } /** * Tests {@link org.apache.commons.dbcp2.PStmtKey#PStmtKey(String, String, String, int[])}. * * See https://issues.apache.org/jira/browse/DBCP-494 */ @Test public void testCtorStringStringArrayOfNullInts() { final int[] input = null; final PStmtKey pStmtKey = new PStmtKey("", "", "", input); Assertions.assertArrayEquals(input, pStmtKey.getColumnIndexes()); } /** * Tests {@link org.apache.commons.dbcp2.PStmtKey#PStmtKey(String, String, String, String[])}. * * See https://issues.apache.org/jira/browse/DBCP-494 */ @Test public void testCtorStringStringArrayOfNullStrings() { final String[] input = null; final PStmtKey pStmtKey = new PStmtKey("", "", "", input); Assertions.assertArrayEquals(input, pStmtKey.getColumnNames()); } /** * Tests {@link org.apache.commons.dbcp2.PStmtKey#PStmtKey(String, String, String, String[])}. * * See https://issues.apache.org/jira/browse/DBCP-494 */ @Test public void testCtorStringStringArrayOfStrings() { final String[] input = {"A", "B"}; final PStmtKey pStmtKey = new PStmtKey("", "", "", input); Assertions.assertArrayEquals(input, pStmtKey.getColumnNames()); input[0] = "C"; input[1] = "D"; Assertions.assertFalse(Arrays.equals(input, pStmtKey.getColumnNames())); } @Test public void testEquals() { final PStmtKey pStmtKey = new PStmtKey("SELECT 1", "catalog", "public", java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY, StatementType.CALLABLE_STATEMENT); assertEquals(pStmtKey, pStmtKey); assertNotEquals(null, pStmtKey); assertNotEquals(pStmtKey, new Object()); assertNotEquals(pStmtKey, new PStmtKey("SELECT 2", "catalog", "public", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, StatementType.CALLABLE_STATEMENT)); assertNotEquals(pStmtKey, new PStmtKey("SELECT 1", "anothercatalog", "public", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, StatementType.CALLABLE_STATEMENT)); assertNotEquals(pStmtKey, new PStmtKey("SELECT 1", "catalog", "private", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, StatementType.CALLABLE_STATEMENT)); assertNotEquals(pStmtKey, new PStmtKey("SELECT 1", "catalog", "public", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY, StatementType.CALLABLE_STATEMENT)); assertNotEquals(pStmtKey, new PStmtKey("SELECT 1", "catalog", "public", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE, StatementType.CALLABLE_STATEMENT)); assertNotEquals(pStmtKey, new PStmtKey("SELECT 1", "catalog", "public", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, StatementType.PREPARED_STATEMENT)); assertEquals(pStmtKey, new PStmtKey("SELECT 1", "catalog", "public", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, StatementType.CALLABLE_STATEMENT)); assertEquals(pStmtKey.hashCode(), new PStmtKey("SELECT 1", "catalog", "public", java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY, StatementType.CALLABLE_STATEMENT).hashCode()); } @Test public void testGettersSetters() { final PStmtKey pStmtKey = new PStmtKey("SELECT 1", "catalog", "public"); assertEquals("SELECT 1", pStmtKey.getSql()); assertEquals("public", pStmtKey.getSchema()); assertEquals("catalog", pStmtKey.getCatalog()); assertNull(pStmtKey.getAutoGeneratedKeys()); assertNull(pStmtKey.getResultSetConcurrency()); assertNull(pStmtKey.getResultSetHoldability()); assertNull(pStmtKey.getResultSetType()); assertEquals(StatementType.PREPARED_STATEMENT, pStmtKey.getStmtType()); } @Test public void testToString() { final PStmtKey pStmtKey = new PStmtKey("SELECT 1", "catalog", "public", StatementType.CALLABLE_STATEMENT, Statement.RETURN_GENERATED_KEYS); assertTrue(pStmtKey.toString().contains("sql=SELECT 1")); assertTrue(pStmtKey.toString().contains("schema=public")); assertTrue(pStmtKey.toString().contains("autoGeneratedKeys=1")); assertTrue(pStmtKey.toString().contains("statementType=CALLABLE_STATEMENT")); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestPStmtPooling.java000066400000000000000000000230611447311732500325710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import javax.management.ObjectName; import javax.sql.DataSource; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * TestSuite for BasicDataSource with prepared statement pooling enabled */ public class TestPStmtPooling { private DataSource createPoolingDataSource() throws Exception { DriverManager.registerDriver(new TesterDriver()); final ConnectionFactory connFactory = new DriverManagerConnectionFactory( "jdbc:apache:commons:testdriver","u1","p1"); final PoolableConnectionFactory pcf = new PoolableConnectionFactory(connFactory, null); pcf.setPoolStatements(true); pcf.setDefaultReadOnly(Boolean.FALSE); pcf.setDefaultAutoCommit(Boolean.TRUE); final ObjectPool connPool = new GenericObjectPool<>(pcf); pcf.setPool(connPool); return new PoolingDataSource<>(connPool); } private PoolablePreparedStatement getPoolablePreparedStatement(Statement s) { while (s != null) { if (s instanceof PoolablePreparedStatement) { return (PoolablePreparedStatement) s; } if (!(s instanceof DelegatingPreparedStatement)) { return null; } s = ((DelegatingPreparedStatement) s).getDelegate(); } return null; } @Test public void testBatchUpdate() throws Exception { DriverManager.registerDriver(new TesterDriver()); final ConnectionFactory connFactory = new DriverManagerConnectionFactory( "jdbc:apache:commons:testdriver","u1","p1"); final PoolableConnectionFactory pcf = new PoolableConnectionFactory(connFactory, null); pcf.setPoolStatements(true); pcf.setDefaultReadOnly(Boolean.FALSE); pcf.setDefaultAutoCommit(Boolean.TRUE); final ObjectPool connPool = new GenericObjectPool<>(pcf); pcf.setPool(connPool); final PoolingDataSource ds = new PoolingDataSource<>(connPool); final Connection conn = ds.getConnection(); final PreparedStatement ps = conn.prepareStatement("select 1 from dual"); final Statement inner = ((DelegatingPreparedStatement) ps).getInnermostDelegate(); // Check DBCP-372 ps.addBatch(); ps.close(); conn.close(); Assertions.assertFalse(inner.isClosed()); ds.close(); } @Test public void testCallableStatementPooling() throws Exception { DriverManager.registerDriver(new TesterDriver()); final ConnectionFactory connFactory = new DriverManagerConnectionFactory( "jdbc:apache:commons:testdriver","u1","p1"); final ObjectName oName = new ObjectName("UnitTests:DataSource=test"); final PoolableConnectionFactory pcf = new PoolableConnectionFactory(connFactory, oName); pcf.setPoolStatements(true); pcf.setDefaultReadOnly(Boolean.FALSE); pcf.setDefaultAutoCommit(Boolean.TRUE); final GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setJmxNameBase("UnitTests:DataSource=test,connectionpool=connections"); config.setJmxNamePrefix(""); final ObjectPool connPool = new GenericObjectPool<>(pcf, config); pcf.setPool(connPool); final PoolingDataSource ds = new PoolingDataSource<>(connPool); try (Connection conn = ds.getConnection()) { final Statement stmt1 = conn.prepareStatement("select 1 from dual"); final Statement ustmt1 = ((DelegatingStatement) stmt1).getInnermostDelegate(); final Statement cstmt1 = conn.prepareCall("{call home}"); final Statement ucstmt1 = ((DelegatingStatement) cstmt1).getInnermostDelegate(); stmt1.close(); // Return to pool cstmt1.close(); // "" final Statement stmt2 = conn.prepareStatement("select 1 from dual"); // Check out from pool final Statement ustmt2 = ((DelegatingStatement) stmt2).getInnermostDelegate(); final Statement cstmt2 = conn.prepareCall("{call home}"); final Statement ucstmt2 = ((DelegatingStatement) cstmt2).getInnermostDelegate(); stmt2.close(); // Return to pool cstmt2.close(); // "" assertSame(ustmt1, ustmt2); assertSame(ucstmt1, ucstmt2); // Verify key distinguishes Callable from Prepared Statements in the pool final Statement stmt3 = conn.prepareCall("select 1 from dual"); final Statement ustmt3 = ((DelegatingStatement) stmt3).getInnermostDelegate(); stmt3.close(); assertNotSame(ustmt1, ustmt3); assertNotSame(ustmt3, ucstmt1); } ds.close(); } @Test public void testClosePool() throws Exception { DriverManager.registerDriver(new TesterDriver()); final ConnectionFactory connFactory = new DriverManagerConnectionFactory( "jdbc:apache:commons:testdriver","u1","p1"); final PoolableConnectionFactory pcf = new PoolableConnectionFactory(connFactory, null); pcf.setPoolStatements(true); pcf.setDefaultReadOnly(Boolean.FALSE); pcf.setDefaultAutoCommit(Boolean.TRUE); final ObjectPool connPool = new GenericObjectPool<>(pcf); pcf.setPool(connPool); final PoolingDataSource ds = new PoolingDataSource<>(connPool); ((PoolingDataSource) ds).setAccessToUnderlyingConnectionAllowed(true); final Connection conn = ds.getConnection(); try (Statement s = conn.prepareStatement("select 1 from dual")) {} final Connection poolableConnection = ((DelegatingConnection) conn).getDelegate(); final Connection poolingConnection = ((DelegatingConnection) poolableConnection).getDelegate(); poolingConnection.close(); try (PreparedStatement ps = conn.prepareStatement("select 1 from dual")) { fail("Expecting SQLException"); } catch (final SQLException ex) { assertTrue(ex.getMessage().endsWith("invalid PoolingConnection.")); } ds.close(); } /** * Verifies that executing close() on an already closed DelegatingStatement * that wraps a PoolablePreparedStatement does not "re-close" the PPS * (which could be in use by another client - see DBCP-414). */ @Test public void testMultipleClose() throws Exception { final DataSource ds = createPoolingDataSource(); final Connection conn = ds.getConnection(); final PreparedStatement stmt1 = conn.prepareStatement("select 1 from dual"); final PoolablePreparedStatement pps1 = getPoolablePreparedStatement(stmt1); conn.close(); assertTrue(stmt1.isClosed()); // Closing conn should close stmt stmt1.close(); // Should already be closed - no-op assertTrue(stmt1.isClosed()); final Connection conn2 = ds.getConnection(); final PreparedStatement stmt2 = conn2.prepareStatement("select 1 from dual"); // Confirm stmt2 now wraps the same PPS wrapped by stmt1 Assertions.assertSame(pps1, getPoolablePreparedStatement(stmt2)); stmt1.close(); // close should not cascade to PPS that stmt1 used to wrap assertFalse(stmt2.isClosed()); stmt2.executeQuery(); // wrapped PPS needs to work here - pre DBCP-414 fix this throws conn2.close(); assertTrue(stmt1.isClosed()); assertTrue(stmt2.isClosed()); } @Test public void testStmtPool() throws Exception { final DataSource ds = createPoolingDataSource(); try (Connection conn = ds.getConnection()) { final Statement stmt1 = conn.prepareStatement("select 1 from dual"); final Statement ustmt1 = ((DelegatingStatement) stmt1).getInnermostDelegate(); stmt1.close(); final Statement stmt2 = conn.prepareStatement("select 1 from dual"); final Statement ustmt2 = ((DelegatingStatement) stmt2).getInnermostDelegate(); stmt2.close(); assertSame(ustmt1, ustmt2); } } } TestPStmtPoolingBasicDataSource.java000066400000000000000000000273471447311732500354420ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import org.apache.commons.pool2.KeyedObjectPool; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * TestSuite for BasicDataSource with prepared statement pooling enabled */ public class TestPStmtPoolingBasicDataSource extends TestBasicDataSource { @Override @BeforeEach public void setUp() throws Exception { super.setUp(); // PoolPreparedStatements enabled, should not affect the basic tests ds.setPoolPreparedStatements(true); ds.setMaxOpenPreparedStatements(2); } /** * Verifies that the prepared statement pool behaves as an LRU cache, * closing least-recently-used statements idle in the pool to make room * for new ones if necessary. */ @Test public void testLRUBehavior() throws Exception { ds.setMaxOpenPreparedStatements(3); final Connection conn = getConnection(); assertNotNull(conn); // Open 3 statements and then close them into the pool final PreparedStatement stmt1 = conn.prepareStatement("select 'a' from dual"); final PreparedStatement inner1 = (PreparedStatement) ((DelegatingPreparedStatement) stmt1).getInnermostDelegate(); final PreparedStatement stmt2 = conn.prepareStatement("select 'b' from dual"); final PreparedStatement inner2 = (PreparedStatement) ((DelegatingPreparedStatement) stmt2).getInnermostDelegate(); final PreparedStatement stmt3 = conn.prepareStatement("select 'c' from dual"); final PreparedStatement inner3 = (PreparedStatement) ((DelegatingPreparedStatement) stmt3).getInnermostDelegate(); stmt1.close(); Thread.sleep(100); // Make sure return timestamps are different stmt2.close(); Thread.sleep(100); stmt3.close(); // Pool now has three idle statements, getting another one will force oldest (stmt1) out final PreparedStatement stmt4 = conn.prepareStatement("select 'd' from dual"); assertNotNull(stmt4); // Verify that inner1 has been closed try { inner1.clearParameters(); fail("expecting SQLExcption - statement should be closed"); } catch (final SQLException ex) { //Expected } // But others are still open inner2.clearParameters(); inner3.clearParameters(); // Now make sure stmt1 does not come back from the dead final PreparedStatement stmt5 = conn.prepareStatement("select 'a' from dual"); final PreparedStatement inner5 = (PreparedStatement) ((DelegatingPreparedStatement) stmt5).getInnermostDelegate(); assertNotSame(inner5, inner1); // inner2 should be closed now try { inner2.clearParameters(); fail("expecting SQLExcption - statement should be closed"); } catch (final SQLException ex) { //Expected } // But inner3 should still be open inner3.clearParameters(); } /** * Tests high-concurrency contention for connections and pooled prepared statements. * DBCP-414 */ @Test public void testMultipleThreads1() throws Exception { ds.setMaxWait(Duration.ofMillis(-1)); ds.setMaxTotal(5); ds.setMaxOpenPreparedStatements(-1); multipleThreads(Duration.ofMillis(5), false, false, Duration.ofMillis(-1), 3, 100, 10000); } @Test public void testPreparedStatementPooling() throws Exception { final Connection conn = getConnection(); assertNotNull(conn); final PreparedStatement stmt1 = conn.prepareStatement("select 'a' from dual"); assertNotNull(stmt1); final PreparedStatement stmt2 = conn.prepareStatement("select 'b' from dual"); assertNotNull(stmt2); assertNotSame(stmt1, stmt2); // go over the maxOpen limit try (PreparedStatement ps = conn.prepareStatement("select 'c' from dual")) { fail("expected SQLException"); } catch (final SQLException e) {} // make idle stmt2.close(); // test cleanup the 'b' statement final PreparedStatement stmt3 = conn.prepareStatement("select 'c' from dual"); assertNotNull(stmt3); assertNotSame(stmt3, stmt1); assertNotSame(stmt3, stmt2); // normal reuse of statement stmt1.close(); try (final PreparedStatement stmt4 = conn.prepareStatement("select 'a' from dual")) { assertNotNull(stmt4); } } // Bugzilla Bug 27246 // PreparedStatement cache should be different depending on the Catalog @Test public void testPStmtCatalog() throws Exception { final Connection conn = getConnection(); conn.setCatalog("catalog1"); final DelegatingPreparedStatement stmt1 = (DelegatingPreparedStatement) conn.prepareStatement("select 'a' from dual"); final TesterPreparedStatement inner1 = (TesterPreparedStatement) stmt1.getInnermostDelegate(); assertEquals("catalog1", inner1.getCatalog()); stmt1.close(); conn.setCatalog("catalog2"); final DelegatingPreparedStatement stmt2 = (DelegatingPreparedStatement) conn.prepareStatement("select 'a' from dual"); final TesterPreparedStatement inner2 = (TesterPreparedStatement) stmt2.getInnermostDelegate(); assertEquals("catalog2", inner2.getCatalog()); stmt2.close(); conn.setCatalog("catalog1"); final DelegatingPreparedStatement stmt3 = (DelegatingPreparedStatement) conn.prepareStatement("select 'a' from dual"); final TesterPreparedStatement inner3 = (TesterPreparedStatement) stmt3.getInnermostDelegate(); assertEquals("catalog1", inner3.getCatalog()); stmt3.close(); assertNotSame(inner1, inner2); assertSame(inner1, inner3); } @Test public void testPStmtPoolingAcrossClose() throws Exception { ds.setMaxTotal(1); // only one connection in pool needed ds.setMaxIdle(1); ds.setAccessToUnderlyingConnectionAllowed(true); final Connection conn1 = getConnection(); assertNotNull(conn1); assertEquals(1, ds.getNumActive()); assertEquals(0, ds.getNumIdle()); final PreparedStatement stmt1 = conn1.prepareStatement("select 'a' from dual"); assertNotNull(stmt1); final Statement inner1 = ((DelegatingPreparedStatement) stmt1).getInnermostDelegate(); assertNotNull(inner1); stmt1.close(); conn1.close(); assertEquals(0, ds.getNumActive()); assertEquals(1, ds.getNumIdle()); final Connection conn2 = getConnection(); assertNotNull(conn2); assertEquals(1, ds.getNumActive()); assertEquals(0, ds.getNumIdle()); final PreparedStatement stmt2 = conn2.prepareStatement("select 'a' from dual"); assertNotNull(stmt2); final Statement inner2 = ((DelegatingPreparedStatement) stmt2).getInnermostDelegate(); assertNotNull(inner2); assertSame(inner1, inner2); } /** * Tests clearStatementPoolOnReturn introduced with DBCP-566. * When turned on, the statement pool must be empty after the connection is closed. * * @throws Exception * @since 2.8.0 */ @Test public void testPStmtPoolingAcrossCloseWithClearOnReturn() throws Exception { ds.setMaxTotal(1); // only one connection in pool needed ds.setMaxIdle(1); ds.setClearStatementPoolOnReturn(true); ds.setAccessToUnderlyingConnectionAllowed(true); final Connection conn1 = getConnection(); assertNotNull(conn1); assertEquals(1, ds.getNumActive()); assertEquals(0, ds.getNumIdle()); @SuppressWarnings("unchecked") final DelegatingConnection poolableConn = (DelegatingConnection) ((DelegatingConnection) conn1).getDelegateInternal(); final KeyedObjectPool stmtPool = ((PoolingConnection) poolableConn.getDelegateInternal()).getStatementPool(); final PreparedStatement stmt1 = conn1.prepareStatement("select 'a' from dual"); assertNotNull(stmt1); final Statement inner1 = ((DelegatingPreparedStatement) stmt1).getInnermostDelegate(); assertNotNull(inner1); stmt1.close(); final PreparedStatement stmt2 = conn1.prepareStatement("select 'a' from dual"); assertNotNull(stmt2); final Statement inner2 = ((DelegatingPreparedStatement) stmt2).getInnermostDelegate(); assertNotNull(inner2); assertSame(inner1, inner2); // from the same connection the statement must be pooled stmt2.close(); conn1.close(); assertTrue(inner1.isClosed()); assertEquals(0, stmtPool.getNumActive()); assertEquals(0, stmtPool.getNumIdle()); assertEquals(0, ds.getNumActive()); assertEquals(1, ds.getNumIdle()); final Connection conn2 = getConnection(); assertNotNull(conn2); assertEquals(1, ds.getNumActive()); assertEquals(0, ds.getNumIdle()); final PreparedStatement stmt3 = conn2.prepareStatement("select 'a' from dual"); assertNotNull(stmt3); final Statement inner3 = ((DelegatingPreparedStatement) stmt3).getInnermostDelegate(); assertNotNull(inner3); assertNotSame(inner1, inner3); // when acquiring the connection the next time, statement must be new conn2.close(); } @Test public void testPStmtPoolingWithNoClose() throws Exception { ds.setMaxTotal(1); // only one connection in pool needed ds.setMaxIdle(1); ds.setAccessToUnderlyingConnectionAllowed(true); final Connection conn1 = getConnection(); assertNotNull(conn1); assertEquals(1, ds.getNumActive()); assertEquals(0, ds.getNumIdle()); final PreparedStatement stmt1 = conn1.prepareStatement("select 'a' from dual"); assertNotNull(stmt1); final Statement inner1 = ((DelegatingPreparedStatement) stmt1).getInnermostDelegate(); assertNotNull(inner1); stmt1.close(); assertNotNull(conn1); assertEquals(1, ds.getNumActive()); assertEquals(0, ds.getNumIdle()); final PreparedStatement stmt2 = conn1.prepareStatement("select 'a' from dual"); assertNotNull(stmt2); final Statement inner2 = ((DelegatingPreparedStatement) stmt2).getInnermostDelegate(); assertNotNull(inner2); assertSame(inner1, inner2); } } TestParallelCreationWithNoIdle.java000066400000000000000000000127101447311732500352620ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.commons.logging.LogFactory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Test if the pooling if no idle objects are used */ public class TestParallelCreationWithNoIdle { class TestThread extends Thread { final java.util.Random _random = new java.util.Random(); final int iter; final int delay; final int delayAfter; public TestThread(final int iter, final int delay, final int delayAfter) { this.iter = iter; this.delay = delay; this.delayAfter = delayAfter; } @Override public void run() { // System.out.println("Thread started " + Thread.currentThread().toString()); for (int i = 0; i < iter; i++) { sleepMax(delay); try (Connection conn = ds.getConnection(); PreparedStatement stmt = conn.prepareStatement("select 'literal', SYSDATE from dual")) { // System.out.println("Got Connection " + Thread.currentThread().toString()); final ResultSet rset = stmt.executeQuery(); rset.next(); sleepMax(delayAfter); rset.close(); } catch (final Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } // System.out.println("Thread done " + Thread.currentThread().toString()); } private void sleepMax(final int timeMax) { if (timeMax == 0) { return; } try { Thread.sleep(_random.nextInt(timeMax)); } catch (final Exception e) { // ignored } } } private static final String CATALOG = "test catalog"; @BeforeAll public static void setUpClass() { // register a custom logger which supports inspection of the log messages LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", "org.apache.commons.dbcp2.StackMessageLog"); } protected BasicDataSource ds; @BeforeEach public void setUp() throws Exception { ds = new BasicDataSource(); ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver"); ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:50"); ds.setMaxTotal(10); // this one is actually very important. // see DBCP-513 ds.setMaxIdle(0); // wait a minute. Usually the test runs in ~ 1 second // but often it's getting stuck ^^ // you have one second to get a thread dump ;) ds.setMaxWait(Duration.ofMinutes(1)); ds.setDefaultAutoCommit(Boolean.TRUE); ds.setDefaultReadOnly(Boolean.FALSE); ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); ds.setDefaultCatalog(CATALOG); ds.setUsername("userName"); ds.setPassword("password"); ds.setValidationQuery("SELECT DUMMY FROM DUAL"); ds.setConnectionInitSqls(Arrays.asList("SELECT 1", "SELECT 2")); ds.setDriverClassLoader(new TesterClassLoader()); ds.setJmxName("org.apache.commons.dbcp2:name=test"); } /** * Fire up 100 Threads but only have 10 maxActive and forcedBlock. * See * @throws Exception */ @Test public void testMassiveConcurrentInitBorrow() throws Exception { final int numThreads = 200; ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver"); ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:20"); ds.setInitialSize(8); final List errors = Collections.synchronizedList(new ArrayList<>()); final Thread[] threads = new Thread[numThreads]; for (int i = 0; i < numThreads; i++) { threads[i] = new TestThread(2, 0, 50); threads[i].setUncaughtExceptionHandler((t, e) -> errors.add(e)); } for (int i = 0; i < numThreads; i++) { threads[i].start(); if (i%4 == 0) { Thread.sleep(20); } } for (int i = 0; i < numThreads; i++) { threads[i].join(); } assertEquals(0, errors.size()); ds.close(); } } TestPoolableConnection.java000066400000000000000000000206011447311732500336650ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import javax.management.OperationsException; import org.apache.commons.pool2.impl.GenericObjectPool; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** */ public class TestPoolableConnection { private GenericObjectPool pool; @BeforeEach public void setUp() throws Exception { final PoolableConnectionFactory factory = new PoolableConnectionFactory( new DriverConnectionFactory( new TesterDriver(),"jdbc:apache:commons:testdriver", null), null); factory.setDefaultAutoCommit(Boolean.TRUE); factory.setDefaultReadOnly(Boolean.TRUE); pool = new GenericObjectPool<>(factory); factory.setPool(pool); } @AfterEach public void tearDown() { pool.close(); } @Test public void testClosingWrappedInDelegate() throws Exception { Assertions.assertEquals(0, pool.getNumActive()); final Connection conn = pool.borrowObject(); final DelegatingConnection outer = new DelegatingConnection<>(conn); Assertions.assertFalse(outer.isClosed()); Assertions.assertFalse(conn.isClosed()); Assertions.assertEquals(1, pool.getNumActive()); outer.close(); Assertions.assertTrue(outer.isClosed()); Assertions.assertTrue(conn.isClosed()); Assertions.assertEquals(0, pool.getNumActive()); Assertions.assertEquals(1, pool.getNumIdle()); } @Test public void testConnectionPool() throws Exception { // Grab a new connection from the pool final Connection c = pool.borrowObject(); assertNotNull(c, "Connection should be created and should not be null"); assertEquals(1, pool.getNumActive(), "There should be exactly one active object in the pool"); // Now return the connection by closing it c.close(); // Can't be null assertEquals(0, pool.getNumActive(), "There should now be zero active objects in the pool"); } @Test public void testFastFailValidation() throws Exception { pool.setTestOnReturn(true); final PoolableConnectionFactory factory = (PoolableConnectionFactory) pool.getFactory(); factory.setFastFailValidation(true); final PoolableConnection conn = pool.borrowObject(); final TesterConnection nativeConnection = (TesterConnection) conn.getInnermostDelegate(); // Set up non-fatal exception nativeConnection.setFailure(new SQLException("Not fatal error.", "Invalid syntax.")); try { conn.createStatement(); fail("Should throw SQL exception."); } catch (final SQLException ignored) { // cleanup failure nativeConnection.setFailure(null); } // validate should not fail - error was not fatal and condition was cleaned up conn.validate("SELECT 1", 1000); // now set up fatal failure nativeConnection.setFailure(new SQLException("Fatal connection error.", "01002")); try { conn.createStatement(); fail("Should throw SQL exception."); } catch (final SQLException ignored) { // cleanup failure nativeConnection.setFailure(null); } // validate should now fail because of previous fatal error, despite cleanup try { conn.validate("SELECT 1", 1000); fail("Should throw SQL exception on validation."); } catch (final SQLException notValid){ // expected - fatal error && fastFailValidation } // verify that bad connection does not get returned to the pool conn.close(); // testOnReturn triggers validate, which should fail assertEquals(0, pool.getNumActive(), "The pool should have no active connections"); assertEquals(0, pool.getNumIdle(), "The pool should have no idle connections"); } @Test public void testFastFailValidationCustomCodes() throws Exception { pool.setTestOnReturn(true); final PoolableConnectionFactory factory = (PoolableConnectionFactory) pool.getFactory(); factory.setFastFailValidation(true); final ArrayList disconnectionSqlCodes = new ArrayList<>(); disconnectionSqlCodes.add("XXX"); factory.setDisconnectionSqlCodes(disconnectionSqlCodes); final PoolableConnection conn = pool.borrowObject(); final TesterConnection nativeConnection = (TesterConnection) conn.getInnermostDelegate(); // Set up fatal exception nativeConnection.setFailure(new SQLException("Fatal connection error.", "XXX")); try { conn.createStatement(); fail("Should throw SQL exception."); } catch (final SQLException ignored) { // cleanup failure nativeConnection.setFailure(null); } // verify that bad connection does not get returned to the pool conn.close(); // testOnReturn triggers validate, which should fail assertEquals(0, pool.getNumActive(), "The pool should have no active connections"); assertEquals(0, pool.getNumIdle(), "The pool should have no idle connections"); } // Bugzilla Bug 33591: PoolableConnection leaks connections if the // delegated connection closes itself. @Test public void testPoolableConnectionLeak() throws Exception { // 'Borrow' a connection from the pool final Connection conn = pool.borrowObject(); // Now close our innermost delegate, simulating the case where the // underlying connection closes itself ((PoolableConnection)conn).getInnermostDelegate().close(); // At this point, we can close the pooled connection. The // PoolableConnection *should* realize that its underlying // connection is gone and invalidate itself. The pool should have no // active connections. try { conn.close(); } catch (final SQLException e) { // Here we expect 'connection already closed', but the connection // should *NOT* be returned to the pool } assertEquals(0, pool.getNumActive(), "The pool should have no active connections"); } @Test public void testIsDisconnectionSqlExceptionStackOverflow() throws Exception { final int maxDeep = 100_000; final SQLException rootException = new SQLException("Data truncated", "22001"); SQLException parentException = rootException; for (int i = 0; i <= maxDeep; i++) { final SQLException childException = new SQLException("Data truncated: " + i, "22001"); parentException.setNextException(childException); parentException = childException; } final Connection conn = pool.borrowObject(); assertEquals(false, ((PoolableConnection) conn).isDisconnectionSqlException(rootException)); assertEquals(false, ((PoolableConnection) conn).isFatalException(rootException)); } /** * Tests if the {@link PoolableConnectionMXBean} interface is a valid MXBean * interface. */ @Test public void testMXBeanCompliance() throws OperationsException { TestBasicDataSourceMXBean.testMXBeanCompliance(PoolableConnectionMXBean.class); } } TestPoolingConnection.java000066400000000000000000000177721447311732500335560ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import java.time.Duration; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class TestPoolingConnection { private PoolingConnection connection; @SuppressWarnings("resource") // Resources closed in @AfterEach method. @BeforeEach public void setUp() throws Exception { connection = new PoolingConnection(new TesterConnection("test", "test")); final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig<>(); config.setMaxTotalPerKey(-1); config.setBlockWhenExhausted(false); config.setMaxWait(Duration.ZERO); config.setMaxIdlePerKey(1); config.setMaxTotal(1); connection.setStatementPool(new GenericKeyedObjectPool<>(connection, config)); } @AfterEach public void tearDown() throws Exception { connection.close(); connection = null; } @Test public void testPrepareCall() throws Exception { final String sql = "select 'a' from dual"; try (final DelegatingCallableStatement statement = (DelegatingCallableStatement) connection.prepareCall(sql)) { final TesterCallableStatement testStatement = (TesterCallableStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); } } @Test public void testPrepareCallWithResultSetConcurrency() throws Exception { final String sql = "select 'a' from dual"; final int resultSetType = 0; final int resultSetConcurrency = 0; try (final DelegatingCallableStatement statement = (DelegatingCallableStatement) connection.prepareCall(sql, resultSetType, resultSetConcurrency)) { final TesterCallableStatement testStatement = (TesterCallableStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); assertEquals(resultSetType, testStatement.getResultSetType()); assertEquals(resultSetConcurrency, testStatement.getResultSetConcurrency()); } } @Test public void testPrepareCallWithResultSetHoldability() throws Exception { final String sql = "select 'a' from dual"; final int resultSetType = 0; final int resultSetConcurrency = 0; final int resultSetHoldability = 0; try (final DelegatingCallableStatement statement = (DelegatingCallableStatement) connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)) { final TesterCallableStatement testStatement = (TesterCallableStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); assertEquals(resultSetType, testStatement.getResultSetType()); assertEquals(resultSetConcurrency, testStatement.getResultSetConcurrency()); assertEquals(resultSetHoldability, testStatement.getResultSetHoldability()); } } @Test public void testPrepareStatement() throws Exception { final String sql = "select 'a' from dual"; try (final DelegatingPreparedStatement statement = (DelegatingPreparedStatement) connection.prepareStatement(sql)) { final TesterPreparedStatement testStatement = (TesterPreparedStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); } } @Test public void testPrepareStatementWithAutoGeneratedKeys() throws Exception { final String sql = "select 'a' from dual"; final int autoGeneratedKeys = 0; try (final DelegatingPreparedStatement statement = (DelegatingPreparedStatement) connection.prepareStatement(sql, autoGeneratedKeys)) { final TesterPreparedStatement testStatement = (TesterPreparedStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); assertEquals(autoGeneratedKeys, testStatement.getAutoGeneratedKeys()); } } @Test public void testPrepareStatementWithColumnIndexes() throws Exception { final String sql = "select 'a' from dual"; final int[] columnIndexes = {1}; try (final DelegatingPreparedStatement statement = (DelegatingPreparedStatement) connection.prepareStatement(sql, columnIndexes)) { final TesterPreparedStatement testStatement = (TesterPreparedStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); assertArrayEquals(columnIndexes, testStatement.getColumnIndexes()); } } @Test public void testPrepareStatementWithColumnNames() throws Exception { final String sql = "select 'a' from dual"; final String[] columnNames = {"columnName1"}; try (final DelegatingPreparedStatement statement = (DelegatingPreparedStatement) connection.prepareStatement(sql, columnNames)) { final TesterPreparedStatement testStatement = (TesterPreparedStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); assertArrayEquals(columnNames, testStatement.getColumnNames()); } } @Test public void testPrepareStatementWithResultSetConcurrency() throws Exception { final String sql = "select 'a' from dual"; final int resultSetType = 0; final int resultSetConcurrency = 0; try ( final DelegatingPreparedStatement statement = (DelegatingPreparedStatement) connection.prepareStatement(sql, resultSetType, resultSetConcurrency)) { final TesterPreparedStatement testStatement = (TesterPreparedStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); assertEquals(resultSetType, testStatement.getResultSetType()); assertEquals(resultSetConcurrency, testStatement.getResultSetConcurrency()); } } @Test public void testPrepareStatementWithResultSetHoldability() throws Exception { final String sql = "select 'a' from dual"; final int resultSetType = 0; final int resultSetConcurrency = 0; final int resultSetHoldability = 0; try (final DelegatingPreparedStatement statement = (DelegatingPreparedStatement) connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)) { final TesterPreparedStatement testStatement = (TesterPreparedStatement) statement.getInnermostDelegate(); // assert assertEquals(sql, testStatement.getSql()); assertEquals(resultSetType, testStatement.getResultSetType()); assertEquals(resultSetConcurrency, testStatement.getResultSetConcurrency()); assertEquals(resultSetHoldability, testStatement.getResultSetHoldability()); } } } TestPoolingDataSource.java000066400000000000000000000205071447311732500334770ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import org.apache.commons.pool2.impl.GenericObjectPool; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * TestSuite for PoolingDataSource */ public class TestPoolingDataSource extends TestConnectionPool { protected PoolingDataSource ds; private GenericObjectPool pool; @Override protected Connection getConnection() throws Exception { return ds.getConnection(); } @BeforeEach public void setUp() throws Exception { final Properties properties = new Properties(); properties.setProperty(Constants.KEY_USER, "userName"); properties.setProperty(Constants.KEY_PASSWORD, "password"); final PoolableConnectionFactory factory = new PoolableConnectionFactory( new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties), null); factory.setValidationQuery("SELECT DUMMY FROM DUAL"); factory.setDefaultReadOnly(Boolean.TRUE); factory.setDefaultAutoCommit(Boolean.TRUE); pool = new GenericObjectPool<>(factory); factory.setPool(pool); pool.setMaxTotal(getMaxTotal()); pool.setMaxWait(getMaxWaitDuration()); ds = new PoolingDataSource<>(pool); ds.setAccessToUnderlyingConnectionAllowed(true); } @Override @AfterEach public void tearDown() throws Exception { ds.close(); super.tearDown(); } @Test public void testClose() throws Exception { final Properties properties = new Properties(); properties.setProperty(Constants.KEY_USER, "userName"); properties.setProperty(Constants.KEY_PASSWORD, "password"); final PoolableConnectionFactory f = new PoolableConnectionFactory( new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties), null); f.setValidationQuery("SELECT DUMMY FROM DUAL"); f.setDefaultReadOnly(Boolean.TRUE); f.setDefaultAutoCommit(Boolean.TRUE); final GenericObjectPool p = new GenericObjectPool<>(f); p.setMaxTotal(getMaxTotal()); p.setMaxWait(getMaxWaitDuration()); try ( PoolingDataSource dataSource = new PoolingDataSource<>(p) ) { final Connection connection = dataSource.getConnection(); assertNotNull(connection); connection.close(); } assertTrue(p.isClosed()); assertEquals(0, p.getNumIdle()); assertEquals(0, p.getNumActive()); } /** * DBCP-412 * Verify that omitting factory.setPool(pool) when setting up PDS does not * result in NPE. */ @Test public void testFixFactoryConfig() throws Exception { final Properties properties = new Properties(); properties.setProperty(Constants.KEY_USER, "userName"); properties.setProperty(Constants.KEY_PASSWORD, "password"); final PoolableConnectionFactory f = new PoolableConnectionFactory( new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties), null); f.setValidationQuery("SELECT DUMMY FROM DUAL"); f.setDefaultReadOnly(Boolean.TRUE); f.setDefaultAutoCommit(Boolean.TRUE); final GenericObjectPool p = new GenericObjectPool<>(f); p.setMaxTotal(getMaxTotal()); p.setMaxWait(getMaxWaitDuration()); ds = new PoolingDataSource<>(p); assertEquals(f.getPool(), p); ds.getConnection(); } @Test public void testIsWrapperFor() throws Exception { assertTrue(ds.isWrapperFor(PoolingDataSource.class)); assertTrue(ds.isWrapperFor(AutoCloseable.class)); assertFalse(ds.isWrapperFor(String.class)); assertFalse(ds.isWrapperFor(null)); } @Test public void testPoolGuardConnectionWrapperEqualInnermost() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); final DelegatingConnection con = (DelegatingConnection) ds.getConnection(); final Connection inner = con.getInnermostDelegate(); ds.setAccessToUnderlyingConnectionAllowed(false); final DelegatingConnection con2 = new DelegatingConnection<>(inner); assertNotEquals(con2, con); assertTrue(con.innermostDelegateEquals(con2.getInnermostDelegate())); assertTrue(con2.innermostDelegateEquals(inner)); assertNotEquals(con, con2); } @Test public void testPoolGuardConnectionWrapperEqualsFail() throws Exception { final Connection con1 = ds.getConnection(); final Connection con2 = ds.getConnection(); assertNotEquals(con1, con2); con1.close(); con2.close(); } @Test public void testPoolGuardConnectionWrapperEqualsNull() throws Exception { final Connection con1 = ds.getConnection(); final Connection con2 = null; assertNotEquals(con2, con1); con1.close(); } /* * JIRA: DBCP-198 */ @Test public void testPoolGuardConnectionWrapperEqualsReflexive() throws Exception { final Connection con = ds.getConnection(); final Connection con2 = con; assertEquals(con2, con); assertEquals(con, con2); con.close(); } @Test public void testPoolGuardConnectionWrapperEqualsSameDelegate() throws Exception { // Get a maximal set of connections from the pool final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = newConnection(); } // Close the delegate of one wrapper in the pool ((DelegatingConnection) c[0]).getDelegate().close(); // Grab a new connection - should get c[0]'s closed connection // so should be delegate-equivalent final Connection con = newConnection(); Assertions.assertNotEquals(c[0], con); Assertions.assertEquals( ((DelegatingConnection) c[0]).getInnermostDelegateInternal(), ((DelegatingConnection) con).getInnermostDelegateInternal()); for (final Connection element : c) { element.close(); } } @Test public void testPoolGuardConnectionWrapperEqualsType() throws Exception { final Connection con1 = ds.getConnection(); final Integer con2 = 0; assertNotEquals(con2, con1); con1.close(); } @Test public void testUnwrap() throws Exception { assertSame(ds.unwrap(PoolingDataSource.class), ds); assertSame(ds.unwrap(AutoCloseable.class), ds); assertThrows(SQLException.class, () -> ds.unwrap(String.class)); assertThrows(SQLException.class, () -> ds.unwrap(null)); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestPoolingDriver.java000066400000000000000000000234121447311732500327550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.time.Duration; import javax.sql.DataSource; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests for a {@link GenericObjectPool} based {@link PoolingDriver}. */ public class TestPoolingDriver extends TestConnectionPool { private PoolingDriver driver; @Override protected Connection getConnection() throws Exception { return DriverManager.getConnection("jdbc:apache:commons:dbcp:test"); } @BeforeEach public void setUp() throws Exception { final DriverConnectionFactory cf = new DriverConnectionFactory(new TesterDriver(),"jdbc:apache:commons:testdriver", null); final PoolableConnectionFactory pcf = new PoolableConnectionFactory(cf, null); pcf.setPoolStatements(true); pcf.setMaxOpenPreparedStatements(10); pcf.setValidationQuery("SELECT COUNT(*) FROM DUAL"); pcf.setDefaultReadOnly(Boolean.FALSE); pcf.setDefaultAutoCommit(Boolean.TRUE); final GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig<>(); poolConfig.setMaxTotal(getMaxTotal()); poolConfig.setMaxWait(getMaxWaitDuration()); poolConfig.setMinIdle(10); poolConfig.setTestOnBorrow(true); poolConfig.setTestOnReturn(true); poolConfig.setTestWhileIdle(true); poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(10_000)); poolConfig.setNumTestsPerEvictionRun(5); poolConfig.setMinEvictableIdleTime(Duration.ofMillis(5_000)); final GenericObjectPool pool = new GenericObjectPool<>(pcf, poolConfig); pcf.setPool(pool); assertNotNull(pcf); driver = new PoolingDriver(true); driver.registerPool("test",pool); } @Override @AfterEach public void tearDown() throws Exception { driver.closePool("test"); super.tearDown(); } @Test public void test1() { final ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string","userName","password"); final PoolableConnectionFactory pcf = new PoolableConnectionFactory(connectionFactory, null); pcf.setDefaultReadOnly(Boolean.FALSE); pcf.setDefaultAutoCommit(Boolean.TRUE); final GenericObjectPool connectionPool = new GenericObjectPool<>(pcf); pcf.setPool(connectionPool); final DataSource ds = new PoolingDataSource<>(connectionPool); Assertions.assertNotNull(ds); } @Test public void test2() { final ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string","userName","password"); final PoolableConnectionFactory pcf = new PoolableConnectionFactory(connectionFactory, null); pcf.setDefaultReadOnly(Boolean.FALSE); pcf.setDefaultAutoCommit(Boolean.TRUE); final GenericObjectPool connectionPool = new GenericObjectPool<>(pcf); final PoolingDriver driver2 = new PoolingDriver(); driver2.registerPool("example", connectionPool); } @Test public void testClosePool() throws Exception { final Connection conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:test"); assertNotNull(conn); conn.close(); final PoolingDriver driver2 = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:"); driver2.closePool("test"); try (Connection c = DriverManager.getConnection("jdbc:apache:commons:dbcp:test")) { fail("expected SQLException"); } catch (final SQLException e) { // OK } } @Test public void testInvalidateConnection() throws Exception { final Connection conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:test"); assertNotNull(conn); final ObjectPool pool = driver.getConnectionPool("test"); assertEquals(1, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); final PoolingDriver driver2 = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:"); driver2.invalidateConnection(conn); assertEquals(0, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); assertTrue(conn.isClosed()); } @Test public void testLogWriter() throws Exception { final PrintStream ps = new PrintStream(new ByteArrayOutputStream(), false, "UTF-8"); final PrintWriter pw = new PrintWriter(new OutputStreamWriter(new ByteArrayOutputStream(), StandardCharsets.UTF_8)); System.setErr(new PrintStream(new ByteArrayOutputStream(), false, "UTF-8")); SQLException ex; DriverManager.setLogWriter(pw); ex = new SQLException("A", new Exception("a")); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); ex = new SQLException("B"); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); ex = new SQLException(null, new Exception("c")); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); ex = new SQLException((String)null); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); DriverManager.setLogWriter(null); ex = new SQLException("A", new Exception("a")); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); ex = new SQLException("B"); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); ex = new SQLException(null, new Exception("c")); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); ex = new SQLException((String)null); ex.printStackTrace(); ex.printStackTrace(ps); ex.printStackTrace(pw); } /** "https://issues.apache.org/bugzilla/show_bug.cgi?id=12400" */ @Test public void testReportedBug12400() throws Exception { final GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(70); config.setMaxWait(Duration.ofMinutes(1)); config.setMaxIdle(10); final ConnectionFactory connectionFactory = new DriverManagerConnectionFactory( "jdbc:apache:commons:testdriver", "userName", "password"); final PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null); poolableConnectionFactory.setDefaultReadOnly(Boolean.FALSE); poolableConnectionFactory.setDefaultAutoCommit(Boolean.TRUE); final ObjectPool connectionPool = new GenericObjectPool<>(poolableConnectionFactory, config); poolableConnectionFactory.setPool(connectionPool); assertNotNull(poolableConnectionFactory); final PoolingDriver driver2 = new PoolingDriver(); driver2.registerPool("neusoftim", connectionPool); final Connection[] conn = new Connection[25]; for(int i=0;i<25;i++) { conn[i] = DriverManager.getConnection("jdbc:apache:commons:dbcp:neusoftim"); for(int j=0;j list = Collections.singletonList(cause); final SQLExceptionList sqlExceptionList = new SQLExceptionList(list); Assertions.assertEquals(cause, sqlExceptionList.getCause()); Assertions.assertEquals(list, sqlExceptionList.getCauseList()); sqlExceptionList.printStackTrace(); } @Test public void testNullCause() { final SQLExceptionList sqlExceptionList = new SQLExceptionList(null); Assertions.assertNull(sqlExceptionList.getCause()); Assertions.assertNull(sqlExceptionList.getCauseList()); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TestUtils.java000066400000000000000000000017541447311732500312770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import org.junit.jupiter.api.Test; public class TestUtils { @Test public void testClassLoads() { Utils.closeQuietly((AutoCloseable) null); } } TesterCallableStatement.java000066400000000000000000000423101447311732500340240ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.Date; import java.sql.NClob; import java.sql.Ref; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLType; import java.sql.SQLXML; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; import java.util.Map; /** * Trivial implementation of a CallableStatement to avoid null pointer exceptions in tests. */ public class TesterCallableStatement extends TesterPreparedStatement implements CallableStatement { public TesterCallableStatement(final Connection conn) { super(conn); } public TesterCallableStatement(final Connection conn, final String sql) { super(conn, sql); } public TesterCallableStatement(final Connection conn, final String sql, final int resultSetType, final int resultSetConcurrency) { super(conn, sql, resultSetType, resultSetConcurrency); } public TesterCallableStatement(final Connection conn, final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { super(conn, sql, resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public Array getArray(final int i) throws SQLException { return null; } @Override public Array getArray(final String parameterName) throws SQLException { return null; } @Override public BigDecimal getBigDecimal(final int parameterIndex) throws SQLException { return null; } /** * @deprecated See {@link CallableStatement#getBigDecimal(int,int)}. */ @Deprecated @Override public BigDecimal getBigDecimal(final int parameterIndex, final int scale) throws SQLException { return null; } @Override public BigDecimal getBigDecimal(final String parameterName) throws SQLException { return null; } @Override public Blob getBlob(final int i) throws SQLException { return null; } @Override public Blob getBlob(final String parameterName) throws SQLException { return null; } @Override public boolean getBoolean(final int parameterIndex) throws SQLException { return false; } @Override public boolean getBoolean(final String parameterName) throws SQLException { return false; } @Override public byte getByte(final int parameterIndex) throws SQLException { return 0; } @Override public byte getByte(final String parameterName) throws SQLException { return 0; } @Override public byte[] getBytes(final int parameterIndex) throws SQLException { return new byte[0]; } @Override public byte[] getBytes(final String parameterName) throws SQLException { return new byte[0]; } @Override public Reader getCharacterStream(final int parameterIndex) throws SQLException { return null; } @Override public Reader getCharacterStream(final String parameterName) throws SQLException { return null; } @Override public Clob getClob(final int i) throws SQLException { return null; } @Override public Clob getClob(final String parameterName) throws SQLException { return null; } @Override public Date getDate(final int parameterIndex) throws SQLException { return null; } @Override public Date getDate(final int parameterIndex, final Calendar cal) throws SQLException { return null; } @Override public Date getDate(final String parameterName) throws SQLException { return null; } @Override public Date getDate(final String parameterName, final Calendar cal) throws SQLException { return null; } @Override public double getDouble(final int parameterIndex) throws SQLException { return 0; } @Override public double getDouble(final String parameterName) throws SQLException { return 0; } @Override public float getFloat(final int parameterIndex) throws SQLException { return 0; } @Override public float getFloat(final String parameterName) throws SQLException { return 0; } @Override public int getInt(final int parameterIndex) throws SQLException { return 0; } @Override public int getInt(final String parameterName) throws SQLException { return 0; } @Override public long getLong(final int parameterIndex) throws SQLException { return 0; } @Override public long getLong(final String parameterName) throws SQLException { return 0; } @Override public Reader getNCharacterStream(final int parameterIndex) throws SQLException { return null; } @Override public Reader getNCharacterStream(final String parameterName) throws SQLException { return null; } @Override public NClob getNClob(final int parameterIndex) throws SQLException { return null; } @Override public NClob getNClob(final String parameterName) throws SQLException { return null; } @Override public String getNString(final int parameterIndex) throws SQLException { return null; } @Override public String getNString(final String parameterName) throws SQLException { return null; } @Override public Object getObject(final int parameterIndex) throws SQLException { return null; } @Override public T getObject(final int parameterIndex, final Class type) throws SQLException { return null; } @Override public Object getObject(final int i, final Map> map) throws SQLException { return null; } @Override public Object getObject(final String parameterName) throws SQLException { return null; } @Override public T getObject(final String parameterName, final Class type) throws SQLException { return null; } @Override public Object getObject(final String parameterName, final Map> map) throws SQLException { return null; } @Override public Ref getRef(final int i) throws SQLException { return null; } @Override public Ref getRef(final String parameterName) throws SQLException { return null; } @Override public RowId getRowId(final int parameterIndex) throws SQLException { return null; } @Override public RowId getRowId(final String parameterName) throws SQLException { return null; } @Override public short getShort(final int parameterIndex) throws SQLException { return 0; } @Override public short getShort(final String parameterName) throws SQLException { return 0; } @Override public SQLXML getSQLXML(final int parameterIndex) throws SQLException { return null; } @Override public SQLXML getSQLXML(final String parameterName) throws SQLException { return null; } @Override public String getString(final int parameterIndex) throws SQLException { return null; } @Override public String getString(final String parameterName) throws SQLException { return null; } @Override public Time getTime(final int parameterIndex) throws SQLException { return null; } @Override public Time getTime(final int parameterIndex, final Calendar cal) throws SQLException { return null; } @Override public Time getTime(final String parameterName) throws SQLException { return null; } @Override public Time getTime(final String parameterName, final Calendar cal) throws SQLException { return null; } @Override public Timestamp getTimestamp(final int parameterIndex) throws SQLException { return null; } @Override public Timestamp getTimestamp(final int parameterIndex, final Calendar cal) throws SQLException { return null; } @Override public Timestamp getTimestamp(final String parameterName) throws SQLException { return null; } @Override public Timestamp getTimestamp(final String parameterName, final Calendar cal) throws SQLException { return null; } @Override public URL getURL(final int parameterIndex) throws SQLException { return null; } @Override public URL getURL(final String parameterName) throws SQLException { return null; } @Override public void registerOutParameter(final int parameterIndex, final int sqlType) throws SQLException { } @Override public void registerOutParameter(final int parameterIndex, final int sqlType, final int scale) throws SQLException { } @Override public void registerOutParameter(final int paramIndex, final int sqlType, final String typeName) throws SQLException { } @Override public void registerOutParameter(final int parameterIndex, final SQLType sqlType) throws SQLException { // Do nothing } @Override public void registerOutParameter(final int parameterIndex, final SQLType sqlType, final int scale) throws SQLException { // Do nothing } @Override public void registerOutParameter(final int parameterIndex, final SQLType sqlType, final String typeName) throws SQLException { // Do nothing } @Override public void registerOutParameter(final String parameterName, final int sqlType) throws SQLException { } @Override public void registerOutParameter(final String parameterName, final int sqlType, final int scale) throws SQLException { } @Override public void registerOutParameter(final String parameterName, final int sqlType, final String typeName) throws SQLException { } @Override public void registerOutParameter(final String parameterName, final SQLType sqlType) throws SQLException { // Do nothing } @Override public void registerOutParameter(final String parameterName, final SQLType sqlType, final int scale) throws SQLException { // Do nothing } @Override public void registerOutParameter(final String parameterName, final SQLType sqlType, final String typeName) throws SQLException { // Do nothing } @Override public void setAsciiStream(final String parameterName, final InputStream inputStream) throws SQLException { } @Override public void setAsciiStream(final String parameterName, final InputStream x, final int length) throws SQLException { } @Override public void setAsciiStream(final String parameterName, final InputStream inputStream, final long length) throws SQLException { } @Override public void setBigDecimal(final String parameterName, final BigDecimal x) throws SQLException { } @Override public void setBinaryStream(final String parameterName, final InputStream inputStream) throws SQLException { } @Override public void setBinaryStream(final String parameterName, final InputStream x, final int length) throws SQLException { } @Override public void setBinaryStream(final String parameterName, final InputStream inputStream, final long length) throws SQLException { } @Override public void setBlob(final String parameterName, final Blob blob) throws SQLException { } @Override public void setBlob(final String parameterName, final InputStream inputStream) throws SQLException { } @Override public void setBlob(final String parameterName, final InputStream inputStream, final long length) throws SQLException { } @Override public void setBoolean(final String parameterName, final boolean x) throws SQLException { } @Override public void setByte(final String parameterName, final byte x) throws SQLException { } @Override public void setBytes(final String parameterName, final byte[] x) throws SQLException { } @Override public void setCharacterStream(final String parameterName, final Reader reader) throws SQLException { } @Override public void setCharacterStream(final String parameterName, final Reader reader, final int length) throws SQLException { } @Override public void setCharacterStream(final String parameterName, final Reader reader, final long length) throws SQLException { } @Override public void setClob(final String parameterName, final Clob clob) throws SQLException { } @Override public void setClob(final String parameterName, final Reader reader) throws SQLException { } @Override public void setClob(final String parameterName, final Reader reader, final long length) throws SQLException { } @Override public void setDate(final String parameterName, final Date x) throws SQLException { } @Override public void setDate(final String parameterName, final Date x, final Calendar cal) throws SQLException { } @Override public void setDouble(final String parameterName, final double x) throws SQLException { } @Override public void setFloat(final String parameterName, final float x) throws SQLException { } @Override public void setInt(final String parameterName, final int x) throws SQLException { } @Override public void setLong(final String parameterName, final long x) throws SQLException { } @Override public void setNCharacterStream(final String parameterName, final Reader reader) throws SQLException { } @Override public void setNCharacterStream(final String parameterName, final Reader reader, final long length) throws SQLException { } @Override public void setNClob(final String parameterName, final NClob value) throws SQLException { } @Override public void setNClob(final String parameterName, final Reader reader) throws SQLException { } @Override public void setNClob(final String parameterName, final Reader reader, final long length) throws SQLException { } @Override public void setNString(final String parameterName, final String value) throws SQLException { } @Override public void setNull(final String parameterName, final int sqlType) throws SQLException { } @Override public void setNull(final String parameterName, final int sqlType, final String typeName) throws SQLException { } @Override public void setObject(final String parameterName, final Object x) throws SQLException { } @Override public void setObject(final String parameterName, final Object x, final int targetSqlType) throws SQLException { } @Override public void setObject(final String parameterName, final Object x, final int targetSqlType, final int scale) throws SQLException { } @Override public void setObject(final String parameterName, final Object x, final SQLType targetSqlType) throws SQLException { // Do nothing } @Override public void setObject(final String parameterName, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { // Do nothing } @Override public void setRowId(final String parameterName, final RowId value) throws SQLException { } @Override public void setShort(final String parameterName, final short x) throws SQLException { } @Override public void setSQLXML(final String parameterName, final SQLXML value) throws SQLException { } @Override public void setString(final String parameterName, final String x) throws SQLException { } @Override public void setTime(final String parameterName, final Time x) throws SQLException { } @Override public void setTime(final String parameterName, final Time x, final Calendar cal) throws SQLException { } @Override public void setTimestamp(final String parameterName, final Timestamp x) throws SQLException { } @Override public void setTimestamp(final String parameterName, final Timestamp x, final Calendar cal) throws SQLException { } @Override public void setURL(final String parameterName, final URL val) throws SQLException { } @Override public boolean wasNull() throws SQLException { return false; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TesterClassLoader.java000066400000000000000000000026771447311732500327270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.util.HashSet; import java.util.Set; /** * Simple class loader that just records the classes it was asked to load. */ public class TesterClassLoader extends ClassLoader { private final Set loadedClasses = new HashSet<>(); public boolean didLoad(final String className) { return loadedClasses.contains(className); } @Override protected synchronized Class loadClass(final String name, final boolean resolve) throws ClassNotFoundException { final Class clazz = super.loadClass(name, resolve); loadedClasses.add(name); return clazz; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TesterConnection.java000066400000000000000000000307621447311732500326260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Statement; import java.sql.Struct; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; /** * A dummy {@link Connection}, for testing purposes. */ public class TesterConnection extends AbandonedTrace implements Connection { protected boolean _open = true; protected boolean _aborted; protected boolean _autoCommit = true; protected int _transactionIsolation = 1; protected final DatabaseMetaData _metaData = new TesterDatabaseMetaData(); protected String _catalog; protected String schema; protected Map> _typeMap; protected boolean _readOnly; protected SQLWarning warnings; protected final String userName; protected Exception failure; protected boolean sqlExceptionOnClose; TesterConnection(final String userName, @SuppressWarnings("unused") final String password) { this.userName = userName; } @Override public void abort(final Executor executor) throws SQLException { checkFailure(); _aborted = true; _open = false; } protected void checkFailure() throws SQLException { if (failure != null) { if (failure instanceof SQLException) { throw (SQLException) failure; } throw new SQLException("TesterConnection failure", failure); } } protected void checkOpen() throws SQLException { if (!_open) { throw new SQLException("Connection is closed."); } checkFailure(); } @Override public void clearWarnings() throws SQLException { checkOpen(); warnings = null; } @Override public void close() throws SQLException { checkFailure(); _open = false; } @Override public void commit() throws SQLException { checkOpen(); if (isReadOnly()) { throw new SQLException("Cannot commit a readonly connection"); } } @Override public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { throw new SQLException("Not implemented."); } @Override public Blob createBlob() throws SQLException { throw new SQLException("Not implemented."); } @Override public Clob createClob() throws SQLException { throw new SQLException("Not implemented."); } @Override public NClob createNClob() throws SQLException { throw new SQLException("Not implemented."); } @Override public SQLXML createSQLXML() throws SQLException { throw new SQLException("Not implemented."); } @Override public Statement createStatement() throws SQLException { checkOpen(); return new TesterStatement(this); } @Override public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); return new TesterStatement(this); } @Override public Statement createStatement(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { return createStatement(); } @Override public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { throw new SQLException("Not implemented."); } @Override public boolean getAutoCommit() throws SQLException { checkOpen(); return _autoCommit; } @Override public String getCatalog() throws SQLException { checkOpen(); return _catalog; } @Override public Properties getClientInfo() throws SQLException { throw new SQLException("Not implemented."); } @Override public String getClientInfo(final String name) throws SQLException { throw new SQLException("Not implemented."); } @Override public int getHoldability() throws SQLException { throw new SQLException("Not implemented."); } @Override public DatabaseMetaData getMetaData() throws SQLException { checkOpen(); return _metaData; } @Override public int getNetworkTimeout() throws SQLException { throw new SQLException("Not implemented."); } @Override public String getSchema() throws SQLException { checkOpen(); return schema; } @Override public int getTransactionIsolation() throws SQLException { checkOpen(); return _transactionIsolation; } @Override public Map> getTypeMap() throws SQLException { checkOpen(); return _typeMap; } public String getUserName() { return this.userName; } @Override public SQLWarning getWarnings() throws SQLException { checkOpen(); return warnings; } public boolean isAborted() throws SQLException { checkFailure(); return _aborted; } @Override public boolean isClosed() throws SQLException { checkFailure(); return !_open; } @Override public boolean isReadOnly() throws SQLException { checkOpen(); return _readOnly; } public boolean isSqlExceptionOnClose() { return sqlExceptionOnClose; } @Override public boolean isValid(final int timeout) throws SQLException { return _open; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { throw new SQLException("Not implemented."); } @Override public String nativeSQL(final String sql) throws SQLException { checkOpen(); return sql; } @Override public CallableStatement prepareCall(final String sql) throws SQLException { checkOpen(); if ("warning".equals(sql)) { setWarnings(new SQLWarning("warning in prepareCall")); } return new TesterCallableStatement(this, sql); } @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); return new TesterCallableStatement(this, sql, resultSetType, resultSetConcurrency); } @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); return new TesterCallableStatement(this, sql, resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public PreparedStatement prepareStatement(final String sql) throws SQLException { checkOpen(); if ("null".equals(sql)) { return null; } if ("invalid".equals(sql)) { throw new SQLException("invalid query"); } if ("broken".equals(sql)) { throw new SQLException("broken connection"); } return new TesterPreparedStatement(this, sql); } @Override public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); return new TesterPreparedStatement(this, sql, autoGeneratedKeys); } @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); return new TesterPreparedStatement(this, sql, resultSetType, resultSetConcurrency); } @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); return new TesterPreparedStatement(this, sql, resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { return new TesterPreparedStatement(this, sql, columnIndexes); } @Override public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { return new TesterPreparedStatement(this, sql, columnNames); } @Override public void releaseSavepoint(final java.sql.Savepoint savepoint) throws SQLException { throw new SQLException("Not implemented."); } @Override public void rollback() throws SQLException { checkOpen(); if (isReadOnly()) { throw new SQLException("Cannot rollback a readonly connection"); } if (getAutoCommit()) { throw new SQLException("Cannot rollback a connection in auto-commit"); } } @Override public void rollback(final java.sql.Savepoint savepoint) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setAutoCommit(final boolean autoCommit) throws SQLException { checkOpen(); _autoCommit = autoCommit; } @Override public void setCatalog(final String catalog) throws SQLException { checkOpen(); _catalog = catalog; } @Override public void setClientInfo(final Properties properties) throws SQLClientInfoException { throw new SQLClientInfoException(); } @Override public void setClientInfo(final String name, final String value) throws SQLClientInfoException { throw new SQLClientInfoException(); } public void setFailure(final Exception failure) { this.failure = failure; } @Override public void setHoldability(final int holdability) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setReadOnly(final boolean readOnly) throws SQLException { checkOpen(); _readOnly = readOnly; } @Override public java.sql.Savepoint setSavepoint() throws SQLException { throw new SQLException("Not implemented."); } @Override public java.sql.Savepoint setSavepoint(final String name) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setSchema(final String schema) throws SQLException { checkOpen(); this.schema= schema; } public void setSqlExceptionOnClose(final boolean sqlExceptionOnClose) { this.sqlExceptionOnClose = sqlExceptionOnClose; } @Override public void setTransactionIsolation(final int level) throws SQLException { checkOpen(); _transactionIsolation = level; } @Override public void setTypeMap(final Map> map) throws SQLException { checkOpen(); _typeMap = map; } public void setWarnings(final SQLWarning warning) { this.warnings = warning; } @Override public T unwrap(final Class iface) throws SQLException { throw new SQLException("Not implemented."); } } TesterConnectionFactory.java000066400000000000000000000046651447311732500341020ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; import java.util.Properties; /** * Dummy {@link ConnectionFactory} for testing purpose. */ public class TesterConnectionFactory implements ConnectionFactory { private final String connectionString; private final Driver driver; private final Properties properties; /** * Constructs a connection factory for a given Driver. * * @param driver The Driver. * @param connectString The connection string. * @param properties The connection properties. */ public TesterConnectionFactory(final Driver driver, final String connectString, final Properties properties) { this.driver = driver; this.connectionString = connectString; this.properties = properties; } @Override public Connection createConnection() throws SQLException { final Connection conn = driver.connect(connectionString, properties); doSomething(conn); return conn; } private void doSomething(final Connection conn) { // do something } /** * @return The connection String. */ public String getConnectionString() { return connectionString; } /** * @return The Driver. */ public Driver getDriver() { return driver; } /** * @return The Properties. */ public Properties getProperties() { return properties; } @Override public String toString() { return this.getClass().getName() + " [" + driver + ";" + connectionString + ";" + properties + "]"; } } TesterDatabaseMetaData.java000066400000000000000000000543341447311732500335560ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.RowIdLifetime; import java.sql.SQLException; /** * Dummy {@link DatabaseMetaData} for testing purposes. Implements only those * methods required by the test cases. */ public class TesterDatabaseMetaData implements DatabaseMetaData { @Override public boolean allProceduresAreCallable() throws SQLException { return false; } @Override public boolean allTablesAreSelectable() throws SQLException { return false; } @Override public boolean autoCommitFailureClosesAllResultSets() throws SQLException { return false; } @Override public boolean dataDefinitionCausesTransactionCommit() throws SQLException { return false; } @Override public boolean dataDefinitionIgnoredInTransactions() throws SQLException { return false; } @Override public boolean deletesAreDetected(final int type) throws SQLException { return false; } @Override public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { return false; } @Override public boolean generatedKeyAlwaysReturned() throws SQLException { return false; } @Override public ResultSet getAttributes(final String catalog, final String schemaPattern, final String typeNamePattern, final String attributeNamePattern) throws SQLException { return null; } @Override public ResultSet getBestRowIdentifier(final String catalog, final String schema, final String table, final int scope, final boolean nullable) throws SQLException { return null; } @Override public ResultSet getCatalogs() throws SQLException { return null; } @Override public String getCatalogSeparator() throws SQLException { return null; } @Override public String getCatalogTerm() throws SQLException { return null; } @Override public ResultSet getClientInfoProperties() throws SQLException { return null; } @Override public ResultSet getColumnPrivileges(final String catalog, final String schema, final String table, final String columnNamePattern) throws SQLException { return null; } @Override public ResultSet getColumns(final String catalog, final String schemaPattern, final String tableNamePattern, final String columnNamePattern) throws SQLException { return null; } @Override public Connection getConnection() throws SQLException { return null; } @Override public ResultSet getCrossReference(final String parentCatalog, final String parentSchema, final String parentTable, final String foreignCatalog, final String foreignSchema, final String foreignTable) throws SQLException { return null; } @Override public int getDatabaseMajorVersion() throws SQLException { return 0; } @Override public int getDatabaseMinorVersion() throws SQLException { return 0; } @Override public String getDatabaseProductName() throws SQLException { return null; } @Override public String getDatabaseProductVersion() throws SQLException { return null; } @Override public int getDefaultTransactionIsolation() throws SQLException { return 0; } @Override public int getDriverMajorVersion() { return 0; } @Override public int getDriverMinorVersion() { return 0; } @Override public String getDriverName() throws SQLException { return null; } @Override public String getDriverVersion() throws SQLException { return null; } @Override public ResultSet getExportedKeys(final String catalog, final String schema, final String table) throws SQLException { return null; } @Override public String getExtraNameCharacters() throws SQLException { return null; } @Override public ResultSet getFunctionColumns(final String catalog, final String schemaPattern, final String functionNamePattern, final String columnNamePattern) throws SQLException { return null; } @Override public ResultSet getFunctions(final String catalog, final String schemaPattern, final String functionNamePattern) throws SQLException { return null; } @Override public String getIdentifierQuoteString() throws SQLException { return null; } @Override public ResultSet getImportedKeys(final String catalog, final String schema, final String table) throws SQLException { return null; } @Override public ResultSet getIndexInfo(final String catalog, final String schema, final String table, final boolean unique, final boolean approximate) throws SQLException { return null; } @Override public int getJDBCMajorVersion() throws SQLException { return 0; } @Override public int getJDBCMinorVersion() throws SQLException { return 0; } @Override public int getMaxBinaryLiteralLength() throws SQLException { return 0; } @Override public int getMaxCatalogNameLength() throws SQLException { return 0; } @Override public int getMaxCharLiteralLength() throws SQLException { return 0; } @Override public int getMaxColumnNameLength() throws SQLException { return 0; } @Override public int getMaxColumnsInGroupBy() throws SQLException { return 0; } @Override public int getMaxColumnsInIndex() throws SQLException { return 0; } @Override public int getMaxColumnsInOrderBy() throws SQLException { return 0; } @Override public int getMaxColumnsInSelect() throws SQLException { return 0; } @Override public int getMaxColumnsInTable() throws SQLException { return 0; } @Override public int getMaxConnections() throws SQLException { return 0; } @Override public int getMaxCursorNameLength() throws SQLException { return 0; } @Override public int getMaxIndexLength() throws SQLException { return 0; } @Override public int getMaxProcedureNameLength() throws SQLException { return 0; } @Override public int getMaxRowSize() throws SQLException { return 0; } @Override public int getMaxSchemaNameLength() throws SQLException { return 0; } @Override public int getMaxStatementLength() throws SQLException { return 0; } @Override public int getMaxStatements() throws SQLException { return 0; } @Override public int getMaxTableNameLength() throws SQLException { return 0; } @Override public int getMaxTablesInSelect() throws SQLException { return 0; } @Override public int getMaxUserNameLength() throws SQLException { return 0; } @Override public String getNumericFunctions() throws SQLException { return null; } @Override public ResultSet getPrimaryKeys(final String catalog, final String schema, final String table) throws SQLException { return null; } @Override public ResultSet getProcedureColumns(final String catalog, final String schemaPattern, final String procedureNamePattern, final String columnNamePattern) throws SQLException { return null; } @Override public ResultSet getProcedures(final String catalog, final String schemaPattern, final String procedureNamePattern) throws SQLException { return null; } @Override public String getProcedureTerm() throws SQLException { return null; } @Override public ResultSet getPseudoColumns(final String catalog, final String schemaPattern, final String tableNamePattern, final String columnNamePattern) throws SQLException { return null; } @Override public int getResultSetHoldability() throws SQLException { return 0; } @Override public RowIdLifetime getRowIdLifetime() throws SQLException { return null; } @Override public ResultSet getSchemas() throws SQLException { return new TesterResultSet(null); } @Override public ResultSet getSchemas(final String catalog, final String schemaPattern) throws SQLException { return null; } @Override public String getSchemaTerm() throws SQLException { return null; } @Override public String getSearchStringEscape() throws SQLException { return null; } @Override public String getSQLKeywords() throws SQLException { return null; } @Override public int getSQLStateType() throws SQLException { return 0; } @Override public String getStringFunctions() throws SQLException { return null; } @Override public ResultSet getSuperTables(final String catalog, final String schemaPattern, final String tableNamePattern) throws SQLException { return null; } @Override public ResultSet getSuperTypes(final String catalog, final String schemaPattern, final String typeNamePattern) throws SQLException { return null; } @Override public String getSystemFunctions() throws SQLException { return null; } @Override public ResultSet getTablePrivileges(final String catalog, final String schemaPattern, final String tableNamePattern) throws SQLException { return null; } @Override public ResultSet getTables(final String catalog, final String schemaPattern, final String tableNamePattern, final String[] types) throws SQLException { return null; } @Override public ResultSet getTableTypes() throws SQLException { return null; } @Override public String getTimeDateFunctions() throws SQLException { return null; } @Override public ResultSet getTypeInfo() throws SQLException { return null; } @Override public ResultSet getUDTs(final String catalog, final String schemaPattern, final String typeNamePattern, final int[] types) throws SQLException { return null; } @Override public String getURL() throws SQLException { return null; } @Override public String getUserName() throws SQLException { return null; } @Override public ResultSet getVersionColumns(final String catalog, final String schema, final String table) throws SQLException { return null; } @Override public boolean insertsAreDetected(final int type) throws SQLException { return false; } @Override public boolean isCatalogAtStart() throws SQLException { return false; } @Override public boolean isReadOnly() throws SQLException { return false; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { return false; } @Override public boolean locatorsUpdateCopy() throws SQLException { return false; } @Override public boolean nullPlusNonNullIsNull() throws SQLException { return false; } @Override public boolean nullsAreSortedAtEnd() throws SQLException { return false; } @Override public boolean nullsAreSortedAtStart() throws SQLException { return false; } @Override public boolean nullsAreSortedHigh() throws SQLException { return false; } @Override public boolean nullsAreSortedLow() throws SQLException { return false; } @Override public boolean othersDeletesAreVisible(final int type) throws SQLException { return false; } @Override public boolean othersInsertsAreVisible(final int type) throws SQLException { return false; } @Override public boolean othersUpdatesAreVisible(final int type) throws SQLException { return false; } @Override public boolean ownDeletesAreVisible(final int type) throws SQLException { return false; } @Override public boolean ownInsertsAreVisible(final int type) throws SQLException { return false; } @Override public boolean ownUpdatesAreVisible(final int type) throws SQLException { return false; } @Override public boolean storesLowerCaseIdentifiers() throws SQLException { return false; } @Override public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { return false; } @Override public boolean storesMixedCaseIdentifiers() throws SQLException { return false; } @Override public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { return false; } @Override public boolean storesUpperCaseIdentifiers() throws SQLException { return false; } @Override public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { return false; } @Override public boolean supportsAlterTableWithAddColumn() throws SQLException { return false; } @Override public boolean supportsAlterTableWithDropColumn() throws SQLException { return false; } @Override public boolean supportsANSI92EntryLevelSQL() throws SQLException { return false; } @Override public boolean supportsANSI92FullSQL() throws SQLException { return false; } @Override public boolean supportsANSI92IntermediateSQL() throws SQLException { return false; } @Override public boolean supportsBatchUpdates() throws SQLException { return false; } @Override public boolean supportsCatalogsInDataManipulation() throws SQLException { return false; } @Override public boolean supportsCatalogsInIndexDefinitions() throws SQLException { return false; } @Override public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { return false; } @Override public boolean supportsCatalogsInProcedureCalls() throws SQLException { return false; } @Override public boolean supportsCatalogsInTableDefinitions() throws SQLException { return false; } @Override public boolean supportsColumnAliasing() throws SQLException { return false; } @Override public boolean supportsConvert() throws SQLException { return false; } @Override public boolean supportsConvert(final int fromType, final int toType) throws SQLException { return false; } @Override public boolean supportsCoreSQLGrammar() throws SQLException { return false; } @Override public boolean supportsCorrelatedSubqueries() throws SQLException { return false; } @Override public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { return false; } @Override public boolean supportsDataManipulationTransactionsOnly() throws SQLException { return false; } @Override public boolean supportsDifferentTableCorrelationNames() throws SQLException { return false; } @Override public boolean supportsExpressionsInOrderBy() throws SQLException { return false; } @Override public boolean supportsExtendedSQLGrammar() throws SQLException { return false; } @Override public boolean supportsFullOuterJoins() throws SQLException { return false; } @Override public boolean supportsGetGeneratedKeys() throws SQLException { return false; } @Override public boolean supportsGroupBy() throws SQLException { return false; } @Override public boolean supportsGroupByBeyondSelect() throws SQLException { return false; } @Override public boolean supportsGroupByUnrelated() throws SQLException { return false; } @Override public boolean supportsIntegrityEnhancementFacility() throws SQLException { return false; } @Override public boolean supportsLikeEscapeClause() throws SQLException { return false; } @Override public boolean supportsLimitedOuterJoins() throws SQLException { return false; } @Override public boolean supportsMinimumSQLGrammar() throws SQLException { return false; } @Override public boolean supportsMixedCaseIdentifiers() throws SQLException { return false; } @Override public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { return false; } @Override public boolean supportsMultipleOpenResults() throws SQLException { return false; } @Override public boolean supportsMultipleResultSets() throws SQLException { return false; } @Override public boolean supportsMultipleTransactions() throws SQLException { return false; } @Override public boolean supportsNamedParameters() throws SQLException { return false; } @Override public boolean supportsNonNullableColumns() throws SQLException { return false; } @Override public boolean supportsOpenCursorsAcrossCommit() throws SQLException { return false; } @Override public boolean supportsOpenCursorsAcrossRollback() throws SQLException { return false; } @Override public boolean supportsOpenStatementsAcrossCommit() throws SQLException { return false; } @Override public boolean supportsOpenStatementsAcrossRollback() throws SQLException { return false; } @Override public boolean supportsOrderByUnrelated() throws SQLException { return false; } @Override public boolean supportsOuterJoins() throws SQLException { return false; } @Override public boolean supportsPositionedDelete() throws SQLException { return false; } @Override public boolean supportsPositionedUpdate() throws SQLException { return false; } @Override public boolean supportsResultSetConcurrency(final int type, final int concurrency) throws SQLException { return false; } @Override public boolean supportsResultSetHoldability(final int holdability) throws SQLException { return false; } @Override public boolean supportsResultSetType(final int type) throws SQLException { return false; } @Override public boolean supportsSavepoints() throws SQLException { return false; } @Override public boolean supportsSchemasInDataManipulation() throws SQLException { return false; } @Override public boolean supportsSchemasInIndexDefinitions() throws SQLException { return false; } @Override public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { return false; } @Override public boolean supportsSchemasInProcedureCalls() throws SQLException { return false; } @Override public boolean supportsSchemasInTableDefinitions() throws SQLException { return false; } @Override public boolean supportsSelectForUpdate() throws SQLException { return false; } @Override public boolean supportsStatementPooling() throws SQLException { return false; } @Override public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { return false; } @Override public boolean supportsStoredProcedures() throws SQLException { return false; } @Override public boolean supportsSubqueriesInComparisons() throws SQLException { return false; } @Override public boolean supportsSubqueriesInExists() throws SQLException { return false; } @Override public boolean supportsSubqueriesInIns() throws SQLException { return false; } @Override public boolean supportsSubqueriesInQuantifieds() throws SQLException { return false; } @Override public boolean supportsTableCorrelationNames() throws SQLException { return false; } @Override public boolean supportsTransactionIsolationLevel(final int level) throws SQLException { return false; } @Override public boolean supportsTransactions() throws SQLException { return false; } @Override public boolean supportsUnion() throws SQLException { return false; } @Override public boolean supportsUnionAll() throws SQLException { return false; } @Override public T unwrap(final Class iface) throws SQLException { return null; } @Override public boolean updatesAreDetected(final int type) throws SQLException { return false; } @Override public boolean usesLocalFilePerTable() throws SQLException { return false; } @Override public boolean usesLocalFiles() throws SQLException { return false; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TesterDriver.java000066400000000000000000000115221447311732500317530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Properties; import java.util.logging.Logger; /** * Mock object implementing the java.sql.Driver interface. * Returns TestConnection's from getConnection methods. * Valid user name, password combinations are: * * * * * * * *
userpassword
foobar
u1p1
u2p2
usernamepassword
*/ public class TesterDriver implements Driver { private static final Properties validUserPasswords = new Properties(); static { try { DriverManager.registerDriver(new TesterDriver()); } catch (final Exception e) { // ignore } validUserPasswords.put("foo", "bar"); validUserPasswords.put("u1", "p1"); validUserPasswords.put("u2", "p2"); validUserPasswords.put("userName", "password"); } private static final String CONNECT_STRING = "jdbc:apache:commons:testdriver"; // version numbers private static final int MAJOR_VERSION = 1; private static final int MINOR_VERSION = 0; /** * TesterDriver specific method to add users to the list of valid users */ public static void addUser(final String userName, final String password) { synchronized (validUserPasswords) { validUserPasswords.put(userName, password); } } @Override public boolean acceptsURL(final String url) throws SQLException { return url != null && url.startsWith(CONNECT_STRING); } private void assertValidUserPassword(final String userName, final String password) throws SQLException { if (userName == null){ throw new SQLException("user name cannot be null."); } synchronized (validUserPasswords) { final String realPassword = validUserPasswords.getProperty(userName); if (realPassword == null) { throw new SQLException(userName + " is not a valid user name."); } if (!realPassword.equals(password)) { throw new SQLException(password + " is not the correct password for " + userName + ". The correct password is " + realPassword); } } } @Override public Connection connect(final String url, final Properties info) throws SQLException { //return (acceptsURL(url) ? new TesterConnection() : null); Connection conn = null; if (acceptsURL(url)) { String userName = "test"; String password = "test"; if (info != null) { userName = info.getProperty(Constants.KEY_USER); password = info.getProperty(Constants.KEY_PASSWORD); if (userName == null) { final String[] parts = url.split(";"); userName = parts[1]; userName = userName.split("=")[1]; password = parts[2]; password = password.split("=")[1]; } assertValidUserPassword(userName, password); } conn = new TesterConnection(userName, password); } return conn; } @Override public int getMajorVersion() { return MAJOR_VERSION; } @Override public int getMinorVersion() { return MINOR_VERSION; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } @Override public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) { return new DriverPropertyInfo[0]; } @Override public boolean jdbcCompliant() { return true; } } TesterPreparedStatement.java000066400000000000000000000367741447311732500341100ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLType; import java.sql.SQLXML; import java.util.Calendar; /** * A dummy {@link PreparedStatement}, for testing purposes. */ public class TesterPreparedStatement extends TesterStatement implements PreparedStatement { private final ResultSetMetaData _resultSetMetaData = null; private String _sql; private String _catalog; private int _autoGeneratedKeys = 1; private int[] _columnIndexes; private String[] _columnNames; public TesterPreparedStatement(final Connection conn) { super(conn); try { _catalog = conn.getCatalog(); } catch (final SQLException e) { // Ignored } } public TesterPreparedStatement(final Connection conn, final String sql) { super(conn); _sql = sql; try { _catalog = conn.getCatalog(); } catch (final SQLException e) { // Ignored } } public TesterPreparedStatement(final Connection conn, final String sql, final int autoGeneratedKeys) { super(conn); _sql = sql; _autoGeneratedKeys = autoGeneratedKeys; try { _catalog = conn.getCatalog(); } catch (final SQLException e) { // Ignored } } public TesterPreparedStatement(final Connection conn, final String sql, final int resultSetType, final int resultSetConcurrency) { super(conn, resultSetType, resultSetConcurrency); _sql = sql; try { _catalog = conn.getCatalog(); } catch (final SQLException e) { // Ignored } } public TesterPreparedStatement(final Connection conn, final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { super(conn, resultSetType, resultSetConcurrency, resultSetHoldability); _sql = sql; try { _catalog = conn.getCatalog(); } catch (final SQLException e) { // Ignored } } public TesterPreparedStatement(final Connection conn, final String sql, final int[] columnIndexes) { super(conn); _sql = sql; _columnIndexes = columnIndexes; try { _catalog = conn.getCatalog(); } catch (final SQLException e) { // Ignored } } public TesterPreparedStatement(final Connection conn, final String sql, final String[] columnNames) { super(conn); _sql = sql; _columnNames = columnNames; try { _catalog = conn.getCatalog(); } catch (final SQLException e) { // Ignored } } @Override public void addBatch() throws SQLException { checkOpen(); } @Override public void clearParameters() throws SQLException { checkOpen(); } @Override public boolean execute() throws SQLException { checkOpen(); return true; } @Override public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); return true; } @Override public boolean execute(final String sl, final int[] columnIndexes) throws SQLException { checkOpen(); return true; } @Override public boolean execute(final String sql, final String[] columnNames) throws SQLException { checkOpen(); return true; } @Override public long executeLargeUpdate() throws SQLException { checkOpen(); return _rowsUpdated; } @Override public long executeLargeUpdate(final String sql) throws SQLException { checkOpen(); return _rowsUpdated; } @Override public long executeLargeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); return 0; } @Override public long executeLargeUpdate(final String sql, final int[] columnIndexes) throws SQLException { checkOpen(); return 0; } @Override public long executeLargeUpdate(final String sql, final String[] columnNames) throws SQLException { checkOpen(); return 0; } @Override public ResultSet executeQuery() throws SQLException { checkOpen(); if ("null".equals(_sql)) { return null; } if (_queryTimeout > 0 && _queryTimeout < 5) { // Simulate timeout if queryTimout is set to less than 5 seconds throw new SQLException("query timeout"); } return new TesterResultSet(this, _resultSetType, _resultSetConcurrency); } @Override public ResultSet executeQuery(final String sql) throws SQLException { checkOpen(); if ("null".equals(sql)) { return null; } return new TesterResultSet(this, _resultSetType, _resultSetConcurrency); } @Override public int executeUpdate() throws SQLException { checkOpen(); return (int) _rowsUpdated; } @Override public int executeUpdate(final String sql) throws SQLException { checkOpen(); return (int) _rowsUpdated; } @Override public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); return 0; } @Override public int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException { checkOpen(); return 0; } @Override public int executeUpdate(final String sql, final String[] columnNames) throws SQLException { checkOpen(); return 0; } public int getAutoGeneratedKeys() { return _autoGeneratedKeys; } public String getCatalog() { return _catalog; } public int[] getColumnIndexes() { return _columnIndexes; } public String[] getColumnNames() { return _columnNames; } @Override public ResultSet getGeneratedKeys() throws SQLException { return new TesterResultSet(this, _resultSetType, _resultSetConcurrency); } @Override public ResultSetMetaData getMetaData() throws SQLException { checkOpen(); return _resultSetMetaData; } @Override public boolean getMoreResults(final int current) throws SQLException { throw new SQLException("Not implemented."); } @Override public java.sql.ParameterMetaData getParameterMetaData() throws SQLException { throw new SQLException("Not implemented."); } /** for junit test only */ public String getSql() { return _sql; } @Override public void setArray (final int i, final Array x) throws SQLException { checkOpen(); } @Override public void setAsciiStream(final int parameterIndex, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setAsciiStream(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setAsciiStream(final int parameterIndex, final java.io.InputStream x, final int length) throws SQLException { checkOpen(); } @Override public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException { checkOpen(); } @Override public void setBinaryStream(final int parameterIndex, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setBinaryStream(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setBinaryStream(final int parameterIndex, final java.io.InputStream x, final int length) throws SQLException { checkOpen(); } @Override public void setBlob (final int i, final Blob x) throws SQLException { checkOpen(); } @Override public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setBlob(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setBoolean(final int parameterIndex, final boolean x) throws SQLException { checkOpen(); } @Override public void setByte(final int parameterIndex, final byte x) throws SQLException { checkOpen(); } @Override public void setBytes(final int parameterIndex, final byte[] x) throws SQLException { checkOpen(); } @Override public void setCharacterStream(final int parameterIndex, final java.io.Reader reader, final int length) throws SQLException { checkOpen(); } @Override public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setCharacterStream(final int parameterIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setClob (final int i, final Clob x) throws SQLException { checkOpen(); } @Override public void setClob(final int parameterIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setDate(final int parameterIndex, final java.sql.Date x) throws SQLException { checkOpen(); } @Override public void setDate(final int parameterIndex, final java.sql.Date x, final Calendar cal) throws SQLException { checkOpen(); } @Override public void setDouble(final int parameterIndex, final double x) throws SQLException { checkOpen(); } @Override public void setFloat(final int parameterIndex, final float x) throws SQLException { checkOpen(); } @Override public void setInt(final int parameterIndex, final int x) throws SQLException { checkOpen(); } @Override public void setLong(final int parameterIndex, final long x) throws SQLException { checkOpen(); } @Override public void setNCharacterStream(final int parameterIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setNCharacterStream(final int parameterIndex, final Reader value, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setNClob(final int parameterIndex, final NClob value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setNClob(final int parameterIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setNString(final int parameterIndex, final String value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setNull(final int parameterIndex, final int sqlType) throws SQLException { checkOpen(); } @Override public void setNull (final int paramIndex, final int sqlType, final String typeName) throws SQLException { checkOpen(); } @Override public void setObject(final int parameterIndex, final Object x) throws SQLException { checkOpen(); } @Override public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException { checkOpen(); } @Override public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale) throws SQLException { checkOpen(); } @Override public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType) throws SQLException { checkOpen(); } @Override public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { checkOpen(); } @Override public void setRef (final int i, final Ref x) throws SQLException { checkOpen(); } @Override public void setRowId(final int parameterIndex, final RowId value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setShort(final int parameterIndex, final short x) throws SQLException { checkOpen(); } @Override public void setSQLXML(final int parameterIndex, final SQLXML value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setString(final int parameterIndex, final String x) throws SQLException { checkOpen(); } @Override public void setTime(final int parameterIndex, final java.sql.Time x) throws SQLException { checkOpen(); } @Override public void setTime(final int parameterIndex, final java.sql.Time x, final Calendar cal) throws SQLException { checkOpen(); } @Override public void setTimestamp(final int parameterIndex, final java.sql.Timestamp x) throws SQLException { checkOpen(); } @Override public void setTimestamp(final int parameterIndex, final java.sql.Timestamp x, final Calendar cal) throws SQLException { checkOpen(); } /** @deprecated */ @Deprecated @Override public void setUnicodeStream(final int parameterIndex, final java.io.InputStream x, final int length) throws SQLException { checkOpen(); } @Override public void setURL(final int parameterIndex, final java.net.URL x) throws SQLException { throw new SQLException("Not implemented."); } @Override public String toString() { return _sql; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TesterResultSet.java000066400000000000000000001014441447311732500324550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.NClob; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLType; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Statement; import java.util.Calendar; import java.util.Map; /** * A dummy {@link ResultSet}, for testing purposes. */ public class TesterResultSet extends AbandonedTrace implements ResultSet { protected int _type = ResultSet.TYPE_FORWARD_ONLY; protected int _concurrency = ResultSet.CONCUR_READ_ONLY; protected Object[][] _data; protected int _currentRow = -1; protected Statement _statement; protected int _rowsLeft = 2; protected boolean _open = true; protected boolean _sqlExceptionOnClose; public TesterResultSet(final Statement stmt) { _statement = stmt; } public TesterResultSet(final Statement stmt, final int type, final int concurrency) { _statement = stmt; _data = null; _type = type; _concurrency = concurrency; } public TesterResultSet(final Statement stmt, final Object[][] data) { _statement = stmt; _data = data; } @Override public boolean absolute(final int row) throws SQLException { checkOpen(); return false; } @Override public void afterLast() throws SQLException { checkOpen(); } @Override public void beforeFirst() throws SQLException { checkOpen(); } @Override public void cancelRowUpdates() throws SQLException { checkOpen(); } protected void checkOpen() throws SQLException { if (!_open) { throw new SQLException("ResultSet is closed."); } } @Override public void clearWarnings() throws SQLException { checkOpen(); } @Override public void close() throws SQLException { if (_sqlExceptionOnClose) { throw new SQLException("TestSQLExceptionOnClose"); } if (!_open) { return; } // Not all result sets are generated from statements eg DatabaseMetaData if (_statement != null) { ((TesterStatement) _statement)._resultSet = null; } _open = false; } @Override public void deleteRow() throws SQLException { checkOpen(); } @Override public int findColumn(final String columnName) throws SQLException { checkOpen(); return 1; } @Override public boolean first() throws SQLException { checkOpen(); return false; } @Override public Array getArray(final int i) throws SQLException { checkOpen(); return null; } @Override public Array getArray(final String colName) throws SQLException { checkOpen(); return null; } @Override public java.io.InputStream getAsciiStream(final int columnIndex) throws SQLException { checkOpen(); return null; } @Override public java.io.InputStream getAsciiStream(final String columnName) throws SQLException { checkOpen(); return null; } @Override public BigDecimal getBigDecimal(final int columnIndex) throws SQLException { checkOpen(); return new BigDecimal(columnIndex); } /** @deprecated */ @Deprecated @Override public BigDecimal getBigDecimal(final int columnIndex, final int scale) throws SQLException { checkOpen(); return new BigDecimal(columnIndex); } @Override public BigDecimal getBigDecimal(final String columnName) throws SQLException { checkOpen(); return new BigDecimal(columnName.hashCode()); } /** @deprecated */ @Deprecated @Override public BigDecimal getBigDecimal(final String columnName, final int scale) throws SQLException { checkOpen(); return new BigDecimal(columnName.hashCode()); } @Override public java.io.InputStream getBinaryStream(final int columnIndex) throws SQLException { checkOpen(); return null; } @Override public java.io.InputStream getBinaryStream(final String columnName) throws SQLException { checkOpen(); return null; } @Override public Blob getBlob(final int i) throws SQLException { checkOpen(); return null; } @Override public Blob getBlob(final String colName) throws SQLException { checkOpen(); return null; } @Override public boolean getBoolean(final int columnIndex) throws SQLException { checkOpen(); return true; } @Override public boolean getBoolean(final String columnName) throws SQLException { checkOpen(); return true; } @Override public byte getByte(final int columnIndex) throws SQLException { checkOpen(); return (byte) columnIndex; } @Override public byte getByte(final String columnName) throws SQLException { checkOpen(); return (byte) columnName.hashCode(); } @Override public byte[] getBytes(final int columnIndex) throws SQLException { checkOpen(); return new byte[] { (byte) columnIndex }; } @Override public byte[] getBytes(final String columnName) throws SQLException { checkOpen(); return columnName.getBytes(StandardCharsets.UTF_8); } @Override public java.io.Reader getCharacterStream(final int columnIndex) throws SQLException { checkOpen(); return null; } @Override public java.io.Reader getCharacterStream(final String columnName) throws SQLException { checkOpen(); return null; } @Override public Clob getClob(final int i) throws SQLException { checkOpen(); return null; } @Override public Clob getClob(final String colName) throws SQLException { checkOpen(); return null; } @Override public int getConcurrency() throws SQLException { return this._concurrency; } @Override public String getCursorName() throws SQLException { checkOpen(); return null; } @Override public java.sql.Date getDate(final int columnIndex) throws SQLException { checkOpen(); return null; } @Override public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws SQLException { checkOpen(); return null; } @Override public java.sql.Date getDate(final String columnName) throws SQLException { checkOpen(); return null; } @Override public java.sql.Date getDate(final String columnName, final Calendar cal) throws SQLException { checkOpen(); return null; } @Override public double getDouble(final int columnIndex) throws SQLException { checkOpen(); return columnIndex; } @Override public double getDouble(final String columnName) throws SQLException { checkOpen(); return columnName.hashCode(); } @Override public int getFetchDirection() throws SQLException { checkOpen(); return 1; } @Override public int getFetchSize() throws SQLException { checkOpen(); return 2; } @Override public float getFloat(final int columnIndex) throws SQLException { checkOpen(); return columnIndex; } @Override public float getFloat(final String columnName) throws SQLException { checkOpen(); return columnName.hashCode(); } @Override public int getHoldability() throws SQLException { throw new SQLException("Not implemented."); } @Override public int getInt(final int columnIndex) throws SQLException { checkOpen(); return (short) columnIndex; } @Override public int getInt(final String columnName) throws SQLException { checkOpen(); return columnName.hashCode(); } @Override public long getLong(final int columnIndex) throws SQLException { checkOpen(); return columnIndex; } @Override public long getLong(final String columnName) throws SQLException { checkOpen(); return columnName.hashCode(); } @Override public ResultSetMetaData getMetaData() throws SQLException { checkOpen(); return null; } @Override public Reader getNCharacterStream(final int columnIndex) throws SQLException { throw new SQLException("Not implemented."); } @Override public Reader getNCharacterStream(final String columnLabel) throws SQLException { throw new SQLException("Not implemented."); } @Override public NClob getNClob(final int columnIndex) throws SQLException { throw new SQLException("Not implemented."); } @Override public NClob getNClob(final String columnLabel) throws SQLException { throw new SQLException("Not implemented."); } @Override public String getNString(final int columnIndex) throws SQLException { throw new SQLException("Not implemented."); } @Override public String getNString(final String columnLabel) throws SQLException { throw new SQLException("Not implemented."); } @Override public Object getObject(final int columnIndex) throws SQLException { checkOpen(); if (_data != null) { return _data[_currentRow][columnIndex - 1]; } return new Object(); } @Override public T getObject(final int columnIndex, final Class type) throws SQLException { throw new SQLException("Not implemented."); } @Override public Object getObject(final int i, final Map> map) throws SQLException { checkOpen(); return new Object(); } @Override public Object getObject(final String columnName) throws SQLException { checkOpen(); return columnName; } @Override public T getObject(final String columnLabel, final Class type) throws SQLException { throw new SQLException("Not implemented."); } @Override public Object getObject(final String colName, final Map> map) throws SQLException { checkOpen(); return colName; } @Override public Ref getRef(final int i) throws SQLException { checkOpen(); return null; } @Override public Ref getRef(final String colName) throws SQLException { checkOpen(); return null; } @Override public int getRow() throws SQLException { checkOpen(); return 3 - _rowsLeft; } @Override public RowId getRowId(final int columnIndex) throws SQLException { throw new SQLException("Not implemented."); } @Override public RowId getRowId(final String columnLabel) throws SQLException { throw new SQLException("Not implemented."); } @Override public short getShort(final int columnIndex) throws SQLException { checkOpen(); return (short) columnIndex; } @Override public short getShort(final String columnName) throws SQLException { checkOpen(); return (short) columnName.hashCode(); } @Override public SQLXML getSQLXML(final int columnIndex) throws SQLException { throw new SQLException("Not implemented."); } @Override public SQLXML getSQLXML(final String columnLabel) throws SQLException { throw new SQLException("Not implemented."); } @Override public Statement getStatement() throws SQLException { checkOpen(); return _statement; } @Override public String getString(final int columnIndex) throws SQLException { checkOpen(); if (columnIndex == -1) { throw new SQLException("broken connection"); } if (_data != null) { return (String) getObject(columnIndex); } return "String" + columnIndex; } @Override public String getString(final String columnName) throws SQLException { checkOpen(); return columnName; } @Override public java.sql.Time getTime(final int columnIndex) throws SQLException { checkOpen(); return null; } @Override public java.sql.Time getTime(final int columnIndex, final Calendar cal) throws SQLException { checkOpen(); return null; } @Override public java.sql.Time getTime(final String columnName) throws SQLException { checkOpen(); return null; } @Override public java.sql.Time getTime(final String columnName, final Calendar cal) throws SQLException { checkOpen(); return null; } @Override public java.sql.Timestamp getTimestamp(final int columnIndex) throws SQLException { checkOpen(); return null; } @Override public java.sql.Timestamp getTimestamp(final int columnIndex, final Calendar cal) throws SQLException { checkOpen(); return null; } @Override public java.sql.Timestamp getTimestamp(final String columnName) throws SQLException { checkOpen(); return null; } @Override public java.sql.Timestamp getTimestamp(final String columnName, final Calendar cal) throws SQLException { checkOpen(); return null; } @Override public int getType() throws SQLException { return this._type; } /** @deprecated */ @Deprecated @Override public java.io.InputStream getUnicodeStream(final int columnIndex) throws SQLException { checkOpen(); return null; } /** @deprecated */ @Deprecated @Override public java.io.InputStream getUnicodeStream(final String columnName) throws SQLException { checkOpen(); return null; } @Override public java.net.URL getURL(final int columnIndex) throws SQLException { throw new SQLException("Not implemented."); } @Override public java.net.URL getURL(final String columnName) throws SQLException { throw new SQLException("Not implemented."); } @Override public SQLWarning getWarnings() throws SQLException { checkOpen(); return null; } @Override public void insertRow() throws SQLException { checkOpen(); } @Override public boolean isAfterLast() throws SQLException { checkOpen(); return _rowsLeft < 0; } @Override public boolean isBeforeFirst() throws SQLException { checkOpen(); return _rowsLeft == 2; } @Override public boolean isClosed() throws SQLException { return !_open; } @Override public boolean isFirst() throws SQLException { checkOpen(); return _rowsLeft == 1; } @Override public boolean isLast() throws SQLException { checkOpen(); return _rowsLeft == 0; } public boolean isSqlExceptionOnClose() { return _sqlExceptionOnClose; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { throw new SQLException("Not implemented."); } @Override public boolean last() throws SQLException { checkOpen(); return false; } @Override public void moveToCurrentRow() throws SQLException { checkOpen(); } @Override public void moveToInsertRow() throws SQLException { checkOpen(); } @Override public boolean next() throws SQLException { checkOpen(); if (_data != null) { _currentRow++; return _currentRow < _data.length; } return --_rowsLeft > 0; } @Override public boolean previous() throws SQLException { checkOpen(); return false; } @Override public void refreshRow() throws SQLException { checkOpen(); } @Override public boolean relative(final int rows) throws SQLException { checkOpen(); return false; } @Override public boolean rowDeleted() throws SQLException { checkOpen(); return false; } @Override public boolean rowInserted() throws SQLException { checkOpen(); return false; } @Override public boolean rowUpdated() throws SQLException { checkOpen(); return false; } @Override public void setFetchDirection(final int direction) throws SQLException { checkOpen(); } @Override public void setFetchSize(final int rows) throws SQLException { checkOpen(); } public void setSqlExceptionOnClose(final boolean sqlExceptionOnClose) { this._sqlExceptionOnClose = sqlExceptionOnClose; } @Override public T unwrap(final Class iface) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateArray(final int columnIndex, final java.sql.Array x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateArray(final String columnName, final java.sql.Array x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateAsciiStream(final int columnIndex, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateAsciiStream(final int columnIndex, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateAsciiStream(final int columnIndex, final java.io.InputStream x, final int length) throws SQLException { checkOpen(); } @Override public void updateAsciiStream(final String columnLabel, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateAsciiStream(final String columnLabel, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateAsciiStream(final String columnName, final java.io.InputStream x, final int length) throws SQLException { checkOpen(); } @Override public void updateBigDecimal(final int columnIndex, final BigDecimal x) throws SQLException { checkOpen(); } @Override public void updateBigDecimal(final String columnName, final BigDecimal x) throws SQLException { checkOpen(); } @Override public void updateBinaryStream(final int columnIndex, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBinaryStream(final int columnIndex, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBinaryStream(final int columnIndex, final java.io.InputStream x, final int length) throws SQLException { checkOpen(); } @Override public void updateBinaryStream(final String columnLabel, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBinaryStream(final String columnLabel, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBinaryStream(final String columnName, final java.io.InputStream x, final int length) throws SQLException { checkOpen(); } @Override public void updateBlob(final int columnIndex, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBlob(final int columnIndex, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBlob(final int columnIndex, final java.sql.Blob x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBlob(final String columnLabel, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBlob(final String columnLabel, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBlob(final String columnName, final java.sql.Blob x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateBoolean(final int columnIndex, final boolean x) throws SQLException { checkOpen(); } @Override public void updateBoolean(final String columnName, final boolean x) throws SQLException { checkOpen(); } @Override public void updateByte(final int columnIndex, final byte x) throws SQLException { checkOpen(); } @Override public void updateByte(final String columnName, final byte x) throws SQLException { checkOpen(); } @Override public void updateBytes(final int columnIndex, final byte[] x) throws SQLException { checkOpen(); } @Override public void updateBytes(final String columnName, final byte[] x) throws SQLException { checkOpen(); } @Override public void updateCharacterStream(final int columnIndex, final java.io.Reader x, final int length) throws SQLException { checkOpen(); } @Override public void updateCharacterStream(final int columnIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateCharacterStream(final int columnIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateCharacterStream(final String columnName, final java.io.Reader reader, final int length) throws SQLException { checkOpen(); } @Override public void updateCharacterStream(final String columnLabel, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateCharacterStream(final String columnLabel, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateClob(final int columnIndex, final java.sql.Clob x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateClob(final int columnIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateClob(final int columnIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateClob(final String columnName, final java.sql.Clob x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateClob(final String columnLabel, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateClob(final String columnLabel, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateDate(final int columnIndex, final java.sql.Date x) throws SQLException { checkOpen(); } @Override public void updateDate(final String columnName, final java.sql.Date x) throws SQLException { checkOpen(); } @Override public void updateDouble(final int columnIndex, final double x) throws SQLException { checkOpen(); } @Override public void updateDouble(final String columnName, final double x) throws SQLException { checkOpen(); } @Override public void updateFloat(final int columnIndex, final float x) throws SQLException { checkOpen(); } @Override public void updateFloat(final String columnName, final float x) throws SQLException { checkOpen(); } @Override public void updateInt(final int columnIndex, final int x) throws SQLException { checkOpen(); } @Override public void updateInt(final String columnName, final int x) throws SQLException { checkOpen(); } @Override public void updateLong(final int columnIndex, final long x) throws SQLException { checkOpen(); } @Override public void updateLong(final String columnName, final long x) throws SQLException { checkOpen(); } @Override public void updateNCharacterStream(final int columnIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNCharacterStream(final int columnIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNCharacterStream(final String columnLabel, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNCharacterStream(final String columnLabel, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNClob(final int columnIndex, final NClob value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNClob(final int columnIndex, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNClob(final int columnIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNClob(final String columnLabel, final NClob value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNClob(final String columnLabel, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNClob(final String columnLabel, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNString(final int columnIndex, final String value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNString(final String columnLabel, final String value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateNull(final int columnIndex) throws SQLException { checkOpen(); } @Override public void updateNull(final String columnName) throws SQLException { checkOpen(); } @Override public void updateObject(final int columnIndex, final Object x) throws SQLException { checkOpen(); } @Override public void updateObject(final int columnIndex, final Object x, final int scale) throws SQLException { checkOpen(); } @Override public void updateObject(final int columnIndex, final Object x, final SQLType targetSqlType) throws SQLException { checkOpen(); } @Override public void updateObject(final int columnIndex, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { checkOpen(); } @Override public void updateObject(final String columnName, final Object x) throws SQLException { checkOpen(); } @Override public void updateObject(final String columnName, final Object x, final int scale) throws SQLException { checkOpen(); } @Override public void updateObject(final String columnLabel, final Object x, final SQLType targetSqlType) throws SQLException { checkOpen(); } @Override public void updateObject(final String columnLabel, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException { checkOpen(); } @Override public void updateRef(final int columnIndex, final java.sql.Ref x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateRef(final String columnName, final java.sql.Ref x) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateRow() throws SQLException { checkOpen(); } @Override public void updateRowId(final int columnIndex, final RowId value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateRowId(final String columnLabel, final RowId value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateShort(final int columnIndex, final short x) throws SQLException { checkOpen(); } @Override public void updateShort(final String columnName, final short x) throws SQLException { checkOpen(); } @Override public void updateSQLXML(final int columnIndex, final SQLXML value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateSQLXML(final String columnLabel, final SQLXML value) throws SQLException { throw new SQLException("Not implemented."); } @Override public void updateString(final int columnIndex, final String x) throws SQLException { checkOpen(); } @Override public void updateString(final String columnName, final String x) throws SQLException { checkOpen(); } @Override public void updateTime(final int columnIndex, final java.sql.Time x) throws SQLException { checkOpen(); } @Override public void updateTime(final String columnName, final java.sql.Time x) throws SQLException { checkOpen(); } @Override public void updateTimestamp(final int columnIndex, final java.sql.Timestamp x) throws SQLException { checkOpen(); } @Override public void updateTimestamp(final String columnName, final java.sql.Timestamp x) throws SQLException { checkOpen(); } @Override public boolean wasNull() throws SQLException { checkOpen(); return false; } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TesterStatement.java000066400000000000000000000256641447311732500325000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; /** * A dummy {@link Statement}, for testing purposes. */ public class TesterStatement extends AbandonedTrace implements Statement { protected final Connection _connection; protected boolean _open = true; protected final long _rowsUpdated = 1; protected final boolean _executeResponse = true; protected int _maxFieldSize = 1024; protected long _maxRows = 1024; protected boolean _escapeProcessing; protected int _queryTimeout = 1000; protected String _cursorName; protected int _fetchDirection = 1; protected int _fetchSize = 1; protected int _resultSetConcurrency = 1; protected int _resultSetType = 1; private int _resultSetHoldability = 1; protected ResultSet _resultSet; protected boolean _sqlExceptionOnClose; public TesterStatement(final Connection conn) { _connection = conn; } public TesterStatement(final Connection conn, final int resultSetType, final int resultSetConcurrency) { _connection = conn; _resultSetType = resultSetType; _resultSetConcurrency = resultSetConcurrency; } public TesterStatement(final Connection conn, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { _connection = conn; _resultSetType = resultSetType; _resultSetConcurrency = resultSetConcurrency; _resultSetHoldability = resultSetHoldability; } @Override public void addBatch(final String sql) throws SQLException { checkOpen(); } @Override public void cancel() throws SQLException { checkOpen(); } protected void checkOpen() throws SQLException { if (!_open) { throw new SQLException("Connection is closed."); } } @Override public void clearBatch() throws SQLException { checkOpen(); } @Override public void clearWarnings() throws SQLException { checkOpen(); } @Override public void close() throws SQLException { if (_sqlExceptionOnClose) { throw new SQLException("TestSQLExceptionOnClose"); } // calling close twice has no effect if (!_open) { return; } _open = false; if (_resultSet != null) { _resultSet.close(); _resultSet = null; } } @Override public void closeOnCompletion() throws SQLException { throw new SQLException("Not implemented."); } @Override public boolean execute(final String sql) throws SQLException { checkOpen(); if ("invalid".equals(sql)) { throw new SQLException("invalid query"); } return _executeResponse; } @Override public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException { throw new SQLException("Not implemented."); } @Override public boolean execute(final String sql, final int[] columnIndexes) throws SQLException { throw new SQLException("Not implemented."); } @Override public boolean execute(final String sql, final String[] columnNames) throws SQLException { throw new SQLException("Not implemented."); } @Override public int[] executeBatch() throws SQLException { checkOpen(); return new int[0]; } @Override public long[] executeLargeBatch() throws SQLException { checkOpen(); return new long[0]; } @Override public long executeLargeUpdate(final String sql) throws SQLException { checkOpen(); return _rowsUpdated; } @Override public long executeLargeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException { throw new SQLException("Not implemented."); } @Override public long executeLargeUpdate(final String sql, final int[] columnIndexes) throws SQLException { throw new SQLException("Not implemented."); } @Override public long executeLargeUpdate(final String sql, final String[] columnNames) throws SQLException { throw new SQLException("Not implemented."); } @Override public ResultSet executeQuery(final String sql) throws SQLException { checkOpen(); if ("null".equals(sql)) { return null; } if ("invalid".equals(sql)) { throw new SQLException("invalid query"); } if ("broken".equals(sql)) { throw new SQLException("broken connection"); } if ("select username".equals(sql)) { final String userName = ((TesterConnection) _connection).getUserName(); final Object[][] data = { { userName } }; return new TesterResultSet(this, data); } // Simulate timeout if queryTimout is set to less than 5 seconds if (_queryTimeout > 0 && _queryTimeout < 5) { throw new SQLException("query timeout"); } return new TesterResultSet(this); } @Override public int executeUpdate(final String sql) throws SQLException { checkOpen(); return (int) _rowsUpdated; } @Override public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException { throw new SQLException("Not implemented."); } @Override public int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException { throw new SQLException("Not implemented."); } @Override public int executeUpdate(final String sql, final String[] columnNames) throws SQLException { throw new SQLException("Not implemented."); } @Override public Connection getConnection() throws SQLException { checkOpen(); return _connection; } @Override public int getFetchDirection() throws SQLException { checkOpen(); return _fetchDirection; } @Override public int getFetchSize() throws SQLException { checkOpen(); return _fetchSize; } @Override public ResultSet getGeneratedKeys() throws SQLException { return new TesterResultSet(this); } @Override public long getLargeMaxRows() throws SQLException { checkOpen(); return _maxRows; } @Override public long getLargeUpdateCount() throws SQLException { checkOpen(); return _rowsUpdated; } @Override public int getMaxFieldSize() throws SQLException { checkOpen(); return _maxFieldSize; } @Override public int getMaxRows() throws SQLException { checkOpen(); return (int) _maxRows; } @Override public boolean getMoreResults() throws SQLException { checkOpen(); return false; } @Override public boolean getMoreResults(final int current) throws SQLException { throw new SQLException("Not implemented."); } @Override public int getQueryTimeout() throws SQLException { checkOpen(); return _queryTimeout; } @Override public ResultSet getResultSet() throws SQLException { checkOpen(); if (_resultSet == null) { _resultSet = new TesterResultSet(this); } return _resultSet; } @Override public int getResultSetConcurrency() throws SQLException { checkOpen(); return _resultSetConcurrency; } @Override public int getResultSetHoldability() throws SQLException { checkOpen(); return _resultSetHoldability; } @Override public int getResultSetType() throws SQLException { checkOpen(); return _resultSetType; } @Override public int getUpdateCount() throws SQLException { checkOpen(); return (int) _rowsUpdated; } @Override public SQLWarning getWarnings() throws SQLException { checkOpen(); return null; } @Override public boolean isClosed() throws SQLException { return !_open; } @Override public boolean isCloseOnCompletion() throws SQLException { throw new SQLException("Not implemented."); } @Override public boolean isPoolable() throws SQLException { throw new SQLException("Not implemented."); } public boolean isSqlExceptionOnClose() { return _sqlExceptionOnClose; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setCursorName(final String name) throws SQLException { checkOpen(); _cursorName = name; } @Override public void setEscapeProcessing(final boolean enable) throws SQLException { checkOpen(); _escapeProcessing = enable; } @Override public void setFetchDirection(final int direction) throws SQLException { checkOpen(); _fetchDirection = direction; } @Override public void setFetchSize(final int rows) throws SQLException { checkOpen(); _fetchSize = rows; } @Override public void setLargeMaxRows(final long max) throws SQLException { checkOpen(); _maxRows = max; } @Override public void setMaxFieldSize(final int max) throws SQLException { checkOpen(); _maxFieldSize = max; } @Override public void setMaxRows(final int max) throws SQLException { checkOpen(); _maxRows = max; } @Override public void setPoolable(final boolean poolable) throws SQLException { throw new SQLException("Not implemented."); } @Override public void setQueryTimeout(final int seconds) throws SQLException { checkOpen(); _queryTimeout = seconds; } public void setSqlExceptionOnClose(final boolean _sqlExceptionOnClose) { this._sqlExceptionOnClose = _sqlExceptionOnClose; } @Override public T unwrap(final Class iface) throws SQLException { throw new SQLException("Not implemented."); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/TesterUtils.java000066400000000000000000000026051447311732500316220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2; import java.lang.reflect.Field; public class TesterUtils { /** * Access a private field. Do it this way rather than increasing the * visibility of the field in the public API. */ public static Object getField(final Object target, final String fieldName) throws Exception { final Class clazz = target.getClass(); final Field f = clazz.getDeclaredField(fieldName); f.setAccessible(true); return f.get(target); } private TesterUtils() { // Utility class - hide default constructor } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/cpdsadapter/000077500000000000000000000000001447311732500307575ustar00rootroot00000000000000TestDriverAdapterCPDS.java000066400000000000000000000341061447311732500356150ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/cpdsadapter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.cpdsadapter; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.PrintWriter; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.time.Duration; import java.util.Properties; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.sql.DataSource; import org.apache.commons.dbcp2.Constants; import org.apache.commons.dbcp2.datasources.SharedPoolDataSource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests for DriverAdapterCPDS */ public class TestDriverAdapterCPDS { private static class ThreadDbcp367 extends Thread { private final DataSource ds; private volatile boolean failed; public ThreadDbcp367(final DataSource ds) { this.ds = ds; } public boolean isFailed() { return failed; } @Override public void run() { Connection c = null; try { for (int j=0; j < 5000; j++) { c = ds.getConnection(); c.close(); } } catch (final SQLException sqle) { failed = true; sqle.printStackTrace(); } } } private DriverAdapterCPDS pcds; @BeforeEach public void setUp() throws Exception { pcds = new DriverAdapterCPDS(); pcds.setDriver("org.apache.commons.dbcp2.TesterDriver"); pcds.setUrl("jdbc:apache:commons:testdriver"); pcds.setUser("foo"); pcds.setPassword("bar"); pcds.setPoolPreparedStatements(false); } @Test public void testClosingWithUserName() throws Exception { final Connection[] c = new Connection[10]; for (int i=0; i pcds.setConnectionProperties(properties)); } @Test public void testSetConnectionPropertiesNull() throws Exception { pcds.setConnectionProperties(null); } @Test public void testSetPasswordNull() throws Exception { pcds.setPassword("Secret"); assertEquals("Secret", pcds.getPassword()); pcds.setPassword((char[]) null); assertNull(pcds.getPassword()); } @Test public void testSetPasswordNullWithConnectionProperties() throws Exception { pcds.setConnectionProperties(new Properties()); pcds.setPassword("Secret"); assertEquals("Secret", pcds.getPassword()); pcds.setPassword((char[]) null); assertNull(pcds.getPassword()); } @Test public void testSetPasswordThenModCharArray() { final char[] pwd = {'a'}; pcds.setPassword(pwd); assertEquals("a", pcds.getPassword()); pwd[0] = 'b'; assertEquals("a", pcds.getPassword()); } @Test public void testSetUserNull() throws Exception { pcds.setUser("Alice"); assertEquals("Alice", pcds.getUser()); pcds.setUser(null); assertNull(pcds.getUser()); } @Test public void testSetUserNullWithConnectionProperties() throws Exception { pcds.setConnectionProperties(new Properties()); pcds.setUser("Alice"); assertEquals("Alice", pcds.getUser()); pcds.setUser(null); assertNull(pcds.getUser()); } @Test public void testSimple() throws Exception { try (final Connection conn = pcds.getPooledConnection().getConnection()) { assertNotNull(conn); try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (final ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } @Test public void testSimpleWithUsername() throws Exception { try (final Connection conn = pcds.getPooledConnection("u1", "p1").getConnection()) { assertNotNull(conn); try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (final ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } @Test public void testToStringWithoutConnectionProperties() throws ClassNotFoundException { final DriverAdapterCPDS cleanCpds = new DriverAdapterCPDS(); cleanCpds.setDriver( "org.apache.commons.dbcp2.TesterDriver" ); cleanCpds.setUrl( "jdbc:apache:commons:testdriver" ); cleanCpds.setUser( "foo" ); cleanCpds.setPassword( "bar" ); cleanCpds.toString(); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/000077500000000000000000000000001447311732500310025ustar00rootroot00000000000000CharArrayTest.java000066400000000000000000000036621447311732500343110ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import org.junit.jupiter.api.Test; /** * Tests {@link CharArray}. */ public class CharArrayTest { @Test public void testAsString() { assertEquals("foo", new CharArray("foo").asString()); } @Test public void testEquals() { assertEquals(new CharArray("foo"), new CharArray("foo")); assertNotEquals(new CharArray("foo"), new CharArray("bar")); } @Test public void testGet() { assertArrayEquals("foo".toCharArray(), new CharArray("foo").get()); } @Test public void testHashCode() { assertEquals(new CharArray("foo").hashCode(), new CharArray("foo").hashCode()); assertNotEquals(new CharArray("foo").hashCode(), new CharArray("bar").hashCode()); } @Test public void testToString() { assertFalse(new CharArray("foo").toString().contains("foo")); } } ConnectionPoolDataSourceProxy.java000066400000000000000000000057731447311732500375500ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.io.PrintWriter; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.logging.Logger; import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; import org.apache.commons.dbcp2.Jdbc41Bridge; /** * ConnectionPoolDataSource implementation that proxies another ConnectionPoolDataSource. */ public class ConnectionPoolDataSourceProxy implements ConnectionPoolDataSource { protected ConnectionPoolDataSource delegate; public ConnectionPoolDataSourceProxy(final ConnectionPoolDataSource cpds) { this.delegate = cpds; } public ConnectionPoolDataSource getDelegate() { return delegate; } @Override public int getLoginTimeout() throws SQLException { return delegate.getLoginTimeout(); } @Override public PrintWriter getLogWriter() throws SQLException { return delegate.getLogWriter(); } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return Jdbc41Bridge.getParentLogger(delegate); } /** * Gets a TesterPooledConnection with notifyOnClose turned on */ @Override public PooledConnection getPooledConnection() throws SQLException { return wrapPooledConnection(delegate.getPooledConnection()); } /** * Gets a TesterPooledConnection with notifyOnClose turned on */ @Override public PooledConnection getPooledConnection(final String user, final String password) throws SQLException { return wrapPooledConnection(delegate.getPooledConnection(user, password)); } @Override public void setLoginTimeout(final int seconds) throws SQLException { delegate.setLoginTimeout(seconds); } @Override public void setLogWriter(final PrintWriter out) throws SQLException { delegate.setLogWriter(out); } /** * Creates a TesterPooledConnection with notifyOnClose turned on */ protected PooledConnection wrapPooledConnection(final PooledConnection pc) { final PooledConnectionProxy tpc = new PooledConnectionProxy(pc); tpc.setNotifyOnClose(true); return tpc; } } PooledConnectionProxy.java000066400000000000000000000110631447311732500360730ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EventListener; import java.util.List; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.PooledConnection; import javax.sql.StatementEventListener; /** * PooledConnection implementation that wraps a driver-supplied * PooledConnection and proxies events, allowing behavior to be * modified to simulate behavior of different implementations. */ public class PooledConnectionProxy implements PooledConnection, ConnectionEventListener { protected PooledConnection delegate; /** * ConnectionEventListeners */ private final List eventListeners = Collections.synchronizedList(new ArrayList<>()); /** * True means we will (dubiously) notify listeners with a * ConnectionClosed event when this (i.e. the PooledConnection itself) * is closed */ private boolean notifyOnClose; public PooledConnectionProxy(final PooledConnection pooledConnection) { this.delegate = pooledConnection; pooledConnection.addConnectionEventListener(this); } /** * Add event listeners. */ @Override public void addConnectionEventListener(final ConnectionEventListener listener) { if (!eventListeners.contains(listener)) { eventListeners.add(listener); } } @Override public void addStatementEventListener(final StatementEventListener listener) { if (!eventListeners.contains(listener)) { eventListeners.add(listener); } } /** * If notifyOnClose is on, notify listeners */ @Override public void close() throws SQLException { delegate.close(); if (isNotifyOnClose()) { notifyListeners(); } } /** * Pass closed events on to listeners */ @Override public void connectionClosed(final ConnectionEvent event) { notifyListeners(); } /** * Pass error events on to listeners */ @Override public void connectionErrorOccurred(final ConnectionEvent event) { final Object[] listeners = eventListeners.toArray(); for (final Object listener : listeners) { ((ConnectionEventListener) listener).connectionErrorOccurred(event); } } @Override public Connection getConnection() throws SQLException { return delegate.getConnection(); } /** * Expose listeners */ public Collection getListeners() { return eventListeners; } public boolean isNotifyOnClose() { return notifyOnClose; } /** * sends a connectionClosed event to listeners. */ void notifyListeners() { final ConnectionEvent event = new ConnectionEvent(this); final Object[] listeners = eventListeners.toArray(); for (final Object listener : listeners) { ((ConnectionEventListener) listener).connectionClosed(event); } } /** * Remove event listeners. */ @Override public void removeConnectionEventListener(final ConnectionEventListener listener) { eventListeners.remove(listener); } @Override public void removeStatementEventListener(final StatementEventListener listener) { eventListeners.remove(listener); } public void setNotifyOnClose(final boolean notifyOnClose) { this.notifyOnClose = notifyOnClose; } /** * Generate a connection error event */ public void throwConnectionError() { final ConnectionEvent event = new ConnectionEvent(this); connectionErrorOccurred(event); } } TestCPDSConnectionFactory.java000066400000000000000000000177001447311732500365340ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import javax.sql.PooledConnection; import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS; import org.apache.commons.pool2.impl.GenericObjectPool; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** */ public class TestCPDSConnectionFactory { protected ConnectionPoolDataSourceProxy cpds; @BeforeEach public void setUp() throws Exception { cpds = new ConnectionPoolDataSourceProxy(new DriverAdapterCPDS()); final DriverAdapterCPDS delegate = (DriverAdapterCPDS) cpds.getDelegate(); delegate.setDriver("org.apache.commons.dbcp2.TesterDriver"); delegate.setUrl("jdbc:apache:commons:testdriver"); delegate.setUser("userName"); delegate.setPassword("password"); } /** * JIRA DBCP-216 * * Verify that pool counters are maintained properly and listeners are * cleaned up when a PooledConnection throws a connectionError event. */ @Test public void testConnectionErrorCleanup() throws Exception { // Setup factory final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, null, Duration.ofMillis(-1), false, "userName", "password"); try (final GenericObjectPool pool = new GenericObjectPool<>(factory)) { factory.setPool(pool); // Checkout a pair of connections final PooledConnection pcon1 = pool.borrowObject().getPooledConnection(); try (final Connection con1 = pcon1.getConnection()) { final PooledConnection pcon2 = pool.borrowObject().getPooledConnection(); assertEquals(2, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); // Verify listening final PooledConnectionProxy pc = (PooledConnectionProxy) pcon1; assertTrue(pc.getListeners().contains(factory)); // Throw connectionError event pc.throwConnectionError(); // Active count should be reduced by 1 and no idle increase assertEquals(1, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); // Throw another one - should be ignored pc.throwConnectionError(); assertEquals(1, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); // Ask for another connection final PooledConnection pcon3 = pool.borrowObject().getPooledConnection(); assertNotEquals(pcon3, pcon1); // better not get baddie back assertFalse(pc.getListeners().contains(factory)); // verify cleanup assertEquals(2, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); // Return good connections back to pool pcon2.getConnection().close(); pcon3.getConnection().close(); assertEquals(2, pool.getNumIdle()); assertEquals(0, pool.getNumActive()); // Verify pc is closed assertThrows(SQLException.class, pc::getConnection, "Expecting SQLException using closed PooledConnection"); // Back from the dead - ignore the ghost! con1.close(); assertEquals(2, pool.getNumIdle()); assertEquals(0, pool.getNumActive()); // Clear pool pool.clear(); assertEquals(0, pool.getNumIdle()); } } } /** * JIRA: DBCP-442 */ @Test public void testNullValidationQuery_Deprecated() throws Exception { final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, null, -1, false, "userName", "password"); try (final GenericObjectPool pool = new GenericObjectPool<>(factory)) { factory.setPool(pool); pool.setTestOnBorrow(true); final PooledConnection pcon = pool.borrowObject().getPooledConnection(); try (final Connection con = pcon.getConnection()) { } } } /** * JIRA: DBCP-442 */ @Test public void testNullValidationQuery() throws Exception { final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, null, Duration.ofMillis(-1), false, "userName", "password"); try (final GenericObjectPool pool = new GenericObjectPool<>(factory)) { factory.setPool(pool); pool.setTestOnBorrow(true); final PooledConnection pcon = pool.borrowObject().getPooledConnection(); try (final Connection con = pcon.getConnection()) { } } } @Test public void testSetPasswordThenModCharArray_Deprecated() { final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, null, -1, false, "userName", "password"); final char[] pwd = {'a'}; factory.setPassword(pwd); assertEquals("a", String.valueOf(factory.getPasswordCharArray())); pwd[0] = 'b'; assertEquals("a", String.valueOf(factory.getPasswordCharArray())); } @Test public void testSetPasswordThenModCharArray() { final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, null, Duration.ofMillis(-1), false, "userName", "password"); final char[] pwd = {'a'}; factory.setPassword(pwd); assertEquals("a", String.valueOf(factory.getPasswordCharArray())); pwd[0] = 'b'; assertEquals("a", String.valueOf(factory.getPasswordCharArray())); } /** * JIRA DBCP-216 * * Check PoolableConnection close triggered by destroy is handled * properly. PooledConnectionProxy (dubiously) fires connectionClosed * when PooledConnection itself is closed. */ @Test public void testSharedPoolDSDestroyOnReturn() throws Exception { try (final PerUserPoolDataSource ds = new PerUserPoolDataSource()) { ds.setConnectionPoolDataSource(cpds); ds.setPerUserMaxTotal("userName", 10); ds.setPerUserMaxWait("userName", Duration.ofMillis(50)); ds.setPerUserMaxIdle("userName", 2); final Connection conn1 = ds.getConnection("userName", "password"); final Connection conn2 = ds.getConnection("userName", "password"); final Connection conn3 = ds.getConnection("userName", "password"); assertEquals(3, ds.getNumActive("userName")); conn1.close(); assertEquals(1, ds.getNumIdle("userName")); conn2.close(); assertEquals(2, ds.getNumIdle("userName")); conn3.close(); // Return to pool will trigger destroy -> close sequence assertEquals(2, ds.getNumIdle("userName")); } } } TestFactory.java000066400000000000000000000043241447311732500340400ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Hashtable; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.naming.spi.ObjectFactory; import org.junit.jupiter.api.Test; /** */ public class TestFactory { // Bugzilla Bug 24082: bug in InstanceKeyDataSourceFactory // There's a fatal bug in InstanceKeyDataSourceFactory that means you can't // instantiate more than one factory. // https://issues.apache.org/bugzilla/show_bug.cgi?id=24082 @Test public void testJNDI2Pools() throws Exception { final Reference refObj = new Reference(SharedPoolDataSource.class.getName()); refObj.add(new StringRefAddr("dataSourceName","java:comp/env/jdbc/bookstoreCPDS")); final Context context = new InitialContext(); final Hashtable env = new Hashtable<>(); final ObjectFactory factory = new SharedPoolDataSourceFactory(); final Name name = new CompositeName("myDB"); final Object obj = factory.getObjectInstance(refObj, name, context, env); assertNotNull(obj); final Name name2 = new CompositeName("myDB2"); final Object obj2 = factory.getObjectInstance(refObj, name2, context, env); assertNotNull(obj2); } } TestInstanceKeyDataSource.java000066400000000000000000000256311447311732500366250ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** */ public class TestInstanceKeyDataSource { private static class ThrowOnSetupDefaultsDataSource extends SharedPoolDataSource { private static final long serialVersionUID = -448025812063133259L; ThrowOnSetupDefaultsDataSource() { } @Override protected void setupDefaults(final Connection connection, final String userName) throws SQLException { throw new SQLException("bang!"); } } private final static String DRIVER = "org.apache.commons.dbcp2.TesterDriver"; private final static String URL = "jdbc:apache:commons:testdriver"; private final static String USER = "foo"; private final static String PASS = "bar"; private DriverAdapterCPDS pcds; private SharedPoolDataSource spds; @BeforeEach public void setUp() throws ClassNotFoundException { pcds = new DriverAdapterCPDS(); pcds.setDriver(DRIVER); pcds.setUrl(URL); pcds.setUser(USER); pcds.setPassword(PASS); pcds.setPoolPreparedStatements(false); spds = new SharedPoolDataSource(); spds.setConnectionPoolDataSource(pcds); } @AfterEach public void tearDown() throws Exception { spds.close(); } @Test public void testConnection() throws SQLException, ClassNotFoundException { spds = new SharedPoolDataSource(); pcds.setDriver(DRIVER); pcds.setUrl(URL); spds.setConnectionPoolDataSource(pcds); final PooledConnectionAndInfo info = spds.getPooledConnectionAndInfo(null, null); assertNull(info.getUserName()); assertNull(info.getPassword()); try (final Connection conn = spds.getConnection()) { assertNotNull(conn); } } @Test public void testConnectionPoolDataSource() { assertEquals(pcds, spds.getConnectionPoolDataSource()); } @Test public void testConnectionPoolDataSourceAlreadySet() { assertThrows(IllegalStateException.class, () -> spds.setConnectionPoolDataSource(new DriverAdapterCPDS())); } @Test public void testConnectionPoolDataSourceAlreadySetUsingJndi() { spds = new SharedPoolDataSource(); spds.setDataSourceName("anything"); assertThrows(IllegalStateException.class, () -> spds.setConnectionPoolDataSource(new DriverAdapterCPDS())); } @Test public void testDataSourceName() { spds = new SharedPoolDataSource(); assertNull(spds.getDataSourceName()); spds.setDataSourceName("anything"); assertEquals("anything", spds.getDataSourceName()); } @Test public void testDataSourceNameAlreadySet() { assertThrows(IllegalStateException.class, () -> spds.setDataSourceName("anything")); } @Test public void testDataSourceNameAlreadySetUsingJndi() { spds = new SharedPoolDataSource(); spds.setDataSourceName("anything"); assertThrows(IllegalStateException.class, () -> spds.setDataSourceName("anything")); } @Test public void testDefaultBlockWhenExhausted() { spds.setDefaultBlockWhenExhausted(true); assertTrue(spds.getDefaultBlockWhenExhausted()); spds.setDefaultBlockWhenExhausted(false); assertFalse(spds.getDefaultBlockWhenExhausted()); } @Test public void testDefaultEvictionPolicyClassName() { spds.setDefaultEvictionPolicyClassName(Object.class.getName()); assertEquals(Object.class.getName(), spds.getDefaultEvictionPolicyClassName()); } @Test public void testDefaultLifo() { spds.setDefaultLifo(true); assertTrue(spds.getDefaultLifo()); spds.setDefaultLifo(false); assertFalse(spds.getDefaultLifo()); } @Test public void testDefaultMinIdle() { spds.setDefaultMinIdle(10); assertEquals(10, spds.getDefaultMinIdle()); } @Test public void testDefaultReadOnly() { spds.setDefaultReadOnly(true); assertTrue(spds.isDefaultReadOnly()); spds.setDefaultReadOnly(false); assertFalse(spds.isDefaultReadOnly()); } @Test public void testDefaultSoftMinEvictableIdleTimeMillis() { spds.setDefaultSoftMinEvictableIdleTimeMillis(10); assertEquals(10, spds.getDefaultSoftMinEvictableIdleTimeMillis()); } @Test public void testDefaultTestOnCreate() { spds.setDefaultTestOnCreate(false); assertFalse(spds.getDefaultTestOnCreate()); spds.setDefaultTestOnCreate(true); assertTrue(spds.getDefaultTestOnCreate()); } @Test public void testDefaultTransactionIsolation() { assertEquals(InstanceKeyDataSource.UNKNOWN_TRANSACTIONISOLATION, spds.getDefaultTransactionIsolation()); spds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); assertEquals(Connection.TRANSACTION_READ_COMMITTED, spds.getDefaultTransactionIsolation()); } @Test public void testDefaultTransactionIsolationInvalid() { assertEquals(InstanceKeyDataSource.UNKNOWN_TRANSACTIONISOLATION, spds.getDefaultTransactionIsolation()); assertThrows(IllegalArgumentException.class, () -> spds.setDefaultTransactionIsolation(Integer.MAX_VALUE)); } @Test public void testDescription() { spds.setDescription("anything"); assertEquals("anything", spds.getDescription()); } /** * Verify that exception on setupDefaults does not leak PooledConnection * * JIRA: DBCP-237 * @throws Exception */ @Test public void testExceptionOnSetupDefaults() throws Exception { try (final ThrowOnSetupDefaultsDataSource tds = new ThrowOnSetupDefaultsDataSource()) { final int numConnections = tds.getNumActive(); assertThrows(SQLException.class, () -> tds.getConnection(USER, PASS)); assertEquals(numConnections, tds.getNumActive()); } } @Test public void testIsWrapperFor() throws Exception { assertTrue(spds.isWrapperFor(InstanceKeyDataSource.class)); assertTrue(spds.isWrapperFor(AutoCloseable.class)); } @Test public void testJndiEnvironment() { assertNull(spds.getJndiEnvironment("name")); final Properties properties = new Properties(); properties.setProperty("name", "clarke"); spds.setJndiEnvironment(properties); assertEquals("clarke", spds.getJndiEnvironment("name")); spds.setJndiEnvironment("name", "asimov"); assertEquals("asimov", spds.getJndiEnvironment("name")); } @Test public void testJndiNullProperties() { assertThrows(NullPointerException.class, () -> spds.setJndiEnvironment(null)); } @Test public void testJndiPropertiesCleared() { spds.setJndiEnvironment("name", "king"); assertEquals("king", spds.getJndiEnvironment("name")); final Properties properties = new Properties(); properties.setProperty("fish", "kohi"); spds.setJndiEnvironment(properties); assertNull(spds.getJndiEnvironment("name")); } @Test public void testJndiPropertiesNotInitialized() { assertNull(spds.getJndiEnvironment("name")); spds.setJndiEnvironment("name", "king"); assertEquals("king", spds.getJndiEnvironment("name")); } @Test public void testLoginTimeout() { spds.setLoginTimeout(10); assertEquals(10, spds.getLoginTimeout()); } @SuppressWarnings("resource") @Test public void testLogWriter() { spds.setLogWriter(new PrintWriter(System.out)); assertNotNull(spds.getLogWriter()); } @SuppressWarnings("resource") @Test public void testLogWriterAutoInitialized() { assertNotNull(spds.getLogWriter()); } @Test public void testMaxConnLifetimeMillis() { assertEquals(-1, spds.getMaxConnLifetimeMillis()); spds.setMaxConnLifetimeMillis(10); assertEquals(10, spds.getMaxConnLifetimeMillis()); } @Test public void testRollbackAfterValidation() { assertFalse(spds.isRollbackAfterValidation()); spds.setRollbackAfterValidation(true); assertTrue(spds.isRollbackAfterValidation()); } @Test public void testRollbackAfterValidationWithConnectionCalled() throws SQLException { try (Connection connection = spds.getConnection()) { assertFalse(spds.isRollbackAfterValidation()); assertThrows(IllegalStateException.class, () -> spds.setRollbackAfterValidation(true)); } } @SuppressWarnings("resource") @Test public void testUnwrap() throws Exception { assertSame(spds.unwrap(InstanceKeyDataSource.class), spds); assertSame(spds.unwrap(AutoCloseable.class), spds); } @Test public void testValidationQuery() { assertNull(spds.getValidationQuery()); spds.setValidationQuery("anything"); assertEquals("anything", spds.getValidationQuery()); } @Test public void testValidationQueryTimeout() { assertEquals(-1, spds.getValidationQueryTimeout()); spds.setValidationQueryTimeout(10); assertEquals(10, spds.getValidationQueryTimeout()); } @Test public void testValidationQueryWithConnectionCalled() throws SQLException { try (Connection connection = spds.getConnection()) { assertNull(spds.getValidationQuery()); assertThrows(IllegalStateException.class, () -> spds.setValidationQuery("anything")); } } } TestKeyedCPDSConnectionFactory.java000066400000000000000000000153531447311732500375200ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import javax.sql.PooledConnection; import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests {@link KeyedCPDSConnectionFactory}. */ public class TestKeyedCPDSConnectionFactory { protected ConnectionPoolDataSourceProxy cpds; @BeforeEach public void setUp() throws Exception { cpds = new ConnectionPoolDataSourceProxy(new DriverAdapterCPDS()); final DriverAdapterCPDS delegate = (DriverAdapterCPDS) cpds.getDelegate(); delegate.setDriver("org.apache.commons.dbcp2.TesterDriver"); delegate.setUrl("jdbc:apache:commons:testdriver"); delegate.setUser("userName"); delegate.setPassword("password"); } /** * JIRA DBCP-216 * * Verify that pool counters are maintained properly and listeners are * cleaned up when a PooledConnection throws a connectionError event. */ @Test public void testConnectionErrorCleanup() throws Exception { // Setup factory final UserPassKey key = new UserPassKey("userName", "password"); final KeyedCPDSConnectionFactory factory = new KeyedCPDSConnectionFactory(cpds, null, -1, false); try (final KeyedObjectPool pool = new GenericKeyedObjectPool<>(factory)) { factory.setPool(pool); // Checkout a pair of connections final PooledConnection pcon1 = pool.borrowObject(key).getPooledConnection(); try (final Connection con1 = pcon1.getConnection()) { final PooledConnection pcon2 = pool.borrowObject(key).getPooledConnection(); assertEquals(2, pool.getNumActive(key)); assertEquals(0, pool.getNumIdle(key)); // Verify listening final PooledConnectionProxy pc = (PooledConnectionProxy) pcon1; assertTrue(pc.getListeners().contains(factory)); // Throw connectionError event pc.throwConnectionError(); // Active count should be reduced by 1 and no idle increase assertEquals(1, pool.getNumActive(key)); assertEquals(0, pool.getNumIdle(key)); // Throw another one - we should be on cleanup list, so ignored pc.throwConnectionError(); assertEquals(1, pool.getNumActive(key)); assertEquals(0, pool.getNumIdle(key)); // Ask for another connection - should trigger makeObject, which causes // cleanup, removing listeners. final PooledConnection pcon3 = pool.borrowObject(key).getPooledConnection(); assertNotEquals(pcon3, pcon1); // better not get baddie back assertFalse(pc.getListeners().contains(factory)); // verify cleanup assertEquals(2, pool.getNumActive(key)); assertEquals(0, pool.getNumIdle(key)); // Return good connections back to pool pcon2.getConnection().close(); pcon3.getConnection().close(); assertEquals(2, pool.getNumIdle(key)); assertEquals(0, pool.getNumActive(key)); // Verify pc is closed assertThrows(SQLException.class, pc::getConnection, "Expecting SQLException using closed PooledConnection"); // Back from the dead - ignore the ghost! } assertEquals(2, pool.getNumIdle(key)); assertEquals(0, pool.getNumActive(key)); // Clear pool pool.clear(); assertEquals(0, pool.getNumIdle(key)); } } /** * JIRA: DBCP-442 */ @Test public void testNullValidationQuery() throws Exception { final UserPassKey key = new UserPassKey("userName", "password"); final KeyedCPDSConnectionFactory factory = new KeyedCPDSConnectionFactory(cpds, null, -1, false); try (final GenericKeyedObjectPool pool = new GenericKeyedObjectPool<>(factory)) { factory.setPool(pool); pool.setTestOnBorrow(true); final PooledConnection pcon = pool.borrowObject(key).getPooledConnection(); try (final Connection con = pcon.getConnection()) { } } } /** * JIRA DBCP-216 * * Check PoolableConnection close triggered by destroy is handled * properly. PooledConnectionProxy (dubiously) fires connectionClosed * when PooledConnection itself is closed. */ @Test public void testSharedPoolDSDestroyOnReturn() throws Exception { try (final SharedPoolDataSource ds = new SharedPoolDataSource()) { ds.setConnectionPoolDataSource(cpds); ds.setMaxTotal(10); ds.setDefaultMaxWait(Duration.ofMillis(50)); ds.setDefaultMaxIdle(2); final Connection conn1 = ds.getConnection("userName", "password"); final Connection conn2 = ds.getConnection("userName", "password"); final Connection conn3 = ds.getConnection("userName", "password"); assertEquals(3, ds.getNumActive()); conn1.close(); assertEquals(1, ds.getNumIdle()); conn2.close(); assertEquals(2, ds.getNumIdle()); conn3.close(); // Return to pool will trigger destroy -> close sequence assertEquals(2, ds.getNumIdle()); } } } TestPerUserPoolDataSource.java000066400000000000000000002161731447311732500366320ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import java.util.HashMap; import java.util.Map; import javax.sql.DataSource; import org.apache.commons.dbcp2.TestConnectionPool; import org.apache.commons.dbcp2.TesterDriver; import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** */ public class TestPerUserPoolDataSource extends TestConnectionPool { private static final Duration DURATION_1_MILLISECOND = Duration.ofMillis(1); private String user; private DataSource ds; @Override protected Connection getConnection() throws SQLException { return ds.getConnection(user,"bar"); } @BeforeEach public void setUp() throws Exception { user = "foo"; final DriverAdapterCPDS pcds = new DriverAdapterCPDS(); pcds.setDriver("org.apache.commons.dbcp2.TesterDriver"); pcds.setUrl("jdbc:apache:commons:testdriver"); pcds.setUser(user); pcds.setPassword("bar"); pcds.setAccessToUnderlyingConnectionAllowed(true); final PerUserPoolDataSource tds = new PerUserPoolDataSource(); tds.setConnectionPoolDataSource(pcds); tds.setDefaultMaxTotal(getMaxTotal()); tds.setDefaultMaxWait(getMaxWaitDuration()); tds.setPerUserMaxTotal(user, getMaxTotal()); tds.setPerUserMaxWait(user, getMaxWaitDuration()); tds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); tds.setDefaultAutoCommit(Boolean.TRUE); ds = tds; } @Override @AfterEach public void tearDown() throws Exception { super.tearDown(); ((PerUserPoolDataSource) ds).close(); } // See DBCP-8 @Test public void testChangePassword() throws Exception { assertThrows(SQLException.class, () -> ds.getConnection(user, "bay")); final Connection con1 = ds.getConnection(user, "bar"); final Connection con2 = ds.getConnection(user, "bar"); final Connection con3 = ds.getConnection(user, "bar"); con1.close(); con2.close(); TesterDriver.addUser(user,"bay"); // change the user/password setting try { final Connection con4 = ds.getConnection(user, "bay"); // new password // Idle instances with old password should have been cleared assertEquals(0, ((PerUserPoolDataSource) ds).getNumIdle(user), "Should be no idle connections in the pool"); con4.close(); // Should be one idle instance with new pwd assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user), "Should be one idle connection in the pool"); try (Connection c = ds.getConnection(user, "bar")) { // old password fail("Should have generated SQLException"); } catch (final SQLException expected) { } final Connection con5 = ds.getConnection(user, "bay"); // take the idle one con3.close(); // Return a connection with the old password ds.getConnection(user, "bay").close(); // will try bad returned connection and destroy it assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user), "Should be one idle connection in the pool"); con5.close(); } finally { TesterDriver.addUser(user,"bar"); } } @Override @Test public void testClosing() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; // open the maximum connections for (int i=0; i ds.getConnection("u1", "zlsafjk")); // Use good password ds.getConnection("u1", "p1").close(); try (Connection c = ds.getConnection("u1", "x")){ fail("Able to retrieve connection with incorrect password"); } catch (final SQLException e) { if (!e.getMessage().startsWith("Given password did not match")) { throw e; } // else the exception was expected } // Make sure we can still use our good password. ds.getConnection("u1", "p1").close(); // Try related users and passwords ds.getConnection(user, "bar").close(); assertThrows(SQLException.class, () -> ds.getConnection("foob", "ar")); assertThrows(SQLException.class, () -> ds.getConnection(user, "baz")); } @Override @Test public void testMaxTotal() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = ds.getConnection(); assertNotNull(c[i]); } try (Connection conn = ds.getConnection()) { fail("Allowed to open more than DefaultMaxTotal connections."); } catch (final java.sql.SQLException e) { // should only be able to open 10 connections, so this test should // throw an exception } for (final Connection element : c) { element.close(); } } /** * Verify that defaultMaxWaitMillis = 0 means immediate failure when * pool is exhausted. */ @Test public void testMaxWaitMillisZero() throws Exception { final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds; tds.setDefaultMaxWait(Duration.ZERO); tds.setPerUserMaxTotal("u1", 1); try (final Connection conn = tds.getConnection("u1", "p1")) { assertThrows(SQLException.class, () -> tds.getConnection("u1", "p1")); } } @Test public void testMultipleThreads1() throws Exception { // Override wait time in order to allow for Thread.sleep(1) sometimes taking a lot longer on // some JVMs, e.g. Windows. final Duration defaultMaxWaitDuration = Duration.ofMillis(430); ((PerUserPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration); ((PerUserPoolDataSource) ds).setPerUserMaxWait(user, defaultMaxWaitDuration); multipleThreads(Duration.ofMillis(1), false, false, defaultMaxWaitDuration); } @Test public void testMultipleThreads2() throws Exception { final Duration defaultMaxWaitDuration = Duration.ofMillis(500); ((PerUserPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration); ((PerUserPoolDataSource) ds).setPerUserMaxWait(user, defaultMaxWaitDuration); multipleThreads(defaultMaxWaitDuration.multipliedBy(2), true, true, defaultMaxWaitDuration); } @Override @Test public void testOpening() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; // test that opening new connections is not closing previous for (int i=0; i userDefaultBlockWhenExhausted = new HashMap<>(); userDefaultBlockWhenExhausted.put("key", Boolean.FALSE); ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted); assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("key")); // when the code above is executed, the backing map was initalized // now check if that still works. The backing map is clear'ed. userDefaultBlockWhenExhausted = new HashMap<>(); userDefaultBlockWhenExhausted.put("anonymous", Boolean.FALSE); ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted); // now the previously entered value was cleared, so it will be back to the // default value of TRUE assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key")); // and our new value exists too assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("anonymous")); } /** * Test per user block when exhausted, with the backing map not initialized before. * Instead we pass the map. */ @Test public void testPerUserBlockWhenExhaustedMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map userDefaultBlockWhenExhausted = new HashMap<>(); userDefaultBlockWhenExhausted.put("key", Boolean.TRUE); ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted); assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key")); } /** * Test per user block when exhausted, with the backing map not initialized before. * Instead, we pass the map. And furthermore, we are now searching for an inexistent * key, which should return the default value. */ @Test public void testPerUserBlockWhenExhaustedMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map userDefaultBlockWhenExhausted = new HashMap<>(); userDefaultBlockWhenExhausted.put("key", Boolean.FALSE); ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted); assertEquals(ds.getDefaultBlockWhenExhausted(), ds.getPerUserBlockWhenExhausted("missingkey")); } /** * Test per user block when exhausted, with the backing map not initialized before. * Instead we pass the user and value, and hence the map is initialized beforehand. * After that, we pass another user, so both values should still be present. The * PerUserPoolDataSource does not clear the perUserPoolDataSource map, unless you * pass a new map, using another internal/package method. */ @Test public void testPerUserBlockWhenExhaustedWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user)); // when the code above is executed, the backing map was initalized // now check if that still works. The backing map is NOT clear'ed. ds.setPerUserBlockWhenExhausted("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user)); assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("anotheruser")); } /** * Test per user block when exhausted, with the backing map not initialized before. * Instead we pass the user and value, and hence the map is initialized beforehand. */ @Test public void testPerUserBlockWhenExhaustedWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user)); } /** * Test per user block when exhausted, with the backing map not initialized before. * Instead we pass the user and value, and hence the map is initialized beforehand. * Furthermore, we are now searching for an inexistent key, which should return the * default value. */ @Test public void testPerUserBlockWhenExhaustedWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserBlockWhenExhausted("whatismyuseragain?", Boolean.FALSE); assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("missingkey")); } @Test public void testPerUserDefaultAutoCommitMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserDefaultAutoCommit(values); assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("key")); values = new HashMap<>(); values.put("anonymous", Boolean.FALSE); ds.setPerUserDefaultAutoCommit(values); assertNull(ds.getPerUserDefaultAutoCommit("key")); assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anonymous")); } // getters and setters. Most follow the same pattern. The initial tests contain a more // complete documentation, which can be helpful when write/understanding the other methods. // -- per user block when exhausted @Test public void testPerUserDefaultAutoCommitMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.TRUE); ds.setPerUserDefaultAutoCommit(values); assertEquals(Boolean.TRUE, ds.getPerUserDefaultAutoCommit("key")); } @Test public void testPerUserDefaultAutoCommitMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserDefaultAutoCommit(values); // TODO this is not consistent with the other methods assertNull(ds.getPerUserDefaultAutoCommit("missingkey")); } @Test public void testPerUserDefaultAutoCommitWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultAutoCommit(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user)); ds.setPerUserDefaultAutoCommit("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user)); assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anotheruser")); } @Test public void testPerUserDefaultAutoCommitWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultAutoCommit(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user)); } @Test public void testPerUserDefaultAutoCommitWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultAutoCommit("whatismyuseragain?", Boolean.FALSE); // TODO this is not consistent with the other methods assertNull(ds.getPerUserDefaultAutoCommit("missingkey")); } @Test public void testPerUserDefaultReadOnlyMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserDefaultReadOnly(values); assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("key")); values = new HashMap<>(); values.put("anonymous", Boolean.FALSE); ds.setPerUserDefaultReadOnly(values); assertNull(ds.getPerUserDefaultReadOnly("key")); assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anonymous")); } // -- per user default auto commit @Test public void testPerUserDefaultReadOnlyMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.TRUE); ds.setPerUserDefaultReadOnly(values); assertEquals(Boolean.TRUE, ds.getPerUserDefaultReadOnly("key")); } @Test public void testPerUserDefaultReadOnlyMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserDefaultReadOnly(values); // TODO this is not consistent with the other methods assertNull(ds.getPerUserDefaultReadOnly("missingkey")); } @Test public void testPerUserDefaultReadOnlyWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultReadOnly(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user)); ds.setPerUserDefaultReadOnly("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user)); assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anotheruser")); } @Test public void testPerUserDefaultReadOnlyWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultReadOnly(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user)); } @Test public void testPerUserDefaultReadOnlyWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultReadOnly("whatismyuseragain?", Boolean.FALSE); // TODO this is not consistent with the other methods assertNull(ds.getPerUserDefaultReadOnly("missingkey")); } @Test public void testPerUserDefaultTransactionIsolationMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserDefaultTransactionIsolation(values); assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("key")); values = new HashMap<>(); values.put("anonymous", 0); ds.setPerUserDefaultTransactionIsolation(values); // TODO this is not consistent with the other methods assertNull(ds.getPerUserDefaultTransactionIsolation("key")); assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anonymous")); } // -- per user default read only @Test public void testPerUserDefaultTransactionIsolationMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 1); ds.setPerUserDefaultTransactionIsolation(values); assertEquals((Integer) 1, ds.getPerUserDefaultTransactionIsolation("key")); } @Test public void testPerUserDefaultTransactionIsolationMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserDefaultTransactionIsolation(values); // TODO this is not consistent with the other methods assertNull(ds.getPerUserDefaultTransactionIsolation("missingkey")); } @Test public void testPerUserDefaultTransactionIsolationWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultTransactionIsolation(user, 0); assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user)); ds.setPerUserDefaultTransactionIsolation("anotheruser", 0); assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user)); assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anotheruser")); } @Test public void testPerUserDefaultTransactionIsolationWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultTransactionIsolation(user, 0); assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user)); } @Test public void testPerUserDefaultTransactionIsolationWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserDefaultTransactionIsolation("whatismyuseragain?", 0); // TODO this is not consistent with the other methods assertNull(ds.getPerUserDefaultTransactionIsolation("missingkey")); } @Test public void testPerUserEvictionPolicyClassNameMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", "bar"); ds.setPerUserEvictionPolicyClassName(values); assertEquals("bar", ds.getPerUserEvictionPolicyClassName("key")); values = new HashMap<>(); values.put("anonymous", "bar"); ds.setPerUserEvictionPolicyClassName(values); assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("key")); assertEquals("bar", ds.getPerUserEvictionPolicyClassName("anonymous")); } // -- per user default transaction isolation @Test public void testPerUserEvictionPolicyClassNameMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", "test"); ds.setPerUserEvictionPolicyClassName(values); assertEquals("test", ds.getPerUserEvictionPolicyClassName("key")); } @Test public void testPerUserEvictionPolicyClassNameMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", "bar"); ds.setPerUserEvictionPolicyClassName(values); assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey")); } @Test public void testPerUserEvictionPolicyClassNameWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserEvictionPolicyClassName(user, "bar"); assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user)); ds.setPerUserEvictionPolicyClassName("anotheruser", "bar"); assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user)); assertEquals("bar", ds.getPerUserEvictionPolicyClassName("anotheruser")); } @Test public void testPerUserEvictionPolicyClassNameWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserEvictionPolicyClassName(user, "bar"); assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user)); } @Test public void testPerUserEvictionPolicyClassNameWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserEvictionPolicyClassName("whatismyuseragain?", "bar"); assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey")); } @Test public void testPerUserLifoMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserLifo(values); assertEquals(Boolean.FALSE, ds.getPerUserLifo("key")); values = new HashMap<>(); values.put("anonymous", Boolean.FALSE); ds.setPerUserLifo(values); assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("key")); assertEquals(Boolean.FALSE, ds.getPerUserLifo("anonymous")); } // -- per user eviction policy class name @Test public void testPerUserLifoMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.TRUE); ds.setPerUserLifo(values); assertEquals(Boolean.TRUE, ds.getPerUserLifo("key")); } @Test public void testPerUserLifoMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserLifo(values); assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey")); } @Test public void testPerUserLifoWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserLifo(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserLifo(user)); ds.setPerUserLifo("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserLifo(user)); assertEquals(Boolean.FALSE, ds.getPerUserLifo("anotheruser")); } @Test public void testPerUserLifoWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserLifo(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserLifo(user)); } @Test public void testPerUserLifoWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserLifo("whatismyuseragain?", Boolean.FALSE); assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey")); } @Test public void testPerUserMaxIdleMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserMaxIdle(values); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("key")); values = new HashMap<>(); values.put("anonymous", 0); ds.setPerUserMaxIdle(values); assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("key")); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("anonymous")); } // -- per user lifo @Test public void testPerUserMaxIdleMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 1); ds.setPerUserMaxIdle(values); assertEquals((Integer) 1, (Integer) ds.getPerUserMaxIdle("key")); } @Test public void testPerUserMaxIdleMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserMaxIdle(values); assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey")); } @Test public void testPerUserMaxIdleWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxIdle(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user)); ds.setPerUserMaxIdle("anotheruser", 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user)); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("anotheruser")); } @Test public void testPerUserMaxIdleWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxIdle(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user)); } @Test public void testPerUserMaxIdleWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxIdle("whatismyuseragain?", 0); assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey")); } @Test public void testPerUserMaxTotalMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserMaxTotal(values); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("key")); values = new HashMap<>(); values.put("anonymous", 0); ds.setPerUserMaxTotal(values); assertEquals((Integer) ds.getDefaultMaxTotal(), (Integer) ds.getPerUserMaxTotal("key")); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("anonymous")); } // -- per user max idle @Test public void testPerUserMaxTotalMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 1); ds.setPerUserMaxTotal(values); assertEquals((Integer) 1, (Integer) ds.getPerUserMaxTotal("key")); } @Test public void testPerUserMaxTotalMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserMaxTotal(values); assertEquals((Integer) ds.getDefaultMaxTotal(), (Integer) ds.getPerUserMaxTotal("missingkey")); } @Test public void testPerUserMaxTotalWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxTotal(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user)); ds.setPerUserMaxTotal("anotheruser", 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user)); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("anotheruser")); } @Test public void testPerUserMaxTotalWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxTotal(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user)); } @Test public void testPerUserMaxTotalWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxTotal("whatismyuseragain?", 0); assertEquals((Integer) ds.getDefaultMaxTotal(), (Integer) ds.getPerUserMaxTotal("missingkey")); } @Test public void testPerUserMaxWaitDurationMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserMaxWaitDuration(values); assertEquals(Duration.ZERO, ds.getPerUserMaxWaitDuration("key")); values = new HashMap<>(); values.put("anonymous", Duration.ZERO); ds.setPerUserMaxWaitDuration(values); assertEquals(ds.getDefaultMaxWait(), ds.getPerUserMaxWaitDuration("key")); assertEquals(Duration.ZERO, ds.getPerUserMaxWaitDuration("anonymous")); } @Test public void testPerUserMaxWaitDurationMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", DURATION_1_MILLISECOND); ds.setPerUserMaxWaitDuration(values); assertEquals(DURATION_1_MILLISECOND, ds.getPerUserMaxWaitDuration("key")); } @Test public void testPerUserMaxWaitDurationMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserMaxWaitDuration(values); assertEquals(ds.getDefaultMaxWait(), ds.getPerUserMaxWaitDuration("missingkey")); } @Test @SuppressWarnings("deprecation") public void testPerUserMaxWaitMillisWithUserMapInitialized_Deprecated() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxWaitMillis(user, 0L); assertEquals(0L, ds.getPerUserMaxWaitMillis(user)); ds.setPerUserMaxWaitMillis("anotheruser", 0L); assertEquals(0L, ds.getPerUserMaxWaitMillis(user)); assertEquals(0L, ds.getPerUserMaxWaitMillis("anotheruser")); } @Test @SuppressWarnings("deprecation") public void testPerUserMaxWaitMillisWithUserMapNotInitialized_Deprecated() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxWaitMillis(user, 0L); assertEquals(0L, ds.getPerUserMaxWaitMillis(user)); } @Test @SuppressWarnings("deprecation") public void testPerUserMaxWaitMillisWithUserMapNotInitializedMissingKey_Deprecated() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMaxWaitMillis("whatismyuseragain?", 0L); assertEquals(ds.getDefaultMaxWaitMillis(), ds.getPerUserMaxWaitMillis("missingkey")); } @Test public void testPerUserMethods() throws Exception { final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds; // you need to set per user maxTotal otherwise there is no accounting tds.setPerUserMaxTotal("u1", 5); tds.setPerUserMaxTotal("u2", 5); assertEquals(0, tds.getNumActive()); assertEquals(0, tds.getNumActive("u1")); assertEquals(0, tds.getNumActive("u2")); assertEquals(0, tds.getNumIdle()); assertEquals(0, tds.getNumIdle("u1")); assertEquals(0, tds.getNumIdle("u2")); try (Connection conn = tds.getConnection()) { assertNotNull(conn); assertEquals(1, tds.getNumActive()); assertEquals(0, tds.getNumActive("u1")); assertEquals(0, tds.getNumActive("u2")); assertEquals(0, tds.getNumIdle()); assertEquals(0, tds.getNumIdle("u1")); assertEquals(0, tds.getNumIdle("u2")); } assertEquals(0, tds.getNumActive()); assertEquals(0, tds.getNumActive("u1")); assertEquals(0, tds.getNumActive("u2")); assertEquals(1, tds.getNumIdle()); assertEquals(0, tds.getNumIdle("u1")); assertEquals(0, tds.getNumIdle("u2")); try (Connection conn = tds.getConnection("u1", "p1")) { assertNotNull(conn); assertEquals(0, tds.getNumActive()); assertEquals(1, tds.getNumActive("u1")); assertEquals(0, tds.getNumActive("u2")); assertEquals(1, tds.getNumIdle()); assertEquals(0, tds.getNumIdle("u1")); assertEquals(0, tds.getNumIdle("u2")); } assertEquals(0, tds.getNumActive()); assertEquals(0, tds.getNumActive("u1")); assertEquals(0, tds.getNumActive("u2")); assertEquals(1, tds.getNumIdle()); assertEquals(1, tds.getNumIdle("u1")); assertEquals(0, tds.getNumIdle("u2")); } // -- per user max wait millis @Test public void testPerUserMinEvictableIdleDurationMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserMinEvictableIdle(values); assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("key")); assertEquals(Duration.ZERO, ds.getPerUserMinEvictableIdleDuration("key")); values = new HashMap<>(); values.put("anonymous", Duration.ZERO); ds.setPerUserMinEvictableIdle(values); assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("key")); assertEquals(ds.getDefaultMinEvictableIdleDuration(), ds.getPerUserMinEvictableIdleDuration("key")); assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("anonymous")); assertEquals(Duration.ZERO, ds.getPerUserMinEvictableIdleDuration("anonymous")); } @Test public void testPerUserMinEvictableIdleDurationMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", DURATION_1_MILLISECOND); ds.setPerUserMinEvictableIdle(values); assertEquals(1L, ds.getPerUserMinEvictableIdleTimeMillis("key")); assertEquals(DURATION_1_MILLISECOND, ds.getPerUserMinEvictableIdleDuration("key")); } @Test public void testPerUserMinEvictableIdleDurationMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserMinEvictableIdle(values); assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("missingkey")); assertEquals(ds.getDefaultMinEvictableIdleDuration(), ds.getPerUserMinEvictableIdleDuration("missingkey")); } @Test public void testPerUserMinEvictableIdleTimeMillisWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMinEvictableIdleTimeMillis(user, 0L); assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user)); ds.setPerUserMinEvictableIdleTimeMillis("anotheruser", 0L); assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user)); assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("anotheruser")); } @Test public void testPerUserMinEvictableIdleTimeMillisWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMinEvictableIdleTimeMillis(user, 0L); assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user)); } @Test public void testPerUserMinEvictableIdleTimeMillisWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMinEvictableIdleTimeMillis("whatismyuseragain?", 0L); assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("missingkey")); } // -- per user min evictable idle time millis @Test public void testPerUserMinIdleMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserMinIdle(values); assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("key")); values = new HashMap<>(); values.put("anonymous", 0); ds.setPerUserMinIdle(values); assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("key")); assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("anonymous")); } @Test public void testPerUserMinIdleMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 1); ds.setPerUserMinIdle(values); assertEquals((Integer) 1, (Integer) ds.getPerUserMinIdle("key")); } @Test public void testPerUserMinIdleMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserMinIdle(values); assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("missingkey")); } @Test public void testPerUserMinIdleWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMinIdle(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user)); ds.setPerUserMinIdle("anotheruser", 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user)); assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("anotheruser")); } @Test public void testPerUserMinIdleWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMinIdle(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user)); } @Test public void testPerUserMinIdleWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserMinIdle("whatismyuseragain?", 0); assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("missingkey")); } // -- per user min idle @Test public void testPerUserNumTestsPerEvictionRunMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserNumTestsPerEvictionRun(values); assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("key")); values = new HashMap<>(); values.put("anonymous", 0); ds.setPerUserNumTestsPerEvictionRun(values); assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("key")); assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("anonymous")); } @Test public void testPerUserNumTestsPerEvictionRunMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 1); ds.setPerUserNumTestsPerEvictionRun(values); assertEquals((Integer) 1, (Integer) ds.getPerUserNumTestsPerEvictionRun("key")); } @Test public void testPerUserNumTestsPerEvictionRunMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", 0); ds.setPerUserNumTestsPerEvictionRun(values); assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("missingkey")); } @Test public void testPerUserNumTestsPerEvictionRunWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserNumTestsPerEvictionRun(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user)); ds.setPerUserNumTestsPerEvictionRun("anotheruser", 0); assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user)); assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("anotheruser")); } @Test public void testPerUserNumTestsPerEvictionRunWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserNumTestsPerEvictionRun(user, 0); assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user)); } @Test public void testPerUserNumTestsPerEvictionRunWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserNumTestsPerEvictionRun("whatismyuseragain?", 0); assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("missingkey")); } // -- per user num tests per eviction run @Test public void testPerUserSoftMinEvictableIdleDurationMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserSoftMinEvictableIdle(values); assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("key")); assertEquals(Duration.ZERO, ds.getPerUserSoftMinEvictableIdleDuration("key")); values = new HashMap<>(); values.put("anonymous", Duration.ZERO); ds.setPerUserSoftMinEvictableIdle(values); assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("key")); assertEquals(ds.getDefaultSoftMinEvictableIdleDuration(), ds.getPerUserSoftMinEvictableIdleDuration("key")); assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("anonymous")); assertEquals(Duration.ZERO, ds.getPerUserSoftMinEvictableIdleDuration("anonymous")); } @Test public void testPerUserSoftMinEvictableIdleDurationMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", DURATION_1_MILLISECOND); ds.setPerUserSoftMinEvictableIdle(values); assertEquals(1L, ds.getPerUserSoftMinEvictableIdleTimeMillis("key")); assertEquals(DURATION_1_MILLISECOND, ds.getPerUserSoftMinEvictableIdleDuration("key")); } @Test public void testPerUserSoftMinEvictableIdleDurationMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserSoftMinEvictableIdle(values); assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("missingkey")); assertEquals(ds.getDefaultSoftMinEvictableIdleDuration(), ds.getPerUserSoftMinEvictableIdleDuration("missingkey")); } @Test public void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserSoftMinEvictableIdleTimeMillis(user, 0L); assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user)); ds.setPerUserSoftMinEvictableIdleTimeMillis("anotheruser", 0L); assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user)); assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("anotheruser")); } @Test public void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserSoftMinEvictableIdleTimeMillis(user, 0L); assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user)); } @Test public void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserSoftMinEvictableIdleTimeMillis("whatismyuseragain?", 0L); assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("missingkey")); } // -- per user soft min evictable idle time millis @Test public void testPerUserTestOnBorrowMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestOnBorrow(values); assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("key")); values = new HashMap<>(); values.put("anonymous", Boolean.FALSE); ds.setPerUserTestOnBorrow(values); assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("key")); assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("anonymous")); } @Test public void testPerUserTestOnBorrowMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.TRUE); ds.setPerUserTestOnBorrow(values); assertEquals(Boolean.TRUE, ds.getPerUserTestOnBorrow("key")); } @Test public void testPerUserTestOnBorrowMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestOnBorrow(values); assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("missingkey")); } @Test public void testPerUserTestOnBorrowWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnBorrow(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user)); ds.setPerUserTestOnBorrow("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user)); assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("anotheruser")); } @Test public void testPerUserTestOnBorrowWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnBorrow(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user)); } @Test public void testPerUserTestOnBorrowWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnBorrow("whatismyuseragain?", Boolean.FALSE); assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("missingkey")); } // -- per user test on borrow @Test public void testPerUserTestOnCreateMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestOnCreate(values); assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("key")); values = new HashMap<>(); values.put("anonymous", Boolean.FALSE); ds.setPerUserTestOnCreate(values); assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("key")); assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("anonymous")); } @Test public void testPerUserTestOnCreateMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.TRUE); ds.setPerUserTestOnCreate(values); assertEquals(Boolean.TRUE, ds.getPerUserTestOnCreate("key")); } @Test public void testPerUserTestOnCreateMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestOnCreate(values); assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("missingkey")); } @Test public void testPerUserTestOnCreateWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnCreate(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user)); ds.setPerUserTestOnCreate("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user)); assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("anotheruser")); } @Test public void testPerUserTestOnCreateWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnCreate(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user)); } @Test public void testPerUserTestOnCreateWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnCreate("whatismyuseragain?", Boolean.FALSE); assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("missingkey")); } // -- per user test on create @Test public void testPerUserTestOnReturnMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestOnReturn(values); assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("key")); values = new HashMap<>(); values.put("anonymous", Boolean.FALSE); ds.setPerUserTestOnReturn(values); assertEquals(ds.getDefaultTestOnReturn(), ds.getPerUserTestOnReturn("key")); assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("anonymous")); } @Test public void testPerUserTestOnReturnMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.TRUE); ds.setPerUserTestOnReturn(values); assertEquals(Boolean.TRUE, ds.getPerUserTestOnReturn("key")); } @Test public void testPerUserTestOnReturnMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestOnReturn(values); assertEquals(ds.getDefaultTestOnReturn(), ds.getPerUserTestOnReturn("missingkey")); } @Test public void testPerUserTestOnReturnWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnReturn(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user)); ds.setPerUserTestOnReturn("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user)); assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("anotheruser")); } @Test public void testPerUserTestOnReturnWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnReturn(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user)); } @Test public void testPerUserTestOnReturnWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestOnReturn("whatismyuseragain?", Boolean.FALSE); assertEquals(ds.getDefaultTestOnReturn(), ds.getPerUserTestOnReturn("missingkey")); } // -- per user test on return @Test public void testPerUserTestWhileIdleMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestWhileIdle(values); assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("key")); values = new HashMap<>(); values.put("anonymous", Boolean.FALSE); ds.setPerUserTestWhileIdle(values); assertEquals(ds.getDefaultTestWhileIdle(), ds.getPerUserTestWhileIdle("key")); assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("anonymous")); } @Test public void testPerUserTestWhileIdleMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.TRUE); ds.setPerUserTestWhileIdle(values); assertEquals(Boolean.TRUE, ds.getPerUserTestWhileIdle("key")); } @Test public void testPerUserTestWhileIdleMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Boolean.FALSE); ds.setPerUserTestWhileIdle(values); assertEquals(ds.getDefaultTestWhileIdle(), ds.getPerUserTestWhileIdle("missingkey")); } @Test public void testPerUserTestWhileIdleWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestWhileIdle(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user)); ds.setPerUserTestWhileIdle("anotheruser", Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user)); assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("anotheruser")); } @Test public void testPerUserTestWhileIdleWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestWhileIdle(user, Boolean.FALSE); assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user)); } @Test public void testPerUserTestWhileIdleWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTestWhileIdle("whatismyuseragain?", Boolean.FALSE); assertEquals(ds.getDefaultTestWhileIdle(), ds.getPerUserTestWhileIdle("missingkey")); } @Test public void testPerUserDurationBetweenEvictionRunsMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserDurationBetweenEvictionRuns(values); assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("key")); assertEquals(Duration.ZERO, ds.getPerUserDurationBetweenEvictionRuns("key")); values = new HashMap<>(); values.put("anonymous", Duration.ZERO); ds.setPerUserDurationBetweenEvictionRuns(values); assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("key")); assertEquals(ds.getDefaultDurationBetweenEvictionRuns(), ds.getPerUserDurationBetweenEvictionRuns("key")); assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("anonymous")); assertEquals(Duration.ZERO, ds.getPerUserDurationBetweenEvictionRuns("anonymous")); } @Test public void testPerUserDurationBetweenEvictionRunsMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", DURATION_1_MILLISECOND); ds.setPerUserDurationBetweenEvictionRuns(values); assertEquals(1L, ds.getPerUserTimeBetweenEvictionRunsMillis("key")); assertEquals(DURATION_1_MILLISECOND, ds.getPerUserDurationBetweenEvictionRuns("key")); } @Test public void testPerUserDurationBetweenEvictionRunsMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; final Map values = new HashMap<>(); values.put("key", Duration.ZERO); ds.setPerUserDurationBetweenEvictionRuns(values); assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("missingkey")); assertEquals(ds.getDefaultDurationBetweenEvictionRuns(), ds.getPerUserDurationBetweenEvictionRuns("missingkey")); } @Test public void testPerUserTimeBetweenEvictionRunsMillisWithUserMapInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTimeBetweenEvictionRunsMillis(user, 0L); assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user)); ds.setPerUserTimeBetweenEvictionRunsMillis("anotheruser", 0L); assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user)); assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("anotheruser")); } @Test public void testPerUserTimeBetweenEvictionRunsMillisWithUserMapNotInitialized() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTimeBetweenEvictionRunsMillis(user, 0L); assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user)); } @Test public void testPerUserTimeBetweenEvictionRunsMillisWithUserMapNotInitializedMissingKey() { final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds; ds.setPerUserTimeBetweenEvictionRunsMillis("whatismyuseragain?", 0L); assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("missingkey")); } // -- per user time between eviction runs millis @Test public void testSerialization() throws Exception { // make sure the pool has initialized final Connection conn = ds.getConnection(); conn.close(); // serialize final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(ds); out.close(); final byte[] b = baos.toByteArray(); final ByteArrayInputStream bais = new ByteArrayInputStream(b); final ObjectInputStream in = new ObjectInputStream(bais); final Object obj = in.readObject(); in.close(); assertEquals(1, ((PerUserPoolDataSource) obj).getNumIdle()); } @Override @Test public void testSimple() throws Exception { try (final Connection conn = ds.getConnection()) { assertNotNull(conn); try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (final ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } @Override @Test public void testSimple2() throws Exception { Connection conn = ds.getConnection(); assertNotNull(conn); PreparedStatement stmt = conn.prepareStatement("select * from dual"); assertNotNull(stmt); ResultSet rset = stmt.executeQuery(); assertNotNull(rset); assertTrue(rset.next()); rset.close(); stmt.close(); stmt = conn.prepareStatement("select * from dual"); assertNotNull(stmt); rset = stmt.executeQuery(); assertNotNull(rset); assertTrue(rset.next()); rset.close(); stmt.close(); conn.close(); try (Statement s = conn.createStatement()) { fail("Can't use closed connections"); } catch (final SQLException e) { // expected } conn = ds.getConnection(); assertNotNull(conn); stmt = conn.prepareStatement("select * from dual"); assertNotNull(stmt); rset = stmt.executeQuery(); assertNotNull(rset); assertTrue(rset.next()); rset.close(); stmt.close(); stmt = conn.prepareStatement("select * from dual"); assertNotNull(stmt); rset = stmt.executeQuery(); assertNotNull(rset); assertTrue(rset.next()); rset.close(); stmt.close(); conn.close(); conn = null; } @Test public void testSimpleWithUsername() throws Exception { try (final Connection conn = ds.getConnection("u1", "p1")) { assertNotNull(conn); try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (final ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } @Test public void testTransactionIsolationBehavior() throws Exception { try (Connection conn = getConnection()) { assertNotNull(conn); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); } final Connection conn2 = getConnection(); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation()); final Connection conn3 = getConnection(); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation()); conn2.close(); conn3.close(); } // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843 // unregistered user is in the same pool as without user name @Test public void testUnregisteredUser() throws Exception { final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds; assertEquals(0, tds.getNumActive()); assertEquals(0, tds.getNumIdle()); try (Connection conn = tds.getConnection()) { assertNotNull(conn); assertEquals(1, tds.getNumActive()); assertEquals(0, tds.getNumIdle()); } assertEquals(0, tds.getNumActive()); assertEquals(1, tds.getNumIdle()); try (Connection conn = tds.getConnection("u1", "p1")) { assertNotNull(conn); assertEquals(0, tds.getNumActive()); assertEquals(1, tds.getNumIdle()); assertEquals(1, tds.getNumActive("u1")); assertEquals(0, tds.getNumIdle("u1")); } assertEquals(0, tds.getNumActive()); assertEquals(1, tds.getNumIdle()); assertEquals(0, tds.getNumActive("u1")); assertEquals(1, tds.getNumIdle("u1")); } } TestPoolKey.java000066400000000000000000000044451447311732500340170ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests for PoolKey. * @since 2.5.0 */ public class TestPoolKey { private PoolKey poolKey; private PoolKey anotherPoolKey; @BeforeEach public void setUp() { poolKey = new PoolKey("ds", "user"); anotherPoolKey = new PoolKey(null, null); } @Test public void testEquals() { assertEquals(poolKey, poolKey); assertNotEquals(poolKey, null); assertNotEquals(poolKey, new Object()); assertNotEquals(new PoolKey(null, "user"), poolKey); assertEquals(new PoolKey(null, "user"), new PoolKey(null, "user")); assertNotEquals(new PoolKey(null, "user"), new PoolKey(null, "foo")); assertNotEquals(new PoolKey("ds", null), new PoolKey("foo", null)); assertNotEquals(new PoolKey("ds", null), poolKey); assertEquals(new PoolKey("ds", null), new PoolKey("ds", null)); } @Test public void testHashcode() { assertEquals(poolKey.hashCode(), new PoolKey("ds", "user").hashCode()); assertNotEquals(poolKey.hashCode(), anotherPoolKey.hashCode()); } @Test public void testToString() { assertEquals(poolKey.toString(), new PoolKey("ds", "user").toString()); assertNotEquals(poolKey.toString(), anotherPoolKey.toString()); } } TestSharedPoolDataSource.java000066400000000000000000000656011447311732500364510ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; import java.util.ArrayList; import javax.sql.DataSource; import org.apache.commons.dbcp2.DelegatingStatement; import org.apache.commons.dbcp2.TestConnectionPool; import org.apache.commons.dbcp2.TesterDriver; import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** */ public class TestSharedPoolDataSource extends TestConnectionPool { private static class CscbString extends AbstractPrepareCallCallback { @Override CallableStatement getCallableStatement() throws SQLException { return conn.prepareCall("{call home()}"); } } private static class CscbStringIntInt extends AbstractPrepareCallCallback { @Override CallableStatement getCallableStatement() throws SQLException { return conn.prepareCall("{call home()}", 0, 0); } } private static class CscbStringIntIntInt extends AbstractPrepareCallCallback { @Override CallableStatement getCallableStatement() throws SQLException { return conn.prepareCall("{call home()}", 0, 0, 0); } } /** * There are 3 different prepareCall statement methods so add a little complexity to reduce what would otherwise be lots * of copy and paste. */ private static abstract class AbstractPrepareCallCallback { protected Connection conn; abstract CallableStatement getCallableStatement() throws SQLException; void setConnection(final Connection conn) { this.conn = conn; } } /** * There are 6 different prepareStatement statement methods so add a little complexity to reduce what would otherwise be * lots of copy and paste. */ private static abstract class AbstractPrepareStatementCallback { protected Connection conn; abstract PreparedStatement prepareStatement() throws SQLException; void setConnection(final Connection conn) { this.conn = conn; } } private static class PscbString extends AbstractPrepareStatementCallback { @Override PreparedStatement prepareStatement() throws SQLException { return conn.prepareStatement("select * from dual"); } } private static class PscbStringInt extends AbstractPrepareStatementCallback { @Override PreparedStatement prepareStatement() throws SQLException { return conn.prepareStatement("select * from dual", 0); } } private static class PscbStringIntArray extends AbstractPrepareStatementCallback { @Override PreparedStatement prepareStatement() throws SQLException { return conn.prepareStatement("select * from dual", ArrayUtils.EMPTY_INT_ARRAY); } } private static class PscbStringIntInt extends AbstractPrepareStatementCallback { @Override PreparedStatement prepareStatement() throws SQLException { return conn.prepareStatement("select * from dual", 0, 0); } } private static class PscbStringIntIntInt extends AbstractPrepareStatementCallback { @Override PreparedStatement prepareStatement() throws SQLException { return conn.prepareStatement("select * from dual", 0, 0, 0); } } private static class PscbStringStringArray extends AbstractPrepareStatementCallback { @Override PreparedStatement prepareStatement() throws SQLException { return conn.prepareStatement("select * from dual", ArrayUtils.EMPTY_STRING_ARRAY); } } private DriverAdapterCPDS pcds; private DataSource ds; private void doTestPoolCallableStatements(final AbstractPrepareCallCallback callBack) throws Exception { final DriverAdapterCPDS myPcds = new DriverAdapterCPDS(); myPcds.setDriver("org.apache.commons.dbcp2.TesterDriver"); myPcds.setUrl("jdbc:apache:commons:testdriver"); myPcds.setUser("foo"); myPcds.setPassword("bar"); myPcds.setPoolPreparedStatements(true); myPcds.setMaxPreparedStatements(10); try (final SharedPoolDataSource spDs = new SharedPoolDataSource()) { spDs.setConnectionPoolDataSource(myPcds); spDs.setMaxTotal(getMaxTotal()); spDs.setDefaultMaxWait(getMaxWaitDuration()); spDs.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); @SuppressWarnings("resource") final DataSource myDs = spDs; try (Connection conn = ds.getConnection()) { callBack.setConnection(conn); assertNotNull(conn); final long l1HashCode; final long l2HashCode; try (CallableStatement stmt = callBack.getCallableStatement()) { assertNotNull(stmt); l1HashCode = getDelegateHashCode(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } try (CallableStatement stmt = callBack.getCallableStatement()) { assertNotNull(stmt); l2HashCode = getDelegateHashCode(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } // statement pooling is not enabled, we should get different statements assertTrue(l1HashCode != l2HashCode); } try (Connection conn = myDs.getConnection()) { callBack.setConnection(conn); final long l3HashCode; final long l4HashCode; try (CallableStatement stmt = callBack.getCallableStatement()) { assertNotNull(stmt); l3HashCode = getDelegateHashCode(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } try (CallableStatement stmt = callBack.getCallableStatement()) { assertNotNull(stmt); l4HashCode = getDelegateHashCode(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } // prepared statement pooling is working assertEquals(l3HashCode, l4HashCode); } } } private void doTestPoolPreparedStatements(final AbstractPrepareStatementCallback psCallBack) throws Exception { final DriverAdapterCPDS mypcds = new DriverAdapterCPDS(); mypcds.setDriver("org.apache.commons.dbcp2.TesterDriver"); mypcds.setUrl("jdbc:apache:commons:testdriver"); mypcds.setUser("foo"); mypcds.setPassword("bar"); mypcds.setPoolPreparedStatements(true); mypcds.setMaxPreparedStatements(10); try (final SharedPoolDataSource tds = new SharedPoolDataSource()) { tds.setConnectionPoolDataSource(mypcds); tds.setMaxTotal(getMaxTotal()); tds.setDefaultMaxWait(getMaxWaitDuration()); tds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); @SuppressWarnings("resource") DataSource myDs = tds; try (Connection conn = ds.getConnection()) { final long l1HashCode; final long l2HashCode; assertNotNull(conn); psCallBack.setConnection(conn); try (PreparedStatement stmt = psCallBack.prepareStatement()) { assertNotNull(stmt); l1HashCode = getDelegateHashCode(stmt); try (ResultSet resultSet = stmt.executeQuery()) { assertNotNull(resultSet); assertTrue(resultSet.next()); } } try (PreparedStatement stmt = psCallBack.prepareStatement()) { assertNotNull(stmt); l2HashCode = getDelegateHashCode(stmt); try (ResultSet resultSet = stmt.executeQuery()) { assertNotNull(resultSet); assertTrue(resultSet.next()); } } // statement pooling is not enabled, we should get different statements assertTrue(l1HashCode != l2HashCode); } try (Connection conn = myDs.getConnection()) { final long l3HashCode; final long l4HashCode; assertNotNull(conn); psCallBack.setConnection(conn); try (PreparedStatement stmt = psCallBack.prepareStatement()) { assertNotNull(stmt); l3HashCode = getDelegateHashCode(stmt); try (ResultSet resultSet = stmt.executeQuery()) { assertNotNull(resultSet); assertTrue(resultSet.next()); } } try (PreparedStatement stmt = psCallBack.prepareStatement()) { assertNotNull(stmt); l4HashCode = getDelegateHashCode(stmt); try (ResultSet resultSet = stmt.executeQuery()) { assertNotNull(resultSet); assertTrue(resultSet.next()); } } // prepared statement pooling is working assertEquals(l3HashCode, l4HashCode); } } } @Override protected Connection getConnection() throws Exception { return ds.getConnection("foo","bar"); } @SuppressWarnings("resource") private int getDelegateHashCode(final Statement stmt) { return ((DelegatingStatement) stmt).getDelegate().hashCode(); } @BeforeEach public void setUp() throws Exception { pcds = new DriverAdapterCPDS(); pcds.setDriver("org.apache.commons.dbcp2.TesterDriver"); pcds.setUrl("jdbc:apache:commons:testdriver"); pcds.setUser("foo"); pcds.setPassword("bar"); pcds.setPoolPreparedStatements(false); pcds.setAccessToUnderlyingConnectionAllowed(true); final SharedPoolDataSource tds = new SharedPoolDataSource(); tds.setConnectionPoolDataSource(pcds); tds.setMaxTotal(getMaxTotal()); tds.setDefaultMaxWait(getMaxWaitDuration()); tds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); tds.setDefaultAutoCommit(Boolean.TRUE); ds = tds; } // See DBCP-8 @Test public void testChangePassword() throws Exception { assertThrows(SQLException.class, () -> ds.getConnection("foo", "bay")); final Connection con1 = ds.getConnection("foo", "bar"); final Connection con2 = ds.getConnection("foo", "bar"); final Connection con3 = ds.getConnection("foo", "bar"); con1.close(); con2.close(); TesterDriver.addUser("foo", "bay"); // change the user/password setting try (Connection con4 = ds.getConnection("foo", "bay")) { // new password // Idle instances with old password should have been cleared assertEquals(0, ((SharedPoolDataSource) ds).getNumIdle(), "Should be no idle connections in the pool"); con4.close(); // Should be one idle instance with new pwd assertEquals(1, ((SharedPoolDataSource) ds).getNumIdle(), "Should be one idle connection in the pool"); assertThrows(SQLException.class, () -> ds.getConnection("foo", "bar")); // old password try (final Connection con5 = ds.getConnection("foo", "bay")) { // take the idle one con3.close(); // Return a connection with the old password ds.getConnection("foo", "bay").close(); // will try bad returned connection and destroy it assertEquals(1, ((SharedPoolDataSource) ds).getNumIdle(), "Should be one idle connection in the pool"); } } finally { TesterDriver.addUser("foo", "bar"); } } /** * Tests pool close. Illustrates BZ 37359. * * @throws Exception */ @Test public void testClosePool() throws Exception { ((SharedPoolDataSource) ds).close(); @SuppressWarnings("resource") // closed below final SharedPoolDataSource tds = new SharedPoolDataSource(); // NPE before BZ 37359 fix tds.close(); } @Override @Test public void testClosing() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; // open the maximum connections for (int i = 0; i < c.length; i++) { c[i] = ds.getConnection(); } // close one of the connections c[0].close(); assertTrue(c[0].isClosed()); // get a new connection c[0] = ds.getConnection(); for (final Connection element : c) { element.close(); } } @Test public void testClosingWithUserName() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; // open the maximum connections for (int i = 0; i < c.length; i++) { c[i] = ds.getConnection("u1", "p1"); } // close one of the connections c[0].close(); assertTrue(c[0].isClosed()); // get a new connection c[0] = ds.getConnection("u1", "p1"); for (final Connection element : c) { element.close(); } // open the maximum connections for (int i = 0; i < c.length; i++) { c[i] = ds.getConnection("u1", "p1"); } for (final Connection element : c) { element.close(); } } @Test public void testDbcp369() { final ArrayList dataSources = new ArrayList<>(); for (int j = 0; j < 10000; j++) { dataSources.add(new SharedPoolDataSource()); } final Thread t1 = new Thread(() -> { for (final SharedPoolDataSource dataSource : dataSources) { dataSource.setDataSourceName("a"); } }); final Thread t2 = new Thread(() -> { for (final SharedPoolDataSource dataSource : dataSources) { try { dataSource.close(); } catch (final Exception e) { // Ignore } } }); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (final InterruptedException ie) { // Ignore } } /** * Starting with a successful connection, then incorrect password, * then correct password for same user illustrates * JIRA: DBCP-245 */ @Test public void testIncorrectPassword() throws SQLException { ds.getConnection("u2", "p2").close(); try (Connection c = ds.getConnection("u1", "zlsafjk")){ // Use bad password fail("Able to retrieve connection with incorrect password"); } catch (final SQLException e1) { // should fail } // Use good password ds.getConnection("u1", "p1").close(); try (Connection c = ds.getConnection("u1", "x")) { fail("Able to retrieve connection with incorrect password"); } catch (final SQLException e) { if (!e.getMessage().startsWith("Given password did not match")) { throw e; } // else the exception was expected } // Make sure we can still use our good password. ds.getConnection("u1", "p1").close(); // Try related users and passwords ds.getConnection("foo", "bar").close(); try (Connection c = ds.getConnection("u1", "ar")) { fail("Should have caused an SQLException"); } catch (final SQLException expected) { } try (Connection c = ds.getConnection("u1", "baz")) { fail("Should have generated SQLException"); } catch (final SQLException expected) { } } @Override @Test public void testMaxTotal() throws Exception { final Connection[] c = new Connection[getMaxTotal()]; for (int i=0; i conn.createStatement(), "Can't use closed connections"); } try (Connection conn = ds.getConnection()) { assertNotNull(conn); try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } @Test public void testSimpleWithUsername() throws Exception { try (final Connection conn = ds.getConnection("u1", "p1")) { assertNotNull(conn); try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) { assertNotNull(stmt); try (final ResultSet rset = stmt.executeQuery()) { assertNotNull(rset); assertTrue(rset.next()); } } } } @Test public void testTransactionIsolationBehavior() throws Exception { try (final Connection conn = getConnection()) { assertNotNull(conn); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); } final Connection conn2 = getConnection(); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation()); final Connection conn3 = getConnection(); assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation()); conn2.close(); conn3.close(); } } TestUserPassKey.java000066400000000000000000000057311447311732500346520ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/datasources/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.datasources; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import org.apache.commons.dbcp2.Utils; import org.apache.commons.lang3.SerializationUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests for UserPassKey. */ public class TestUserPassKey { private UserPassKey userPassKey; private UserPassKey anotherUserPassKey; @BeforeEach public void setUp() { userPassKey = new UserPassKey("user", "pass"); anotherUserPassKey = new UserPassKey((String) null, ""); } @Test public void testEquals() { assertEquals(new UserPassKey("user"), new UserPassKey("user", (char[]) null)); assertEquals(userPassKey, userPassKey); assertNotEquals(userPassKey, null); assertNotEquals(userPassKey, new Object()); assertNotEquals(new UserPassKey(null), userPassKey); assertEquals(new UserPassKey(null), new UserPassKey(null)); assertNotEquals(new UserPassKey("user", "pass"), new UserPassKey("foo", "pass")); } @Test public void testGettersAndSetters() { assertEquals("user", userPassKey.getUserName()); assertEquals("pass", userPassKey.getPassword()); assertArrayEquals(Utils.toCharArray("pass"), userPassKey.getPasswordCharArray()); } @Test public void testHashcode() { assertEquals(userPassKey.hashCode(), new UserPassKey("user", "pass").hashCode()); assertNotEquals(userPassKey.hashCode(), anotherUserPassKey.hashCode()); } @Test public void testSerialization() { assertEquals(userPassKey, SerializationUtils.roundtrip(userPassKey)); assertEquals(anotherUserPassKey, SerializationUtils.roundtrip(anotherUserPassKey)); } @Test public void testToString() { assertEquals(userPassKey.toString(), new UserPassKey("user", "pass").toString()); assertNotEquals(userPassKey.toString(), anotherUserPassKey.toString()); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/000077500000000000000000000000001447311732500300615ustar00rootroot00000000000000TestBasicManagedDataSource.java000066400000000000000000000264561447311732500357730ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.SQLException; import javax.sql.XADataSource; import javax.transaction.TransactionManager; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAException; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.TestBasicDataSource; import org.apache.geronimo.transaction.manager.TransactionManagerImpl; import org.h2.Driver; import org.h2.jdbcx.JdbcDataSource; import org.junit.jupiter.api.Test; import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple; import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple; /** * TestSuite for BasicManagedDataSource */ public class TestBasicManagedDataSource extends TestBasicDataSource { @Override protected BasicDataSource createDataSource() throws Exception { final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource(); final TransactionManagerImpl transactionManager = new TransactionManagerImpl(); basicManagedDataSource.setTransactionManager(transactionManager); basicManagedDataSource.setTransactionSynchronizationRegistry(transactionManager); return basicManagedDataSource; } @Test public void testCreateXaDataSourceNewInstance() throws SQLException, XAException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setXADataSource(JdbcDataSource.class.getCanonicalName()); basicManagedDataSource.setDriverClassName(Driver.class.getName()); basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); assertNotNull(basicManagedDataSource.createConnectionFactory()); } } @Test public void testCreateXaDataSourceNoInstanceSetAndNoDataSource() throws SQLException, XAException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); assertNotNull(basicManagedDataSource.createConnectionFactory()); } } /** * JIRA: DBCP-294 * Verify that PoolableConnections created by BasicManagedDataSource unregister themselves * when reallyClosed. */ @Test public void testReallyClose() throws Exception { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); basicManagedDataSource.setUsername("userName"); basicManagedDataSource.setPassword("password"); basicManagedDataSource.setMaxIdle(1); // Create two connections final ManagedConnection conn = (ManagedConnection) basicManagedDataSource.getConnection(); assertNotNull(basicManagedDataSource.getTransactionRegistry().getXAResource(conn)); final ManagedConnection conn2 = (ManagedConnection) basicManagedDataSource.getConnection(); conn2.close(); // Return one connection to the pool conn.close(); // No room at the inn - this will trigger reallyClose(), which should unregister assertThrows(SQLException.class, () -> basicManagedDataSource.getTransactionRegistry().getXAResource(conn), "Expecting SQLException - XAResources orphaned"); conn2.close(); } } @Test public void testRuntimeExceptionsAreRethrown() throws SQLException, XAException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); basicManagedDataSource.setUsername("userName"); basicManagedDataSource.setPassword("password"); basicManagedDataSource.setMaxIdle(1); // results in a NPE assertThrows(NullPointerException.class, () -> basicManagedDataSource.createPoolableConnectionFactory(null)); } } @Test public void testSetDriverName() throws SQLException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setDriverClassName("adams"); assertEquals("adams", basicManagedDataSource.getDriverClassName()); basicManagedDataSource.setDriverClassName(null); assertNull(basicManagedDataSource.getDriverClassName()); } } @Test public void testSetNullXaDataSourceInstance() throws SQLException, XAException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); basicManagedDataSource.setUsername("userName"); basicManagedDataSource.setPassword("password"); basicManagedDataSource.setMaxIdle(1); basicManagedDataSource.setXaDataSourceInstance(null); assertNull(basicManagedDataSource.getXaDataSourceInstance()); } } /** DBCP-564 */ @Test public void testSetRollbackOnlyBeforeGetConnectionDoesNotLeak() throws Exception { final TransactionManager transactionManager = ((BasicManagedDataSource) ds).getTransactionManager(); final int n = 3; ds.setMaxIdle(n); ds.setMaxTotal(n); for (int i = 0; i <= n; i++) { // loop n+1 times transactionManager.begin(); transactionManager.setRollbackOnly(); try (final Connection conn = getConnection()) { assertNotNull(conn); } transactionManager.rollback(); } assertEquals(0, ds.getNumActive()); assertEquals(1, ds.getNumIdle()); } @Test public void testSetXaDataSourceInstance() throws SQLException, XAException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); basicManagedDataSource.setUsername("userName"); basicManagedDataSource.setPassword("password"); basicManagedDataSource.setMaxIdle(1); basicManagedDataSource.setXaDataSourceInstance(new JdbcDataSource()); assertNotNull(basicManagedDataSource.createConnectionFactory()); } } @Test public void testTransactionManagerNotSet() throws SQLException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { assertThrows(SQLException.class, basicManagedDataSource::createConnectionFactory); } } @Test public void testTransactionSynchronizationRegistry() throws Exception { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setTransactionManager(new TransactionManagerImple()); final TransactionSynchronizationRegistry tsr = new TransactionSynchronizationRegistryImple(); basicManagedDataSource.setTransactionSynchronizationRegistry(tsr); final JdbcDataSource xaDataSource = new JdbcDataSource(); xaDataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); basicManagedDataSource.setXaDataSourceInstance(xaDataSource); basicManagedDataSource.setMaxIdle(1); final TransactionManager tm = basicManagedDataSource.getTransactionManager(); tm.begin(); tsr.registerInterposedSynchronization(new SynchronizationAdapter() { @Override public void beforeCompletion() { Connection connection = null; try { connection = basicManagedDataSource.getConnection(); assertNotNull(connection); } catch (final SQLException e) { fail(e.getMessage()); } finally { if (connection != null) { try { connection.close(); } catch (final SQLException e) { fail(e.getMessage()); } } } } }); tm.commit(); } } @Test public void testXADataSource() throws SQLException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setXADataSource("anything"); assertEquals("anything", basicManagedDataSource.getXADataSource()); } } @Test public void testXaDataSourceInstance() throws SQLException { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { final XADataSource ds = new JdbcDataSource(); basicManagedDataSource.setXaDataSourceInstance(ds); assertEquals(ds, basicManagedDataSource.getXaDataSourceInstance()); } } } TestConnectionWithNarayana.java000066400000000000000000000204471447311732500361220ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.time.Duration; import javax.transaction.RollbackException; import javax.transaction.Status; import org.apache.commons.dbcp2.Utils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple; import com.arjuna.ats.jta.common.jtaPropertyManager; /** * Requires Java 8. */ public class TestConnectionWithNarayana { private static final String CREATE_STMT = "CREATE TABLE TEST_DATA (KEY1 VARCHAR(100), ID BIGINT, VALUE1 DOUBLE PRECISION, INFO TEXT, TS TIMESTAMP)"; private static final String INSERT_STMT = "INSERT INTO TEST_DATA (KEY1, ID, VALUE1, INFO, TS) VALUES (?,?,?,?,?)"; private static final String SELECT_STMT = "SELECT KEY1, ID, VALUE1, INFO, TS FROM TEST_DATA LIMIT 1"; private static final String PAYLOAD; private static final String DROP_STMT = "DROP TABLE TEST_DATA"; static { final StringBuilder sb = new StringBuilder(); sb.append("Start"); sb.append("payload"); for (int i = 0; i < 10000; i++) { sb.append("..."); sb.append(i); } sb.append("End"); sb.append("payload"); PAYLOAD = sb.toString(); } private BasicManagedDataSource mds; @BeforeEach public void setUp() throws Exception { jtaPropertyManager.getJTAEnvironmentBean().setLastResourceOptimisationInterfaceClassName( "org.apache.commons.dbcp2.managed.LocalXAConnectionFactory$LocalXAResource"); mds = new BasicManagedDataSource(); mds.setTransactionManager(new TransactionManagerImple()); mds.setDriverClassName("org.h2.Driver"); mds.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); mds.setMaxTotal(80); mds.setMinIdle(0); mds.setMaxIdle(80); mds.setMinEvictableIdle(Duration.ofSeconds(10)); mds.setDurationBetweenEvictionRuns(Duration.ofSeconds(10)); mds.setLogAbandoned(true); mds.setMaxWait(Duration.ofSeconds(2)); mds.setRemoveAbandonedOnMaintenance(true); mds.setRemoveAbandonedOnBorrow(true); mds.setRemoveAbandonedTimeout(Duration.ofSeconds(10)); mds.setLogExpiredConnections(true); mds.setLifo(false); try (final Connection conn = mds.getConnection()) { try (final PreparedStatement ps = conn.prepareStatement(CREATE_STMT)) { ps.execute(); } } } @AfterEach public void tearDown() throws Exception { try (final Connection conn = mds.getConnection()) { try (final PreparedStatement ps = conn.prepareStatement(DROP_STMT)) { ps.execute(); } } Utils.closeQuietly(mds); } @Test public void testConnectionCommitAfterTimeout() throws Exception { mds.getTransactionManager().setTransactionTimeout(1); mds.getTransactionManager().begin(); try (Connection conn = mds.getConnection()) { do { Thread.sleep(1000); } while (mds.getTransactionManager().getTransaction().getStatus() != Status.STATUS_ROLLEDBACK); // Let the reaper do it's thing Thread.sleep(1000); try { conn.commit(); fail("Should not work after timeout"); } catch (final SQLException e) { // Expected Assertions.assertEquals("Commit can not be set while enrolled in a transaction", e.getMessage()); } mds.getTransactionManager().rollback(); } Assertions.assertEquals(0, mds.getNumActive()); } @Test public void testConnectionInTimeout() throws Exception { Connection conn = null; PreparedStatement ps = null; for (int i = 0; i < 5; i++) { try { mds.getTransactionManager().setTransactionTimeout(1); mds.getTransactionManager().begin(); conn = mds.getConnection(); ps = conn.prepareStatement(INSERT_STMT); ps.setString(1, Thread.currentThread().getName()); ps.setLong(2, i); ps.setDouble(3, new java.util.Random().nextDouble()); ps.setString(4, PAYLOAD); ps.setTimestamp(5, new Timestamp(System.currentTimeMillis())); ps.execute(); int n = 0; do { if (mds.getTransactionManager().getTransaction().getStatus() != Status.STATUS_ACTIVE) { n++; } try (Connection c = mds.getConnection(); PreparedStatement ps2 = c.prepareStatement(SELECT_STMT); ResultSet rs = ps2.executeQuery()) { // nothing here, all auto-close. } } while (n < 2); ps.close(); ps = null; conn.close(); conn = null; try { mds.getTransactionManager().commit(); fail("Should not have been able to commit"); } catch (final RollbackException e) { // this is expected if (mds.getTransactionManager().getTransaction() != null) { // Need to pop it off the thread if a background thread rolled the transaction back mds.getTransactionManager().rollback(); } } } catch (final Exception e) { if (mds.getTransactionManager().getTransaction() != null) { // Need to pop it off the thread if a background thread rolled the transaction back mds.getTransactionManager().rollback(); } } finally { if (ps != null) { ps.close(); } if (conn != null) { conn.close(); } } Assertions.assertEquals(0, mds.getNumActive()); } } @Test public void testRepeatedGetConnectionInTimeout() throws Exception { mds.getTransactionManager().setTransactionTimeout(1); mds.getTransactionManager().begin(); try { do { Thread.sleep(1000); } while (mds.getTransactionManager().getTransaction().getStatus() != Status.STATUS_ROLLEDBACK); // Let the reaper do it's thing Thread.sleep(1000); try (Connection conn = mds.getConnection()) { fail("Should not get the connection 1"); } catch (final SQLException e) { if (!e.getCause().getClass().equals(IllegalStateException.class)) { throw e; } try (Connection conn = mds.getConnection()) { fail("Should not get connection 2"); } catch (final SQLException e2) { if (!e2.getCause().getClass().equals(IllegalStateException.class)) { throw e2; } } } } finally { mds.getTransactionManager().rollback(); } Assertions.assertEquals(0, mds.getNumActive()); } }TestDataSourceXAConnectionFactory.java000066400000000000000000000076461447311732500373550ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.atomic.AtomicInteger; import javax.sql.XAConnection; import javax.sql.XADataSource; import org.apache.commons.dbcp2.TestBasicDataSource; import org.apache.geronimo.transaction.manager.TransactionManagerImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * TestSuite for BasicManagedDataSource when using a * DataSourceXAConnectionFactory (configured from a XADataSource) */ public class TestDataSourceXAConnectionFactory extends TestBasicDataSource { /** * Delegates everything to the BasicDataSource (ds field), except for * getXAConnection which creates a BasicXAConnection. */ public class XADataSourceHandle implements InvocationHandler { protected XAConnection getXAConnection() throws SQLException { return new TesterBasicXAConnection(ds.getConnection(), closeCounter); } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { final String methodName = method.getName(); if (methodName.equals("hashCode")) { return System.identityHashCode(proxy); } if (methodName.equals("equals")) { return proxy == args[0]; } if (methodName.equals("getXAConnection")) { // both zero and 2-arg signatures return getXAConnection(); } try { return method.invoke(ds, args); } catch (final InvocationTargetException e) { throw e.getTargetException(); } } } protected BasicManagedDataSource bmds; public final AtomicInteger closeCounter = new AtomicInteger(); @Override @BeforeEach public void setUp() throws Exception { super.setUp(); bmds = new BasicManagedDataSource(); bmds.setTransactionManager(new TransactionManagerImpl()); bmds.setXADataSource("notnull"); final XADataSourceHandle handle = new XADataSourceHandle(); final XADataSource xads = (XADataSource) Proxy.newProxyInstance( XADataSourceHandle.class.getClassLoader(), new Class[] { XADataSource.class }, handle); bmds.setXaDataSourceInstance(xads); } /** * JIRA: DBCP-355 */ @Test public void testPhysicalClose() throws Exception { bmds.setMaxIdle(1); final Connection conn1 = bmds.getConnection(); final Connection conn2 = bmds.getConnection(); closeCounter.set(0); conn1.close(); assertEquals(0, closeCounter.get()); // stays idle in the pool conn2.close(); assertEquals(1, closeCounter.get()); // can't have 2 idle ones bmds.close(); assertEquals(2, closeCounter.get()); } } TestLocalXaResource.java000066400000000000000000000451101447311732500345410ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests for LocalXAConnectionFactory$LocalXAResource */ public class TestLocalXaResource { private static class TestConnection implements Connection { public boolean throwWhenGetAutoCommit; public boolean throwWhenSetAutoCommit; boolean autoCommit; boolean readOnly; public boolean committed; public boolean rolledback; public boolean closed; @Override public void abort(final Executor executor) throws SQLException { } @Override public void clearWarnings() throws SQLException { } @Override public void close() throws SQLException { closed = true; } @Override public void commit() throws SQLException { committed = true; } @Override public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { return null; } @Override public Blob createBlob() throws SQLException { return null; } @Override public Clob createClob() throws SQLException { return null; } @Override public NClob createNClob() throws SQLException { return null; } @Override public SQLXML createSQLXML() throws SQLException { return null; } @Override public Statement createStatement() throws SQLException { return null; } @Override public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { return null; } @Override public Statement createStatement(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { return null; } @Override public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { return null; } @Override public boolean getAutoCommit() throws SQLException { if (throwWhenGetAutoCommit) { throw new SQLException(); } return autoCommit; } @Override public String getCatalog() throws SQLException { return null; } @Override public Properties getClientInfo() throws SQLException { return null; } @Override public String getClientInfo(final String name) throws SQLException { return null; } @Override public int getHoldability() throws SQLException { return 0; } @Override public DatabaseMetaData getMetaData() throws SQLException { return null; } @Override public int getNetworkTimeout() throws SQLException { return 0; } @Override public String getSchema() throws SQLException { return null; } @Override public int getTransactionIsolation() throws SQLException { return 0; } @Override public Map> getTypeMap() throws SQLException { return null; } @Override public SQLWarning getWarnings() throws SQLException { return null; } @Override public boolean isClosed() throws SQLException { return closed; } @Override public boolean isReadOnly() throws SQLException { return readOnly; } @Override public boolean isValid(final int timeout) throws SQLException { return false; } @Override public boolean isWrapperFor(final Class iface) throws SQLException { return false; } @Override public String nativeSQL(final String sql) throws SQLException { return null; } @Override public CallableStatement prepareCall(final String sql) throws SQLException { return null; } @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { return null; } @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(final String sql) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { return null; } @Override public void releaseSavepoint(final Savepoint savepoint) throws SQLException { } @Override public void rollback() throws SQLException { rolledback = true; } @Override public void rollback(final Savepoint savepoint) throws SQLException { } @Override public void setAutoCommit(final boolean autoCommit) throws SQLException { if (throwWhenSetAutoCommit) { throw new SQLException(); } this.autoCommit = autoCommit; } @Override public void setCatalog(final String catalog) throws SQLException { } @Override public void setClientInfo(final Properties properties) throws SQLClientInfoException { } @Override public void setClientInfo(final String name, final String value) throws SQLClientInfoException { } @Override public void setHoldability(final int holdability) throws SQLException { } @Override public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { } @Override public void setReadOnly(final boolean readOnly) throws SQLException { this.readOnly = readOnly; } @Override public Savepoint setSavepoint() throws SQLException { return null; } @Override public Savepoint setSavepoint(final String name) throws SQLException { return null; } @Override public void setSchema(final String schema) throws SQLException { } @Override public void setTransactionIsolation(final int level) throws SQLException { } @Override public void setTypeMap(final Map> map) throws SQLException { } @Override public T unwrap(final Class iface) throws SQLException { return null; } } private static class TestXid implements Xid { @Override public byte[] getBranchQualifier() { return null; } @Override public int getFormatId() { return 0; } @Override public byte[] getGlobalTransactionId() { return null; } } private Connection conn; private LocalXAConnectionFactory.LocalXAResource resource; @BeforeEach public void setUp() { conn = new TestConnection(); resource = new LocalXAConnectionFactory.LocalXAResource(conn); } @Test public void testCommit() throws SQLException, XAException { final Xid xid = new TestXid(); ((TestConnection) conn).closed = false; conn.setReadOnly(false); resource.start(xid, XAResource.TMNOFLAGS); resource.commit(xid, false); assertTrue(((TestConnection) conn).committed); } @Test public void testCommitConnectionClosed() throws SQLException, XAException { final Xid xid = new TestXid(); ((TestConnection) conn).closed = true; conn.setReadOnly(false); resource.start(xid, XAResource.TMNOFLAGS); assertThrows(XAException.class, () -> resource.commit(xid, false)); } @Test public void testCommitConnectionNotReadOnly() throws SQLException, XAException { final Xid xid = new TestXid(); ((TestConnection) conn).closed = false; conn.setReadOnly(true); resource.start(xid, XAResource.TMNOFLAGS); resource.commit(xid, false); assertFalse(((TestConnection) conn).committed); } @Test public void testCommitInvalidXid() throws SQLException, XAException { final Xid xid = new TestXid(); ((TestConnection) conn).closed = false; conn.setReadOnly(false); resource.start(xid, XAResource.TMNOFLAGS); assertThrows(XAException.class, () -> resource.commit(new TestXid(), false)); } @Test public void testCommitMissingXid() { assertThrows(NullPointerException.class, () -> resource.commit(null, false)); } @Test public void testCommitNoTransaction() throws SQLException { ((TestConnection) conn).closed = false; conn.setReadOnly(false); assertThrows(XAException.class, () -> resource.commit(new TestXid(), false)); } @Test public void testConstructor() { assertEquals(0, resource.getTransactionTimeout()); assertNull(resource.getXid()); // the current implementation always return false, regardless of the input value assertFalse(resource.setTransactionTimeout(100)); // the current implementation always return an empty/zero'd array, regardless of the input value assertEquals(0, resource.recover(100).length); } @Test public void testForget() throws XAException { final Xid xid = new TestXid(); resource.start(xid, XAResource.TMNOFLAGS); resource.forget(xid); assertNull(resource.getXid()); } @Test public void testForgetDifferentXid() throws XAException { final Xid xid = new TestXid(); resource.start(xid, XAResource.TMNOFLAGS); resource.forget(new TestXid()); assertEquals(xid, resource.getXid()); } @Test public void testForgetMissingXid() throws XAException { final Xid xid = new TestXid(); resource.start(xid, XAResource.TMNOFLAGS); resource.forget(null); assertEquals(xid, resource.getXid()); } @Test public void testIsSame() { assertTrue(resource.isSameRM(resource)); assertFalse(resource.isSameRM(new LocalXAConnectionFactory.LocalXAResource(conn))); } @Test public void testRollback() throws SQLException, XAException { final Xid xid = new TestXid(); ((TestConnection) conn).closed = false; conn.setReadOnly(false); resource.start(xid, XAResource.TMNOFLAGS); resource.rollback(xid); assertTrue(((TestConnection) conn).rolledback); } @Test public void testRollbackInvalidXid() throws SQLException, XAException { final Xid xid = new TestXid(); ((TestConnection) conn).closed = false; conn.setReadOnly(false); resource.start(xid, XAResource.TMNOFLAGS); assertThrows(XAException.class, () -> resource.rollback(new TestXid())); } @Test public void testRollbackMissingXid() { assertThrows(NullPointerException.class, () -> resource.rollback(null)); } /** * When an exception is thrown on the {@link Connection#getAutoCommit()}, then the * value is set to {@code true} by default. * @throws XAException when there are errors with the transaction * @throws SQLException when there are errors with other SQL/DB parts */ @Test public void testStartExceptionOnGetAutoCommit() throws XAException, SQLException { final Xid xid = new TestXid(); ((TestConnection) conn).throwWhenGetAutoCommit = true; conn.setAutoCommit(false); conn.setReadOnly(true); // the start method with no flag will call getAutoCommit, the exception will be thrown, and it will be set // to true resource.start(xid, XAResource.TMNOFLAGS); // and prepare sets the value computed in start in the connection resource.prepare(xid); ((TestConnection) conn).throwWhenGetAutoCommit = false; assertTrue(conn.getAutoCommit()); } @Test public void testStartFailsWhenCannotSetAutoCommit() { final Xid xid = new TestXid(); ((TestConnection) conn).throwWhenSetAutoCommit = true; assertThrows(XAException.class, () -> resource.start(xid, XAResource.TMNOFLAGS)); } @Test public void testStartInvalidFlag() { // currently, valid values are TMNOFLAGS and TMRESUME assertThrows(XAException.class, () -> resource.start(null, XAResource.TMENDRSCAN)); } @Test public void testStartNoFlagButAlreadyEnlisted() throws XAException { resource.start(new TestXid(), XAResource.TMNOFLAGS); assertThrows(XAException.class, () -> resource.start(new TestXid(), XAResource.TMNOFLAGS)); } @Test public void testStartNoFlagResume() throws XAException { final Xid xid = new TestXid(); resource.start(xid, XAResource.TMNOFLAGS); resource.start(xid, XAResource.TMRESUME); assertEquals(xid, resource.getXid()); } @Test public void testStartNoFlagResumeButDifferentXid() throws XAException { resource.start(new TestXid(), XAResource.TMNOFLAGS); assertThrows(XAException.class, () -> resource.start(new TestXid(), XAResource.TMRESUME)); } @Test public void testStartNoFlagResumeEnd() throws XAException { final Xid xid = new TestXid(); resource.start(xid, XAResource.TMNOFLAGS); resource.start(xid, XAResource.TMRESUME); // flag is never used in the end resource.end(xid, 0); assertEquals(xid, resource.getXid()); } @Test public void testStartNoFlagResumeEndDifferentXid() throws XAException { final Xid xid = new TestXid(); resource.start(xid, XAResource.TMNOFLAGS); resource.start(xid, XAResource.TMRESUME); // flag is never used in the end assertThrows(XAException.class, () -> resource.end(new TestXid(), 0)); } @Test public void testStartNoFlagResumeEndMissingXid() throws XAException { final Xid xid = new TestXid(); resource.start(xid, XAResource.TMNOFLAGS); resource.start(xid, XAResource.TMRESUME); // flag is never used in the end assertThrows(NullPointerException.class, () -> resource.end(null, 0)); } /** * When an exception is thrown on the {@link Connection#getAutoCommit()}, then the * value is set to {@code true} by default. However, if the connection is not read-only, * then the value set by the user in the original connection will be kept. * @throws XAException when there are errors with the transaction * @throws SQLException when there are errors with other SQL/DB parts */ @Test public void testStartReadOnlyConnectionExceptionOnGetAutoCommit() throws XAException, SQLException { final Xid xid = new TestXid(); ((TestConnection) conn).throwWhenGetAutoCommit = true; conn.setAutoCommit(false); conn.setReadOnly(false); // the start method with no flag will call getAutoCommit, the exception will be thrown, and it will be set // to true resource.start(xid, XAResource.TMNOFLAGS); // and prepare sets the value computed in start in the connection resource.prepare(xid); ((TestConnection) conn).throwWhenGetAutoCommit = false; assertFalse(conn.getAutoCommit()); } @Test public void testStartReadOnlyConnectionPrepare() throws XAException, SQLException { final Xid xid = new TestXid(); conn.setAutoCommit(false); conn.setReadOnly(true); resource.start(xid, XAResource.TMNOFLAGS); resource.prepare(xid); assertFalse(conn.getAutoCommit()); } } TestManagedConnection.java000066400000000000000000000165421447311732500350710ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import java.util.Properties; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.RollbackException; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import javax.transaction.xa.XAResource; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.Constants; import org.apache.commons.dbcp2.DriverConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingDataSource; import org.apache.commons.dbcp2.TesterDriver; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.geronimo.transaction.manager.TransactionManagerImpl; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * TestSuite for ManagedConnection. */ public class TestManagedConnection { private class UncooperativeLocalXAConnectionFactory extends LocalXAConnectionFactory { public UncooperativeLocalXAConnectionFactory(final TransactionManager transactionManager, final ConnectionFactory connectionFactory) { super(transactionManager, connectionFactory); try { // inject our own TransactionRegistry which returns Uncooperative Transactions which always fail to enlist a XAResource final Field field = LocalXAConnectionFactory.class.getDeclaredField("transactionRegistry"); field.setAccessible(true); field.set(this, new UncooperativeTransactionRegistry(transactionManager)); } catch (final Exception e) { e.printStackTrace(); } } } /** * Transaction that always fails enlistResource. */ private static class UncooperativeTransaction implements Transaction { private final Transaction wrappedTransaction; public UncooperativeTransaction(final Transaction transaction) { this.wrappedTransaction = transaction; } @Override public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException { wrappedTransaction.commit(); } @Override public boolean delistResource(final XAResource arg0, final int arg1) throws IllegalStateException, SystemException { return wrappedTransaction.delistResource(arg0, arg1); } @Override public synchronized boolean enlistResource(final XAResource xaRes) { return false; } @Override public int getStatus() throws SystemException { return wrappedTransaction.getStatus(); } @Override public void registerSynchronization(final Synchronization arg0) throws IllegalStateException, RollbackException, SystemException { wrappedTransaction.registerSynchronization(arg0); } @Override public void rollback() throws IllegalStateException, SystemException { wrappedTransaction.rollback(); } @Override public void setRollbackOnly() throws IllegalStateException, SystemException { wrappedTransaction.setRollbackOnly(); } } private class UncooperativeTransactionRegistry extends TransactionRegistry { public UncooperativeTransactionRegistry(final TransactionManager transactionManager) { super(transactionManager); } @Override public TransactionContext getActiveTransactionContext() throws SQLException { try { return new TransactionContext(this, new UncooperativeTransaction(transactionManager.getTransaction())); } catch (final SystemException e) { return null; } } } protected PoolingDataSource ds; private GenericObjectPool pool; protected TransactionManager transactionManager; public Connection getConnection() throws Exception { return ds.getConnection(); } @BeforeEach public void setUp() throws Exception { // create a GeronimoTransactionManager for testing transactionManager = new TransactionManagerImpl(); // create a driver connection factory final Properties properties = new Properties(); properties.setProperty(Constants.KEY_USER, "userName"); properties.setProperty(Constants.KEY_PASSWORD, "password"); final ConnectionFactory connectionFactory = new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties); // wrap it with a LocalXAConnectionFactory final XAConnectionFactory xaConnectionFactory = new UncooperativeLocalXAConnectionFactory(transactionManager, connectionFactory); // create the pool object factory final PoolableConnectionFactory factory = new PoolableConnectionFactory(xaConnectionFactory, null); factory.setValidationQuery("SELECT DUMMY FROM DUAL"); factory.setDefaultReadOnly(Boolean.TRUE); factory.setDefaultAutoCommit(Boolean.TRUE); // create the pool pool = new GenericObjectPool<>(factory); factory.setPool(pool); pool.setMaxTotal(10); pool.setMaxWait(Duration.ofMillis(100)); // finally create the datasource ds = new ManagedDataSource<>(pool, xaConnectionFactory.getTransactionRegistry()); ds.setAccessToUnderlyingConnectionAllowed(true); } @AfterEach public void tearDown() throws Exception { pool.close(); } @Test public void testConnectionReturnOnErrorWhenEnlistingXAResource() throws Exception { // see DBCP-433 transactionManager.begin(); assertThrows(SQLException.class, () -> getConnection()); transactionManager.commit(); assertEquals(1, pool.getBorrowedCount()); // assertEquals(1, pool.getReturnedCount()); assertEquals(1, pool.getDestroyedCount()); assertEquals(0, pool.getNumActive()); } } TestManagedConnectionCachedState.java000066400000000000000000000114141447311732500371530ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.transaction.TransactionManager; import javax.transaction.xa.XAException; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.Constants; import org.apache.commons.dbcp2.DriverConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingDataSource; import org.apache.commons.dbcp2.TesterDriver; import org.apache.commons.pool2.SwallowedExceptionListener; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.geronimo.transaction.manager.TransactionManagerImpl; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Test for ManagedConnection cached state. */ public class TestManagedConnectionCachedState { private static class SwallowedExceptionRecorder implements SwallowedExceptionListener { private final List exceptions = new ArrayList<>(); public List getExceptions() { return exceptions; } @Override public void onSwallowException(final Exception e) { exceptions.add(e); } } private PoolingDataSource ds; private GenericObjectPool pool; private TransactionManager transactionManager; private SwallowedExceptionRecorder swallowedExceptionRecorder; public Connection getConnection() throws SQLException { return ds.getConnection(); } @BeforeEach public void setUp() throws XAException { // create a GeronimoTransactionManager for testing transactionManager = new TransactionManagerImpl(); // create a driver connection factory final Properties properties = new Properties(); properties.setProperty(Constants.KEY_USER, "userName"); properties.setProperty(Constants.KEY_PASSWORD, "password"); final ConnectionFactory connectionFactory = new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties); // wrap it with a LocalXAConnectionFactory final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(transactionManager, connectionFactory); // create the pool object factory // make sure we ask for state caching final PoolableConnectionFactory factory = new PoolableConnectionFactory(xaConnectionFactory, null); factory.setValidationQuery("SELECT DUMMY FROM DUAL"); factory.setCacheState(true); // create the pool pool = new GenericObjectPool<>(factory); factory.setPool(pool); // record swallowed exceptions swallowedExceptionRecorder = new SwallowedExceptionRecorder(); pool.setSwallowedExceptionListener(swallowedExceptionRecorder); // finally create the datasource ds = new ManagedDataSource<>(pool, xaConnectionFactory.getTransactionRegistry()); ds.setAccessToUnderlyingConnectionAllowed(true); } @AfterEach public void tearDown() { pool.close(); } @Test public void testConnectionCachedState() throws Exception { // see DBCP-568 // begin a transaction transactionManager.begin(); // acquire a connection enlisted in the transaction try (final Connection conn = getConnection()) { // check the autocommit status to trigger internal caching conn.getAutoCommit(); // ask the transaction manager to rollback transactionManager.rollback(); } // check that no exceptions about failed rollback during close were logged assertEquals(0, swallowedExceptionRecorder.getExceptions().size()); } } TestManagedDataSource.java000066400000000000000000000257311447311732500350240ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Connection; import java.util.Properties; import javax.transaction.TransactionManager; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.Constants; import org.apache.commons.dbcp2.DelegatingConnection; import org.apache.commons.dbcp2.DriverConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingDataSource; import org.apache.commons.dbcp2.TestConnectionPool; import org.apache.commons.dbcp2.TesterDriver; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.geronimo.transaction.manager.TransactionManagerImpl; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * TestSuite for ManagedDataSource without a transaction in progress. */ public class TestManagedDataSource extends TestConnectionPool { protected PoolingDataSource ds; protected GenericObjectPool pool; protected TransactionManager transactionManager; @Override protected Connection getConnection() throws Exception { return ds.getConnection(); } @BeforeEach public void setUp() throws Exception { // create a GeronimoTransactionManager for testing transactionManager = new TransactionManagerImpl(); // create a driver connection factory final Properties properties = new Properties(); properties.setProperty(Constants.KEY_USER, "userName"); properties.setProperty(Constants.KEY_PASSWORD, "password"); final ConnectionFactory connectionFactory = new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties); // wrap it with a LocalXAConnectionFactory final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(transactionManager, connectionFactory); // create the pool object factory final PoolableConnectionFactory factory = new PoolableConnectionFactory(xaConnectionFactory, null); factory.setValidationQuery("SELECT DUMMY FROM DUAL"); factory.setDefaultReadOnly(Boolean.TRUE); factory.setDefaultAutoCommit(Boolean.TRUE); // create the pool pool = new GenericObjectPool<>(factory); factory.setPool(pool); pool.setMaxTotal(getMaxTotal()); pool.setMaxWait(getMaxWaitDuration()); // finally create the datasource ds = new ManagedDataSource<>(pool, xaConnectionFactory.getTransactionRegistry()); ds.setAccessToUnderlyingConnectionAllowed(true); } @Override @AfterEach public void tearDown() throws Exception { pool.close(); super.tearDown(); } /** * Verify the accessToUnderlyingConnectionAllowed properly limits access to the physical connection. */ @Test public void testAccessToUnderlyingConnectionAllowed() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); try (ManagedConnection connection = (ManagedConnection) newConnection()) { assertTrue(connection.isAccessToUnderlyingConnectionAllowed()); assertNotNull(connection.getDelegate()); assertNotNull(connection.getInnermostDelegate()); } ds.setAccessToUnderlyingConnectionAllowed(false); try (ManagedConnection connection = (ManagedConnection) newConnection()) { assertFalse(connection.isAccessToUnderlyingConnectionAllowed()); assertNull(connection.getDelegate()); assertNull(connection.getInnermostDelegate()); } } @Test public void testConnectionReturnOnCommit() throws Exception { transactionManager.begin(); try (DelegatingConnection connectionA = (DelegatingConnection) newConnection()) { // auto close. } transactionManager.commit(); assertEquals(1, pool.getBorrowedCount()); assertEquals(1, pool.getReturnedCount()); assertEquals(0, pool.getNumActive()); } @Test public void testManagedConnectionEqualInnermost() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); try (DelegatingConnection con = (DelegatingConnection) getConnection()) { @SuppressWarnings("resource") final Connection inner = con.getInnermostDelegate(); ds.setAccessToUnderlyingConnectionAllowed(false); final DelegatingConnection con2 = new DelegatingConnection<>(inner); assertNotEquals(con2, con); assertTrue(con.innermostDelegateEquals(con2.getInnermostDelegate())); assertTrue(con2.innermostDelegateEquals(inner)); assertNotEquals(con, con2); } } @Test public void testManagedConnectionEqualsFail() throws Exception { try (Connection con1 = getConnection(); final Connection con2 = getConnection()) { assertNotEquals(con1, con2); } } @Test public void testManagedConnectionEqualsNull() throws Exception { try (Connection con1 = getConnection()) { final Connection con2 = null; assertNotEquals(con2, con1); } } /* * JIRA: DBCP-198 */ @Test public void testManagedConnectionEqualsReflexive() throws Exception { try (Connection con = getConnection()) { @SuppressWarnings("resource") final Connection con2 = con; assertEquals(con2, con); assertEquals(con, con2); } } @Test public void testManagedConnectionEqualsSameDelegate() throws Exception { // Get a maximal set of connections from the pool final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = newConnection(); } // Close the delegate of one wrapper in the pool ((DelegatingConnection) c[0]).getDelegate().close(); // Grab a new connection - should get c[0]'s closed connection // so should be delegate-equivalent try (Connection con = newConnection()) { Assertions.assertNotEquals(c[0], con); Assertions.assertEquals(((DelegatingConnection) c[0]).getInnermostDelegateInternal(), ((DelegatingConnection) con).getInnermostDelegateInternal()); for (final Connection element : c) { element.close(); } } } @Test public void testManagedConnectionEqualsSameDelegateNoUnderlyingAccess() throws Exception { // Get a maximal set of connections from the pool final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { c[i] = newConnection(); } // Close the delegate of one wrapper in the pool ((DelegatingConnection) c[0]).getDelegate().close(); // Disable access for the new connection ds.setAccessToUnderlyingConnectionAllowed(false); // Grab a new connection - should get c[0]'s closed connection // so should be delegate-equivalent try (Connection con = newConnection()) { Assertions.assertNotEquals(c[0], con); Assertions.assertEquals(((DelegatingConnection) c[0]).getInnermostDelegateInternal(), ((DelegatingConnection) con).getInnermostDelegateInternal()); for (final Connection element : c) { element.close(); } ds.setAccessToUnderlyingConnectionAllowed(true); } } @Test public void testManagedConnectionEqualsType() throws Exception { try (Connection con1 = getConnection()) { final Integer con2 = 0; assertNotEquals(con2, con1); } } @Test public void testNestedConnections() throws Exception { transactionManager.begin(); try (Connection c1 = newConnection(); final Connection c2 = newConnection()) { transactionManager.commit(); } } @Test public void testSetNullTransactionRegistry() throws Exception { try (ManagedDataSource ds = new ManagedDataSource<>(pool, null)) { assertThrows(NullPointerException.class, () -> ds.setTransactionRegistry(null)); } } @Test() public void testSetTransactionRegistry() throws Exception { try (ManagedDataSource ds = new ManagedDataSource<>(pool, null)) { ds.setTransactionRegistry(new TransactionRegistry(transactionManager)); } } @Test public void testSetTransactionRegistryAlreadySet() { final ManagedDataSource managed = (ManagedDataSource) ds; assertThrows(IllegalStateException.class, () -> managed.setTransactionRegistry(null)); } /** * Verify that connection sharing is working (or not working) as expected. */ @Test public void testSharedConnection() throws Exception { try (DelegatingConnection connectionA = (DelegatingConnection) newConnection(); final DelegatingConnection connectionB = (DelegatingConnection) newConnection()) { assertNotEquals(connectionA, connectionB); assertNotEquals(connectionB, connectionA); assertFalse(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); assertFalse(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); } } @Test public void testTransactionRegistryNotInitialized() throws Exception { try (ManagedDataSource ds = new ManagedDataSource<>(pool, null)) { assertThrows(IllegalStateException.class, ds::getConnection); } } } TestManagedDataSourceInTx.java000066400000000000000000000411721447311732500356240ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.transaction.Synchronization; import javax.transaction.Transaction; import org.apache.commons.dbcp2.DelegatingConnection; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests ManagedDataSource with an active transaction in progress. */ public class TestManagedDataSourceInTx extends TestManagedDataSource { // can't actually test close in a transaction @Override protected void assertBackPointers(final Connection conn, final Statement statement) throws SQLException { assertFalse(conn.isClosed()); assertFalse(isClosed(statement)); assertSame(conn, statement.getConnection(), "statement.getConnection() should return the exact same connection instance that was used to create the statement"); try (ResultSet resultSet = statement.getResultSet()) { assertFalse(isClosed(resultSet)); assertSame(statement, resultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); try (ResultSet executeResultSet = statement.executeQuery("select * from dual")) { assertFalse(isClosed(executeResultSet)); assertSame(statement, executeResultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); } try (ResultSet keysResultSet = statement.getGeneratedKeys()) { assertFalse(isClosed(keysResultSet)); assertSame(statement, keysResultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); } if (statement instanceof PreparedStatement) { final PreparedStatement preparedStatement = (PreparedStatement) statement; try (ResultSet preparedResultSet = preparedStatement.executeQuery()) { assertFalse(isClosed(preparedResultSet)); assertSame(statement, preparedResultSet.getStatement(), "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); } } resultSet.getStatement().getConnection().close(); } } @Override @BeforeEach public void setUp() throws Exception { super.setUp(); transactionManager.begin(); } @Override @AfterEach public void tearDown() throws Exception { if (transactionManager.getTransaction() != null) { transactionManager.commit(); } super.tearDown(); } @Override @Test public void testAutoCommitBehavior() throws Exception { final Connection connection = newConnection(); // auto commit should be off assertFalse(connection.getAutoCommit(), "Auto-commit should be disabled"); // attempt to set auto commit try { connection.setAutoCommit(true); fail("setAutoCommit method should be disabled while enlisted in a transaction"); } catch (final SQLException e) { // expected } // make sure it is still disabled assertFalse(connection.getAutoCommit(), "Auto-commit should be disabled"); // close connection connection.close(); } @Override @Test public void testClearWarnings() throws Exception { // open a connection Connection connection = newConnection(); assertNotNull(connection); // generate SQLWarning on connection final CallableStatement statement = connection.prepareCall("warning"); assertNotNull(connection.getWarnings()); // create a new shared connection final Connection sharedConnection = newConnection(); // shared connection should see warning assertNotNull(sharedConnection.getWarnings()); // close and allocate a new (original) connection connection.close(); connection = newConnection(); // warnings should not have been cleared by closing the connection assertNotNull(connection.getWarnings()); assertNotNull(sharedConnection.getWarnings()); statement.close(); sharedConnection.close(); connection.close(); } @Test public void testCloseInTransaction() throws Exception { try (DelegatingConnection connectionA = (DelegatingConnection) newConnection(); DelegatingConnection connectionB = (DelegatingConnection) newConnection()) { assertNotEquals(connectionA, connectionB); assertNotEquals(connectionB, connectionA); assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); } final Connection connection = newConnection(); assertFalse(connection.isClosed(), "Connection should be open"); connection.close(); assertTrue(connection.isClosed(), "Connection should be closed"); } @Test public void testCommit() throws Exception { try (Connection connection = newConnection()) { // connection should be open assertFalse(connection.isClosed(), "Connection should be open"); // attempt commit directly try { connection.commit(); fail("commit method should be disabled while enlisted in a transaction"); } catch (final SQLException e) { // expected } // make sure it is still open assertFalse(connection.isClosed(), "Connection should be open"); } } @Override @Test public void testConnectionReturnOnCommit() throws Exception { // override with no-op test } @Override @Test public void testConnectionsAreDistinct() throws Exception { final Connection[] conn = new Connection[getMaxTotal()]; for (int i = 0; i < conn.length; i++) { conn[i] = newConnection(); for (int j = 0; j < i; j++) { // two connections should be distinct instances Assertions.assertNotSame(conn[j], conn[i]); // neither should they should be equivalent even though they are // sharing the same underlying connection Assertions.assertNotEquals(conn[j], conn[i]); // Check underlying connection is the same Assertions.assertEquals(((DelegatingConnection) conn[j]).getInnermostDelegateInternal(), ((DelegatingConnection) conn[i]).getInnermostDelegateInternal()); } } for (final Connection element : conn) { element.close(); } } @Test public void testDoubleReturn() throws Exception { transactionManager.getTransaction().registerSynchronization(new Synchronization() { private ManagedConnection conn; @Override public void afterCompletion(final int i) { final int numActive = pool.getNumActive(); try { conn.checkOpen(); } catch (final Exception e) { // Ignore } assertEquals(numActive, pool.getNumActive()); try { conn.close(); } catch (final Exception e) { fail("Should have been able to close the connection"); } // TODO Requires DBCP-515 assertTrue(numActive -1 == pool.getNumActive()); } @Override public void beforeCompletion() { try { conn = (ManagedConnection) ds.getConnection(); assertNotNull(conn); } catch (final SQLException e) { fail("Could not get connection"); } } }); transactionManager.commit(); } @Test public void testGetConnectionInAfterCompletion() throws Exception { try (DelegatingConnection connection = (DelegatingConnection) newConnection()) { // Don't close so we can check it for warnings in afterCompletion transactionManager.getTransaction().registerSynchronization(new SynchronizationAdapter() { @Override public void afterCompletion(final int i) { try { final Connection connection1 = ds.getConnection(); try { connection1.getWarnings(); fail("Could operate on closed connection"); } catch (final SQLException e) { // This is expected } } catch (final SQLException e) { fail("Should have been able to get connection"); } } }); } transactionManager.commit(); } @Override @Test public void testHashCode() throws Exception { try (Connection conn1 = newConnection()) { assertNotNull(conn1); try (Connection conn2 = newConnection()) { assertNotNull(conn2); // shared connections should not have the same hash code Assertions.assertNotEquals(conn1.hashCode(), conn2.hashCode()); } } } /** * @see #testSharedConnection() */ @Override @Test public void testManagedConnectionEqualsFail() throws Exception { // this test is invalid for managed connections since because // two connections to the same datasource are supposed to share // a single connection } @Override @Test public void testMaxTotal() throws Exception { final Transaction[] transactions = new Transaction[getMaxTotal()]; final Connection[] c = new Connection[getMaxTotal()]; for (int i = 0; i < c.length; i++) { // create a new connection in the current transaction c[i] = newConnection(); assertNotNull(c[i]); // suspend the current transaction and start a new one transactions[i] = transactionManager.suspend(); assertNotNull(transactions[i]); transactionManager.begin(); } try { newConnection(); fail("Allowed to open more than DefaultMaxTotal connections."); } catch (final java.sql.SQLException e) { // should only be able to open 10 connections, so this test should // throw an exception } finally { transactionManager.commit(); for (int i = 0; i < c.length; i++) { transactionManager.resume(transactions[i]); c[i].close(); transactionManager.commit(); } } } @Override @Test public void testNestedConnections() { // Not supported } @Test public void testReadOnly() throws Exception { try (Connection connection = newConnection()) { // NOTE: This test class uses connections that are read-only by default // connection should be read only assertTrue(connection.isReadOnly(), "Connection be read-only"); // attempt to setReadOnly try { connection.setReadOnly(true); fail("setReadOnly method should be disabled while enlisted in a transaction"); } catch (final SQLException e) { // expected } // make sure it is still read-only assertTrue(connection.isReadOnly(), "Connection be read-only"); // attempt to setReadonly try { connection.setReadOnly(false); fail("setReadOnly method should be disabled while enlisted in a transaction"); } catch (final SQLException e) { // expected } // make sure it is still read-only assertTrue(connection.isReadOnly(), "Connection be read-only"); // TwR closes the connection } } @Override @Test public void testSharedConnection() throws Exception { try (DelegatingConnection connectionA = (DelegatingConnection) newConnection(); DelegatingConnection connectionB = (DelegatingConnection) newConnection()) { assertNotEquals(connectionA, connectionB); assertNotEquals(connectionB, connectionA); assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); } } @Test public void testSharedTransactionConversion() throws Exception { try (DelegatingConnection connectionA = (DelegatingConnection) newConnection(); DelegatingConnection connectionB = (DelegatingConnection) newConnection()) { // in a transaction the inner connections should be equal assertNotEquals(connectionA, connectionB); assertNotEquals(connectionB, connectionA); assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); transactionManager.commit(); // use the connection so it adjusts to the completed transaction connectionA.getAutoCommit(); connectionB.getAutoCommit(); // no there is no transaction so inner connections should not be equal assertNotEquals(connectionA, connectionB); assertNotEquals(connectionB, connectionA); assertFalse(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); assertFalse(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); transactionManager.begin(); // use the connection so it adjusts to the new transaction connectionA.getAutoCommit(); connectionB.getAutoCommit(); // back in a transaction so inner connections should be equal again assertNotEquals(connectionA, connectionB); assertNotEquals(connectionB, connectionA); assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); } } } TestPoolableManagedConnection.java000066400000000000000000000140001447311732500365320ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import java.util.Properties; import javax.transaction.TransactionManager; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.Constants; import org.apache.commons.dbcp2.DriverConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.TesterDriver; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.geronimo.transaction.manager.TransactionManagerImpl; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests for PoolableManagedConnection. */ public class TestPoolableManagedConnection { private TransactionManager transactionManager; private TransactionRegistry transactionRegistry; private GenericObjectPool pool; private Connection conn; private PoolableManagedConnection poolableManagedConnection; @BeforeEach public void setUp() throws Exception { // create a GeronimoTransactionManager for testing transactionManager = new TransactionManagerImpl(); // create a driver connection factory final Properties properties = new Properties(); properties.setProperty(Constants.KEY_USER, "userName"); properties.setProperty(Constants.KEY_PASSWORD, "password"); final ConnectionFactory connectionFactory = new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties); // wrap it with a LocalXAConnectionFactory final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(transactionManager, connectionFactory); // create transaction registry transactionRegistry = xaConnectionFactory.getTransactionRegistry(); // create the pool object factory final PoolableConnectionFactory factory = new PoolableConnectionFactory(xaConnectionFactory, null); factory.setValidationQuery("SELECT DUMMY FROM DUAL"); factory.setDefaultReadOnly(Boolean.TRUE); factory.setDefaultAutoCommit(Boolean.TRUE); // create the pool pool = new GenericObjectPool<>(factory); factory.setPool(pool); pool.setMaxTotal(10); pool.setMaxWait(Duration.ofMillis(100)); } @AfterEach public void tearDown() throws SQLException { if (conn != null && !conn.isClosed()) { conn.close(); } if (pool != null && !pool.isClosed()) { pool.close(); } } @Test public void testManagedConnection() throws Exception { assertEquals(0, pool.getNumActive()); // create a connection conn = pool.borrowObject(); assertEquals(1, pool.getNumActive()); // create the poolable managed connection poolableManagedConnection = new PoolableManagedConnection(transactionRegistry, conn, pool); poolableManagedConnection.close(); // closing a poolable managed connection won't close it, but simply return to the pool assertEquals(1, pool.getNumActive()); // but closing the underlying connection really closes it conn.close(); assertEquals(0, pool.getNumActive()); } @Test public void testPoolableConnection() throws Exception { // create a connection // pool uses LocalXAConnectionFactory, which register the connection with the TransactionRegistry conn = pool.borrowObject(); assertNotNull(transactionRegistry.getXAResource(conn)); // create the poolable managed connection poolableManagedConnection = new PoolableManagedConnection(transactionRegistry, conn, pool); poolableManagedConnection.close(); assertNotNull(transactionRegistry.getXAResource(conn)); } @Test public void testReallyClose() throws Exception { assertEquals(0, pool.getNumActive()); // create a connection // pool uses LocalXAConnectionFactory, which register the connection with the TransactionRegistry conn = pool.borrowObject(); assertEquals(1, pool.getNumActive()); assertNotNull(transactionRegistry.getXAResource(conn)); // create the poolable managed connection poolableManagedConnection = new PoolableManagedConnection(transactionRegistry, conn, pool); poolableManagedConnection.close(); assertNotNull(transactionRegistry.getXAResource(conn)); assertEquals(1, pool.getNumActive()); // this must close the managed connection, removing it from the transaction registry poolableManagedConnection.reallyClose(); try { assertNull(transactionRegistry.getXAResource(conn)); fail("Transaction registry was supposed to be empty now"); } catch (final SQLException ignore) { // ignore } assertEquals(0, pool.getNumActive()); } }TestSynchronizationOrder.java000066400000000000000000000230031447311732500357000ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import javax.sql.XAConnection; import javax.sql.XADataSource; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAResource; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.DelegatingConnection; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.TesterClassLoader; import org.apache.commons.dbcp2.transaction.TransactionAdapter; import org.apache.commons.dbcp2.transaction.TransactionManagerAdapter; import org.apache.commons.dbcp2.transaction.TransactionSynchronizationRegistryAdapter; import org.apache.commons.pool2.impl.GenericObjectPool; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class TestSynchronizationOrder { private boolean transactionManagerRegistered; private boolean transactionSynchronizationRegistryRegistered; private TransactionManager transactionManager; private TransactionSynchronizationRegistry transactionSynchronizationRegistry; private XADataSource xads; private BasicManagedDataSource bmds; private BasicDataSource bds; @BeforeEach public void setup() { transactionManager = new TransactionManagerAdapter() { private Transaction transaction; @Override public void begin() throws NotSupportedException, SystemException { transaction = new TransactionAdapter() { @Override public boolean enlistResource(final XAResource xaResource) throws IllegalStateException, RollbackException, SystemException { // Called and used return true; } @Override public void registerSynchronization(final Synchronization synchronization) throws IllegalStateException, RollbackException, SystemException { transactionManagerRegistered = true; } }; } @Override public Transaction getTransaction() throws SystemException { return transaction; } }; transactionSynchronizationRegistry = new TransactionSynchronizationRegistryAdapter() { @Override public void registerInterposedSynchronization(final Synchronization synchronization) { transactionSynchronizationRegistryRegistered = true; } }; bmds = new BasicManagedDataSource(); bmds.setTransactionManager(transactionManager); bmds.setTransactionSynchronizationRegistry(transactionSynchronizationRegistry); bmds.setXADataSource("notnull"); bds = new BasicDataSource(); bds.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); bds.setUrl("jdbc:apache:commons:testdriver"); bds.setMaxTotal(10); bds.setMaxWait(Duration.ofMillis(100)); bds.setDefaultAutoCommit(Boolean.TRUE); bds.setDefaultReadOnly(Boolean.FALSE); bds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); bds.setDefaultCatalog("test catalog"); bds.setUsername("userName"); bds.setPassword("password"); bds.setValidationQuery("SELECT DUMMY FROM DUAL"); bds.setConnectionInitSqls(Arrays.asList("SELECT 1", "SELECT 2")); bds.setDriverClassLoader(new TesterClassLoader()); bds.setJmxName("org.apache.commons.dbcp2:name=test"); final AtomicInteger closeCounter = new AtomicInteger(); final InvocationHandler handle = new InvocationHandler() { @SuppressWarnings("resource") // caller closes protected XAConnection getXAConnection() throws SQLException { return new TesterBasicXAConnection(bds.getConnection(), closeCounter); } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { final String methodName = method.getName(); if (methodName.equals("hashCode")) { return System.identityHashCode(proxy); } if (methodName.equals("equals")) { return proxy == args[0]; } if (methodName.equals("getXAConnection")) { // both zero and 2-arg signatures return getXAConnection(); } try { return method.invoke(bds, args); } catch (final InvocationTargetException e) { throw e.getTargetException(); } } }; xads = (XADataSource) Proxy.newProxyInstance( TestSynchronizationOrder.class.getClassLoader(), new Class[]{XADataSource.class}, handle); bmds.setXaDataSourceInstance(xads); } @AfterEach public void tearDown() throws SQLException { bds.close(); bmds.close(); } @Test public void testInterposedSynchronization() throws Exception { final DataSourceXAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(transactionManager, xads, transactionSynchronizationRegistry); final PoolableConnectionFactory factory = new PoolableConnectionFactory(xaConnectionFactory, null); factory.setValidationQuery("SELECT DUMMY FROM DUAL"); factory.setDefaultReadOnly(Boolean.TRUE); factory.setDefaultAutoCommit(Boolean.TRUE); // create the pool try (final GenericObjectPool pool = new GenericObjectPool<>(factory)) { factory.setPool(pool); pool.setMaxTotal(10); pool.setMaxWait(Duration.ofSeconds(1)); // finally create the datasource try (final ManagedDataSource ds = new ManagedDataSource<>(pool, xaConnectionFactory.getTransactionRegistry())) { ds.setAccessToUnderlyingConnectionAllowed(true); transactionManager.begin(); try (final Connection connectionA = ds.getConnection()) { // Check and close right away. assertTrue(connectionA instanceof DelegatingConnection); } transactionManager.commit(); assertFalse(transactionManagerRegistered); assertTrue(transactionSynchronizationRegistryRegistered); } } } @Test public void testSessionSynchronization() throws Exception { final DataSourceXAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(transactionManager, xads); final PoolableConnectionFactory factory = new PoolableConnectionFactory(xaConnectionFactory, null); factory.setValidationQuery("SELECT DUMMY FROM DUAL"); factory.setDefaultReadOnly(Boolean.TRUE); factory.setDefaultAutoCommit(Boolean.TRUE); // create the pool try (final GenericObjectPool pool = new GenericObjectPool<>(factory)) { factory.setPool(pool); pool.setMaxTotal(10); pool.setMaxWait(Duration.ofSeconds(1)); // finally create the datasource try (final ManagedDataSource ds = new ManagedDataSource<>(pool, xaConnectionFactory.getTransactionRegistry())) { ds.setAccessToUnderlyingConnectionAllowed(true); transactionManager.begin(); try (final Connection connectionA = ds.getConnection()) { // Check and close right away. assertTrue(connectionA instanceof DelegatingConnection); } transactionManager.commit(); assertTrue(transactionManagerRegistered); assertFalse(transactionSynchronizationRegistryRegistered); } } } } TestTransactionContext.java000066400000000000000000000054601447311732500353440ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Connection; import java.sql.SQLException; import javax.transaction.xa.XAResource; import org.apache.geronimo.transaction.manager.TransactionImpl; import org.apache.geronimo.transaction.manager.TransactionManagerImpl; import org.junit.jupiter.api.Test; /** * TestSuite for {@link TransactionContext}. */ public class TestTransactionContext { /** * Transaction that always fails enlistResource. */ private static class UncooperativeTransaction extends TransactionImpl { public UncooperativeTransaction() { super(null, null); } @Override public synchronized boolean enlistResource(final XAResource xaRes) { return false; } } /** * JIRA: DBCP-428 */ @Test public void testSetSharedConnectionEnlistFailure() throws Exception { try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); basicManagedDataSource.setUsername("userName"); basicManagedDataSource.setPassword("password"); basicManagedDataSource.setMaxIdle(1); try (final Connection conn = basicManagedDataSource.getConnection()) { assertTrue(conn instanceof ManagedConnection); final UncooperativeTransaction transaction = new UncooperativeTransaction(); final TransactionContext transactionContext = new TransactionContext(basicManagedDataSource.getTransactionRegistry(), transaction); assertThrows(SQLException.class, () -> transactionContext.setSharedConnection(conn)); } } } } TesterBasicXAConnection.java000066400000000000000000000156331447311732500353360ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/managed/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.apache.commons.dbcp2.managed; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.StatementEventListener; import javax.sql.XAConnection; import javax.transaction.xa.XAResource; /** * Basic XAConnection. getConnection() returns a handle on a physical * Connection. Closing the handle does not close the physical connection, you * have to close the XAConnection for that (PooledConnection behavior). * XA behavior is implemented through a LocalXAResource. */ public class TesterBasicXAConnection implements XAConnection { /** * Delegates everything to a Connection, except for close() which just * notifies the parent XAConnection. */ public static class ConnectionHandle implements InvocationHandler { public Connection conn; public final TesterBasicXAConnection xaconn; public ConnectionHandle(final Connection conn, final TesterBasicXAConnection xaconn) { this.conn = conn; this.xaconn = xaconn; } protected Object close() throws SQLException { if (conn != null) { conn.clearWarnings(); conn = null; xaconn.handle = null; xaconn.notifyConnectionClosed(); } return null; } public void closeHandle() { conn = null; } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { final String methodName = method.getName(); if (methodName.equals("hashCode")) { return System.identityHashCode(proxy); } if (methodName.equals("equals")) { return proxy == args[0]; } if (methodName.equals("isClosed")) { return conn == null; } if (methodName.equals("close")) { return close(); } if (conn == null) { throw new SQLException("Connection closed"); } try { return method.invoke(conn, args); } catch (final InvocationTargetException e) { final Throwable te = e.getTargetException(); if (te instanceof SQLException) { xaconn.notifyConnectionErrorOccurred((SQLException) te); } throw te; } } } public Connection conn; public ConnectionHandle handle; public final List listeners = new LinkedList<>(); public final AtomicInteger closeCounter; public TesterBasicXAConnection(final Connection conn) { this(conn, null); } public TesterBasicXAConnection(final Connection conn, final AtomicInteger closeCounter) { this.conn = conn; this.closeCounter = closeCounter; } @Override public void addConnectionEventListener( final ConnectionEventListener connectionEventListener) { listeners.add(connectionEventListener); } @Override public void addStatementEventListener(final StatementEventListener listener) { throw new UnsupportedOperationException(); } @Override public void close() throws SQLException { if (handle != null) { closeHandle(); } try { conn.close(); if (closeCounter != null) { closeCounter.incrementAndGet(); } } finally { conn = null; } } protected void closeHandle() throws SQLException { handle.closeHandle(); if (!conn.getAutoCommit()) { try { conn.rollback(); } catch (final SQLException e) { e.printStackTrace(); } } handle = null; } @Override public Connection getConnection() throws SQLException { if (conn == null) { final SQLException e = new SQLException("XAConnection closed"); notifyConnectionErrorOccurred(e); throw e; } try { if (handle != null) { // only one handle at a time on the XAConnection closeHandle(); conn.clearWarnings(); } } catch (final SQLException e) { notifyConnectionErrorOccurred(e); throw e; } handle = new ConnectionHandle(conn, this); return (Connection) Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] { Connection.class }, handle); } @Override public XAResource getXAResource() throws SQLException { return new LocalXAConnectionFactory.LocalXAResource(conn); } protected void notifyConnectionClosed() { final ConnectionEvent event = new ConnectionEvent(this); final List copy = new ArrayList<>( listeners); for (final ConnectionEventListener listener : copy) { listener.connectionClosed(event); } } protected void notifyConnectionErrorOccurred(final SQLException e) { final ConnectionEvent event = new ConnectionEvent(this, e); final List copy = new ArrayList<>( listeners); for (final ConnectionEventListener listener : copy) { listener.connectionErrorOccurred(event); } } @Override public void removeConnectionEventListener( final ConnectionEventListener connectionEventListener) { listeners.remove(connectionEventListener); } @Override public void removeStatementEventListener(final StatementEventListener listener) { throw new UnsupportedOperationException(); } } commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/transaction/000077500000000000000000000000001447311732500310125ustar00rootroot00000000000000TransactionAdapter.java000066400000000000000000000043421447311732500353670ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/transaction/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.transaction; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.RollbackException; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.xa.XAResource; /** * A Transaction adapter. */ public class TransactionAdapter implements Transaction { @Override public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException { // Noop } @Override public boolean delistResource(final XAResource arg0, final int arg1) throws IllegalStateException, SystemException { return false; } @Override public boolean enlistResource(final XAResource arg0) throws IllegalStateException, RollbackException, SystemException { return false; } @Override public int getStatus() throws SystemException { return 0; } @Override public void registerSynchronization(final Synchronization arg0) throws IllegalStateException, RollbackException, SystemException { // Noop } @Override public void rollback() throws IllegalStateException, SystemException { // Noop } @Override public void setRollbackOnly() throws IllegalStateException, SystemException { // Noop } } TransactionManagerAdapter.java000066400000000000000000000046641447311732500366710ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/transaction/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.transaction; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.InvalidTransactionException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; /** * A TransactionManager adapter. */ public class TransactionManagerAdapter implements TransactionManager { @Override public void begin() throws NotSupportedException, SystemException { // Noop } @Override public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException, SecurityException, SystemException { // Noop } @Override public int getStatus() throws SystemException { return 0; } @Override public Transaction getTransaction() throws SystemException { return null; } @Override public void resume(final Transaction arg0) throws IllegalStateException, InvalidTransactionException, SystemException { // Noop } @Override public void rollback() throws IllegalStateException, SecurityException, SystemException { // Noop } @Override public void setRollbackOnly() throws IllegalStateException, SystemException { // Noop } @Override public void setTransactionTimeout(final int arg0) throws SystemException { // Noop } @Override public Transaction suspend() throws SystemException { return null; } } TransactionSynchronizationRegistryAdapter.java000066400000000000000000000033251447311732500422420ustar00rootroot00000000000000commons-dbcp-rel-commons-dbcp-2.10.0/src/test/java/org/apache/commons/dbcp2/transaction/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.dbcp2.transaction; import javax.transaction.Synchronization; import javax.transaction.TransactionSynchronizationRegistry; /** * A TransactionSynchronizationRegistry adapter. */ public class TransactionSynchronizationRegistryAdapter implements TransactionSynchronizationRegistry { @Override public Object getResource(final Object arg0) { return null; } @Override public boolean getRollbackOnly() { return false; } @Override public Object getTransactionKey() { return null; } @Override public int getTransactionStatus() { return 0; } @Override public void putResource(final Object arg0, final Object arg1) { // Noop } @Override public void registerInterposedSynchronization(final Synchronization arg0) { // Noop } @Override public void setRollbackOnly() { // Noop } }