[SDNC-5] Rebase sdnc-core 01/2901/2
authorDan Timoney <dtimoney@att.com>
Fri, 31 Mar 2017 19:03:13 +0000 (15:03 -0400)
committerDan Timoney <dtimoney@att.com>
Fri, 31 Mar 2017 19:11:48 +0000 (15:11 -0400)
Upgrade to OpenDaylight Boron release, and sync changes made since 16.10 release to ONAP SDN-C distribution

Change-Id: I20bef9e6d0008c4436b5624ce839bbb70ecc20a5
Signed-off-by: Dan Timoney <dtimoney@att.com>
111 files changed:
.gitignore
.scanignore [new file with mode: 0644]
dblib/common/LICENSE [new file with mode: 0755]
dblib/common/NOTICE [new file with mode: 0755]
dblib/common/doc/changelog.xml [new file with mode: 0755]
dblib/common/doc/jdbc-pool.xml [new file with mode: 0755]
dblib/common/doc/package.xsl [new file with mode: 0755]
dblib/common/doc/project.xml [new file with mode: 0755]
dblib/common/pom.xml [new file with mode: 0755]
dblib/common/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSource.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DisposableConnectionFacade.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolExhaustedException.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/TrapException.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/Validator.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/XADataSource.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/QueryTimeoutInterceptor.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ResetAbandonedTimer.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java [new file with mode: 0644]
dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml [new file with mode: 0644]
dblib/common/src/main/java/org/openecomp/sdnc/sli/resource/common/CommonActivator.java [new file with mode: 0644]
dblib/features/src/main/resources/features.xml
dblib/pom.xml
dblib/provider/pom.xml
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/CachedDataSourceFactory.java
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBResourceManager.java
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/DbConfigPool.java
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractDBResourceManagerFactory.java
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractResourceManagerFactory.java
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/DBConfigFactory.java
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/JdbcDBCachedDataSource.java [new file with mode: 0644]
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jndi/JNDIDbResourceManagerFactory.java [deleted file]
dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jndi/JndiCachedDataSource.java [deleted file]
dblib/provider/src/main/resources/dblib.properties
filters/provider/pom.xml
filters/provider/src/main/java/org/openecomp/sdnc/filters/LogFilter.java
filters/provider/src/main/java/org/openecomp/sdnc/filters/RequestResponseDbLoggingFilter.java [new file with mode: 0644]
filters/provider/src/main/java/org/openecomp/sdnc/filters/RequestResponseLoggingFilter.java
pom.xml
rootpom/pom.xml
sli/common/pom.xml
sli/common/src/main/java/org/openecomp/sdnc/sli/BreakNodeException.java [new file with mode: 0644]
sli/common/src/main/java/org/openecomp/sdnc/sli/MessageWriter.java [new file with mode: 0644]
sli/common/src/main/java/org/openecomp/sdnc/sli/SvcLogicExprListener.java
sli/common/src/main/java/org/openecomp/sdnc/sli/SvcLogicExpressionFactory.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/BreakNodeExecutor.java [new file with mode: 0644]
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/CallNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/DeleteNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/ExecuteNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/ExistsNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/ForNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/GetResourceNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/IsAvailableNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/MdsalHelper.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/NotifyNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/RecordNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/ReleaseNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/ReserveNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/SaveNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/SetNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/SvcLogicActivator.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/SvcLogicExpressionResolver.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/SvcLogicServiceImpl.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/SwitchNodeExecutor.java
sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/UpdateNodeExecutor.java
sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/BadPlugin.java [new file with mode: 0644]
sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/ExecuteNodeExecutorTest.java [new file with mode: 0644]
sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/LunchSelectorPlugin.java [new file with mode: 0644]
sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/MdsalHelperTest.java [new file with mode: 0644]
sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/MdsalHelperTesterUtil.java [new file with mode: 0644]
sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/PluginTest.java [new file with mode: 0644]
sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/VoidDummyPlugin.java [new file with mode: 0644]
sliPluginUtils/provider/pom.xml
sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/DME2.java [new file with mode: 0644]
sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtils.java
sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtilsActivator.java
sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/SliStringUtils.java [new file with mode: 0644]
sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/SvcLogicContextList.java
sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/CheckParametersTest.java [new file with mode: 0644]
sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/Dme2Test.java [new file with mode: 0644]
sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtils_StaticFunctionsTest.java [new file with mode: 0644]
sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtils_ctxSortListTest.java [new file with mode: 0644]
sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliStringUtilsTest.java [new file with mode: 0644]
sliapi/installer/pom.xml
sliapi/model/pom.xml
sliapi/model/src/main/yang/sliapi.yang
sliapi/provider/pom.xml
sliapi/provider/src/main/java/org/openecomp/sdnc/sliapi/sliapiProvider.java

index 8f8f95a..f9801b8 100755 (executable)
@@ -40,3 +40,5 @@ ExprGrammarLexer.tokens
 
 # BlackDuck generated file
 sdnc-core_bdio.jsonld
+blackDuckHubProjectName.txt
+blackDuckHubProjectVersionName.txt
diff --git a/.scanignore b/.scanignore
new file mode 100644 (file)
index 0000000..06ff17a
--- /dev/null
@@ -0,0 +1,5 @@
+.git
+./dblib/provider/src/main/resources/dblib.properties:org.openecomp.sdnc.sli.jdbc.password=gamma
+./sli/common/src/test/resources/svclogic.properties:org.openecomp.sdnc.sli.jdbc.password = gamma
+./sli/provider/src/test/resources/svclogic.properties:org.openecomp.sdnc.sli.jdbc.password = gamma
+./sli/recording/src/main/resources/svclogic.properties:org.openecomp.sdnc.sli.jdbc.password = gamma
diff --git a/dblib/common/LICENSE b/dblib/common/LICENSE
new file mode 100755 (executable)
index 0000000..f49a4e1
--- /dev/null
@@ -0,0 +1,201 @@
+                                 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.
\ No newline at end of file
diff --git a/dblib/common/NOTICE b/dblib/common/NOTICE
new file mode 100755 (executable)
index 0000000..0b6fc4b
--- /dev/null
@@ -0,0 +1,6 @@
+Apache Tomcat JDBC Pool
+Copyright 2008-2016 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/dblib/common/doc/changelog.xml b/dblib/common/doc/changelog.xml
new file mode 100755 (executable)
index 0000000..2d7ddf8
--- /dev/null
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "@TOMCAT_PROJECT_DEST@">
+]>
+<?xml-stylesheet type="text/xsl" href="package.xsl"?>
+<document url="changelog.html">
+
+  &project;
+
+  <properties>
+    <author email="fhanik@apache.org">Filip Hanik</author>
+    <title>Changelog</title>
+  </properties>
+
+<body>
+
+<section name="Tomcat JDBC Connection Pool - Apache Tomcat 7.0.19 and later">
+  <p>
+    Starting with Apache Tomcat 7.0.19 in July 2011, Tomcat JDBC Connection Pool
+    is built and released as a component in official releases of Tomcat.
+    The changes are now listed in "jdbc-pool" sections of Apache Tomcat
+    changelog file. This changelog file is obsolete.
+  </p>
+</section>
+
+<section name="Tomcat JDBC Connection Pool 1.1.0.0">
+  <subsection name="pool">
+    <changelog>
+      <add><rev>1207712</rev> Pool cleaner should be a global thread, not spawn one thread per connection pool. (fhanik)</add>
+      <fix><rev>1073531</rev> <bug>50805</bug> Only initialize connections once when async (fhanik)</fix>
+      <fix><rev>1076380</rev> <bug>50857</bug> Correctly handle timeouts when the pool is busy when async (fhanik)</fix>
+      <add>Added QueryTimeoutInterceptor to be able to configure timeouts on running queries automatically.</add>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat JDBC Connection Pool 1.0.9.4">
+  <subsection name="pool">
+    <changelog>
+      <fix><rev>1069864</rev> <bug>50759</bug> Correctly set validation timestamp when using external validator.(fhanik)</fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat JDBC Connection Pool 1.0.9.3">
+  <subsection name="pool">
+    <changelog>
+      <fix><rev>1060998</rev> <bug>50613</bug> Fix concurrency issue around pool size calculation.(fhanik)</fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat JDBC Connection Pool 1.0.9.2">
+  <subsection name="pool">
+    <changelog>
+      <fix><rev>1057743</rev> Make sure passwords are masked.(fhanik)</fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat JDBC Connection Pool 1.0.9.0">
+  <subsection name="pool">
+    <changelog>
+      <fix><rev>997321</rev> Ensure threads borrowing connections do not
+      get stuck waiting for a new connection if a connection is released in
+      another thread. (markt)</fix>
+      <fix><rev>995432</rev> Make interceptor class names, property names
+      and property values tolerant of whitespace by trimming the values before
+      use. (markt)</fix>
+      <fix><rev>995091</rev> <bug>49831</bug> Make sure pooled XAConnections are
+      closed when the connection pool shuts down. Patch provided by Daniel
+      Mikusa. (markt)</fix>
+      <update><rev>995087</rev> Code clean-up. Remove some unused code. (markt)
+      </update>
+      <update><rev>995083</rev> Update to Tomcat 6.0.29 (for JULI). (markt)
+      </update>
+      <update><rev>992409</rev> Code clean-up. Reduce sequences of three or more
+      blank lines to two blank lines. (markt)</update>
+      <add><rev>952811</rev>, <rev>995095</rev> <bug>48814</bug> Add Validator
+      interface and allow users to configure a Validator class name. Patch
+      provided by Matt Passell. (markt)</add>
+      <update><rev>948073</rev> Code clean-up. Remove unused imports. (markt)
+      </update>
+      <fix><rev>943434</rev> <bug>49224</bug> Only try setting the username and
+      password if they are non-null. Patch provided by Matt Passell. (markt)
+      </fix>
+      <fix><rev>943032</rev> <bug>49269</bug> Set maxIdle to maxActive by
+      default to prevent warning on start when maxIdle > maxActive. Patch
+      provided by Matt Passell. (markt)</fix>
+      <fix><rev>940574</rev> <bug>49241</bug> Don&apos;t ignore the
+      suspectTimeout property. (fhanik)</fix>
+      <fix><rev>939320</rev> Fix svn:keywords for property replacement.
+      (kkolinko)</fix>
+      <add><rev>931550</rev>, <rev>934651</rev>, <rev>934677</rev> Add a
+      statement cache. (fhanik)</add>
+      <update><rev>919076</rev> Improve XA support. (fhanik)</update>
+      <fix><rev>915940</rev> <bug>48392</bug> Add an interceptor to wrap
+      Statements and ResultSets to prevent access to the physical connection.
+      (fhanik)</fix>
+      <fix><rev>912026</rev> Call <code>setTransactionIsolation()</code> before
+      anything else as some drivers require this to be the first call. (fhanik)
+      </fix>
+      <update><rev>900017</rev> Update Javadoc for XADataSource. (kkolinko)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat JDBC Connection Pool prior to 1.0.9.0 (incomplete)">
+  <subsection name="pool">
+    <changelog>
+      <update><rev>720253</rev> Document how to use interceptors</update>
+      <update><rev>717972</rev> Added an interceptor that will clean up non closed statements when a connection is returned to the pool. (<code>org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer</code>)</update>
+      <update><rev>713763</rev> Improve connection state handling</update>
+      <fix><rev>713763</rev> Improve connection state handling</fix>
+    </changelog>
+  </subsection>
+</section>
+</body>
+</document>
diff --git a/dblib/common/doc/jdbc-pool.xml b/dblib/common/doc/jdbc-pool.xml
new file mode 100755 (executable)
index 0000000..8d69624
--- /dev/null
@@ -0,0 +1,988 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "@TOMCAT_PROJECT_DEST@">
+]>
+<document url="jdbc-pool.html">
+
+  &project;
+
+ <properties>
+    <author email="fhanik@apache.org">Filip Hanik</author>
+    <title>The Tomcat JDBC Connection Pool</title>
+  </properties>
+
+<body>
+
+<section name="Table of Contents">
+<toc/>
+</section>
+
+<section name="Introduction">
+
+  <p>The <strong>JDBC Connection Pool <code>org.apache.tomcat.jdbc.pool</code></strong>
+  is a replacement or an alternative to the <a href="http://commons.apache.org/dbcp/">Apache Commons DBCP</a>
+  connection pool.</p>
+
+  <p>So why do we need a new connection pool?</p>
+
+  <p>Here are a few of the reasons:</p>
+    <ol>
+      <li>Commons DBCP 1.x is single threaded. In order to be thread safe
+          Commons locks the entire pool for short periods during both object
+          allocation and object return. Note that this does not apply to
+          Commons DBCP 2.x.</li>
+      <li>Commons DBCP 1.x can be slow. As the number of logical CPUs grows and
+          the number of concurrent threads attempting to borrow or return
+          objects increases, the performance suffers. For highly concurrent
+          systems the impact can be significant. Note that this does not apply
+          to Commons DBCP 2.x.</li>
+      <li>Commons DBCP is over 60 classes. tomcat-jdbc-pool core is 8 classes,
+          hence modifications for future requirement will require much less
+          changes. This is all you need to run the connection pool itself, the
+          rest is gravy.</li>
+      <li>Commons DBCP uses static interfaces. This means you have to use the
+          right version for a given JRE version or you may see
+          <code>NoSuchMethodException</code> exceptions.</li>
+      <li>It's not worth rewriting over 60 classes, when a connection pool can
+          be accomplished with a much simpler implementation.</li>
+      <li>Tomcat jdbc pool implements the ability retrieve a connection
+          asynchronously, without adding additional threads to the library
+          itself.</li>
+      <li>Tomcat jdbc pool is a Tomcat module, it depends on Tomcat JULI, a
+          simplified logging framework used in Tomcat.</li>
+      <li>Retrieve the underlying connection using the
+          <code>javax.sql.PooledConnection</code> interface.</li>
+      <li>Starvation proof. If a pool is empty, and threads are waiting for a
+          connection, when a connection is returned, the pool will awake the
+          correct thread waiting. Most pools will simply starve.</li>
+    </ol>
+
+  <p>Features added over other connection pool implementations</p>
+    <ol>
+      <li>Support for highly concurrent environments and multi core/cpu systems.</li>
+      <li>Dynamic implementation of interface, will support <code>java.sql</code> and <code>javax.sql</code> interfaces for
+          your runtime environment (as long as your JDBC driver does the same), even when compiled with a lower version of the JDK.</li>
+      <li>Validation intervals - we don't have to validate every single time we use the connection, we can do this
+          when we borrow or return the connection, just not more frequent than an interval we can configure.</li>
+      <li>Run-Once query, a configurable query that will be run only once, when the connection to the database is established.
+          Very useful to setup session settings, that you want to exist during the entire time the connection is established.</li>
+      <li>Ability to configure custom interceptors.
+          This allows you to write custom interceptors to enhance the functionality. You can use interceptors to gather query stats,
+          cache session states, reconnect the connection upon failures, retry queries, cache query results, and so on.
+          Your options are endless and the interceptors are dynamic, not tied to a JDK version of a
+          <code>java.sql</code>/<code>javax.sql</code> interface.</li>
+      <li>High performance - we will show some differences in performance later on</li>
+      <li>Extremely simple, due to the very simplified implementation, the line count and source file count are very low, compare with c3p0
+          that has over 200 source files(last time we checked), Tomcat jdbc has a core of 8 files, the connection pool itself is about half
+          that. As bugs may occur, they will be faster to track down, and easier to fix. Complexity reduction has been a focus from inception.</li>
+      <li>Asynchronous connection retrieval - you can queue your request for a connection and receive a <code>Future&lt;Connection&gt;</code> back.</li>
+      <li>Better idle connection handling. Instead of closing connections directly, it can still pool connections and sizes the idle pool with a smarter algorithm.</li>
+      <li>You can decide at what moment connections are considered abandoned, is it when the pool is full, or directly at a timeout
+          by specifying a pool usage threshold.
+      </li>
+      <li>The abandon connection timer will reset upon a statement/query activity. Allowing a connections that is in use for a long time to not timeout.
+          This is achieved using the <code>ResetAbandonedTimer</code>
+      </li>
+      <li>Close connections after they have been connected for a certain time. Age based close upon return to the pool.
+      </li>
+      <li>Get JMX notifications and log entries when connections are suspected for being abandoned. This is similar to
+          the <code>removeAbandonedTimeout</code> but it doesn't take any action, only reports the information.
+          This is achieved using the <code>suspectTimeout</code> attribute.</li>
+      <li>Connections can be retrieved from a <code>java.sql.Driver</code>, <code>javax.sql.DataSource</code> or <code>javax.sql.XADataSource</code>
+          This is achieved using the <code>dataSource</code> and <code>dataSourceJNDI</code> attributes.</li>
+      <li>XA connection support</li>
+    </ol>
+
+
+</section>
+<section name="How to use">
+  <p>
+    Usage of the Tomcat connection pool has been made to be as simple as possible, for those of you that are familiar with commons-dbcp, the
+    transition will be very simple. Moving from other connection pools is also fairly straight forward.
+  </p>
+  <subsection name="Additional features">
+    <p>The Tomcat connection pool offers a few additional features over what most other pools let you do:</p>
+    <ul>
+      <li><code>initSQL</code> - the ability to run a SQL statement exactly once, when the connection is created</li>
+      <li><code>validationInterval</code> - in addition to running validations on connections, avoid running them too frequently.</li>
+      <li><code>jdbcInterceptors</code> - flexible and pluggable interceptors to create any customizations around the pool,
+          the query execution and the result set handling. More on this in the advanced section.</li>
+      <li><code>fairQueue</code> - Set the fair flag to true to achieve thread fairness or to use asynchronous connection retrieval</li>
+    </ul>
+  </subsection>
+  <subsection name="Inside the Apache Tomcat Container">
+    <p>
+      The Tomcat Connection pool is configured as a resource described in <a href="http://tomcat.apache.org/tomcat-8.0-doc/jndi-datasource-examples-howto.html" target="_blank">The Tomcat JDBC documentation</a>
+      With the only difference being that you have to specify the <code>factory</code> attribute and set the value to
+      <code>org.apache.tomcat.jdbc.pool.DataSourceFactory</code>
+    </p>
+  </subsection>
+  <subsection name="Standalone">
+    <p>
+      The connection pool only has another dependency, and that is on tomcat-juli.jar.
+      To configure the pool in a stand alone project using bean instantiation, the bean to instantiate is
+      <code>org.apache.tomcat.jdbc.pool.DataSource</code>. The same attributes (documented below) as you use to configure a connection
+      pool as a JNDI resource, are used to configure a data source as a bean.
+    </p>
+  </subsection>
+  <subsection name="JMX">
+    <p>
+      The connection pool object exposes an MBean that can be registered.
+      In order for the connection pool object to create the MBean, the flag <code>jmxEnabled</code> has to be set to true.
+      This doesn't imply that the pool will be registered with an MBean server, merely that the MBean is created.
+      In a container like Tomcat, Tomcat itself registers the DataSource with the MBean server, the
+      <code>org.apache.tomcat.jdbc.pool.DataSource</code> object will then register the actual
+      connection pool MBean.
+      If you're running outside of a container, you can register the DataSource yourself under any object name you specify,
+      and it propagates the registration to the underlying pool. To do this you would call <code>mBeanServer.registerMBean(dataSource.getPool().getJmxPool(),objectname)</code>.
+      Prior to this call, ensure that the pool has been created by calling <code>dataSource.createPool()</code>.
+    </p>
+  </subsection>
+
+</section>
+<section name="Attributes">
+  <p>To provide a very simple switch to and from commons-dbcp and tomcat-jdbc-pool,
+     Most attributes are the same and have the same meaning.</p>
+  <subsection name="JNDI Factory and Type">
+    <attributes>
+      <attribute name="factory" required="true">
+        <p>factory is required, and the value should be <code>org.apache.tomcat.jdbc.pool.DataSourceFactory</code></p>
+      </attribute>
+      <attribute name="type" required="true">
+        <p>Type should always be <code>javax.sql.DataSource</code> or <code>javax.sql.XADataSource</code></p>
+        <p>Depending on the type a <code>org.apache.tomcat.jdbc.pool.DataSource</code> or a <code>org.apache.tomcat.jdbc.pool.XADataSource</code> will be created.</p>
+      </attribute>
+    </attributes>
+  </subsection>
+
+  <subsection name="System Properties">
+    <p>System properties are JVM wide, affect all pools created in the JVM</p>
+    <attributes>
+      <attribute name="org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader" required="false">
+        <p>(boolean) Controls classloading of dynamic classes, such as
+           JDBC drivers, interceptors and validators. If set to
+           <code>false</code>, default value, the pool will first attempt
+           to load using the current loader (i.e. the class loader that
+           loaded the pool classes) and if class loading fails attempt to
+           load using the thread context loader. Set this value to
+           <code>true</code>, if you wish to remain backwards compatible
+           with Apache Tomcat 8.0.8 and earlier, and only attempt the
+           current loader.
+           If not set then the default value is <code>false</code>.
+        </p>
+      </attribute>
+    </attributes>
+  </subsection>
+
+  <subsection name="Common Attributes">
+  <p>These attributes are shared between commons-dbcp and tomcat-jdbc-pool, in some cases default values are different.</p>
+  <attributes>
+
+    <attribute name="defaultAutoCommit" required="false">
+      <p>(boolean) The default auto-commit state of connections created by this pool. If not set, default is JDBC driver default (If not set then the <code>setAutoCommit</code> method will not be called.)</p>
+    </attribute>
+
+    <attribute name="defaultReadOnly" required="false">
+      <p>(boolean) The default read-only state of connections created by this pool. If not set then the <code>setReadOnly</code> method will not be called. (Some drivers don't support read only mode, ex: Informix)</p>
+    </attribute>
+
+    <attribute name="defaultTransactionIsolation" required="false">
+      <p>(String) The default TransactionIsolation state of connections created by this pool. One of the following: (see javadoc )</p>
+         <ul>
+           <li><code>NONE</code></li>
+           <li><code>READ_COMMITTED</code></li>
+           <li><code>READ_UNCOMMITTED</code></li>
+           <li><code>REPEATABLE_READ</code></li>
+           <li><code>SERIALIZABLE</code></li>
+         </ul>
+         <p>If not set, the method will not be called and it defaults to the JDBC driver.</p>
+    </attribute>
+
+    <attribute name="defaultCatalog" required="false">
+      <p>(String) The default catalog of connections created by this pool.</p>
+    </attribute>
+
+    <attribute name="driverClassName" required="true">
+      <p>(String) The fully qualified Java class name of the JDBC driver to be used. The driver has to be accessible
+         from the same classloader as tomcat-jdbc.jar
+      </p>
+    </attribute>
+
+    <attribute name="username" required="true">
+      <p>(String) The connection username to be passed to our JDBC driver to establish a connection.
+         Note that method <code>DataSource.getConnection(username,password)</code>
+         by default will not use credentials passed into the method,
+         but will use the ones configured here. See <code>alternateUsernameAllowed</code>
+         property for more details.
+      </p>
+    </attribute>
+
+    <attribute name="password" required="true">
+      <p>(String) The connection password to be passed to our JDBC driver to establish a connection.
+         Note that method <code>DataSource.getConnection(username,password)</code>
+         by default will not use credentials passed into the method,
+         but will use the ones configured here. See <code>alternateUsernameAllowed</code>
+         property for more details.
+      </p>
+    </attribute>
+
+    <attribute name="maxActive" required="false">
+      <p>(int) The maximum number of active connections that can be allocated from this pool at the same time.
+         The default value is <code>100</code></p>
+    </attribute>
+
+    <attribute name="maxIdle" required="false">
+      <p>(int) The maximum number of connections that should be kept in the pool at all times.
+         Default value is  <code>maxActive</code>:<code>100</code>
+         Idle connections are checked periodically (if enabled) and
+         connections that been idle for longer than <code>minEvictableIdleTimeMillis</code>
+         will be released. (also see <code>testWhileIdle</code>)</p>
+    </attribute>
+
+    <attribute name="minIdle" required="false">
+      <p>
+        (int) The minimum number of established connections that should be kept in the pool at all times.
+        The connection pool can shrink below this number if validation queries fail.
+        Default value is derived from <code>initialSize</code>:<code>10</code> (also see <code>testWhileIdle</code>)
+      </p>
+    </attribute>
+
+    <attribute name="initialSize" required="false">
+      <p>(int)The initial number of connections that are created when the pool is started.
+         Default value is <code>10</code></p>
+    </attribute>
+
+    <attribute name="maxWait" required="false">
+      <p>(int) The maximum number of milliseconds that the pool will wait (when there are no available connections)
+         for a connection to be returned before throwing an exception.
+         Default value is <code>30000</code> (30 seconds)</p>
+    </attribute>
+
+    <attribute name="testOnBorrow" required="false">
+      <p>(boolean) 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.
+         NOTE - for a true value to have any effect, the <code>validationQuery</code>
+         or <code>validatorClassName</code> parameter must be set to a non-null string.
+         In order to have a more efficient validation, see <code>validationInterval</code>.
+         Default value is <code>false</code>
+      </p>
+    </attribute>
+
+    <attribute name="testOnConnect" required="false">
+      <p>(boolean) The indication of whether objects will be validated when a connection is first created.
+         If an object fails to validate, it will be throw <code>SQLException</code>.
+         NOTE - for a true value to have any effect, the <code>validationQuery</code>, <code>initSQL</code>
+         or <code>validatorClassName</code> parameter must be set to a non-null string.
+         Default value is <code>false</code>
+      </p>
+    </attribute>
+
+    <attribute name="testOnReturn" required="false">
+      <p>(boolean) The indication of whether objects will be validated before being returned to the pool.
+         NOTE - for a true value to have any effect, the <code>validationQuery</code>
+         or <code>validatorClassName</code> parameter must be set to a non-null string.
+         The default value is <code>false</code>.
+      </p>
+    </attribute>
+
+    <attribute name="testWhileIdle" required="false">
+      <p>(boolean) 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.
+         NOTE - for a true value to have any effect, the <code>validationQuery</code>
+         or <code>validatorClassName</code> parameter must be set to a non-null string.
+         The default value is <code>false</code> and this property has to be set in order for the
+         pool cleaner/test thread is to run (also see <code>timeBetweenEvictionRunsMillis</code>)
+      </p>
+    </attribute>
+
+    <attribute name="validationQuery" required="false">
+      <p>(String) The SQL query that will be used to validate connections from this pool before returning them to the caller.
+         If specified, this query does not have to return any data, it just can't throw a <code>SQLException</code>.
+         The default value is <code>null</code>.
+         Example values are <code>SELECT 1</code>(mysql), <code>select 1 from dual</code>(oracle), <code>SELECT 1</code>(MS Sql Server)
+      </p>
+    </attribute>
+
+    <attribute name="validationQueryTimeout" required="false">
+      <p>(int) The timeout in seconds before a connection validation queries fail.  This works by calling
+         <code>java.sql.Statement.setQueryTimeout(seconds)</code> on the statement that executes the <code>validationQuery</code>.
+         The pool itself doesn't timeout the query, it is still up to the JDBC driver to enforce query timeouts.
+         A value less than or equal to zero will disable this feature.
+         The default value is <code>-1</code>.
+      </p>
+    </attribute>
+
+    <attribute name="validatorClassName" required="false">
+      <p>(String) The name of a class which implements the
+         <code>org.apache.tomcat.jdbc.pool.Validator</code> interface and
+         provides a no-arg constructor (may be implicit). If specified, the
+         class will be used to create a Validator instance which is then used
+         instead of any validation query to validate connections. The default
+         value is <code>null</code>. An example value is
+         <code>com.mycompany.project.SimpleValidator</code>.
+      </p>
+    </attribute>
+
+    <attribute name="timeBetweenEvictionRunsMillis" required="false">
+      <p>(int) The number of milliseconds to sleep between runs of the idle connection validation/cleaner thread.
+         This value should not be set under 1 second. It dictates how often we check for idle, abandoned connections, and how often
+         we validate idle connections.
+         The default value is <code>5000</code> (5 seconds). <br/>
+      </p>
+    </attribute>
+
+    <attribute name="numTestsPerEvictionRun" required="false">
+      <p>(int) Property not used in tomcat-jdbc-pool.</p>
+    </attribute>
+
+    <attribute name="minEvictableIdleTimeMillis" required="false">
+      <p>(int) The minimum amount of time an object may sit idle in the pool before it is eligible for eviction.
+         The default value is <code>60000</code> (60 seconds).</p>
+    </attribute>
+
+    <attribute name="accessToUnderlyingConnectionAllowed" required="false">
+      <p>(boolean) Property not used. Access can be achieved by calling <code>unwrap</code> on the pooled connection.
+         see <code>javax.sql.DataSource</code> interface, or call <code>getConnection</code> through reflection or
+         cast the object as <code>javax.sql.PooledConnection</code></p>
+    </attribute>
+
+    <attribute name="removeAbandoned" required="false">
+      <p>(boolean) Flag to remove abandoned connections if they exceed the <code>removeAbandonedTimeout</code>.
+         If set to true a connection is considered abandoned and eligible for removal if it has been in use
+         longer than the <code>removeAbandonedTimeout</code> Setting this to <code>true</code> can recover db connections from
+         applications that fail to close a connection. See also <code>logAbandoned</code>
+         The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="removeAbandonedTimeout" required="false">
+      <p>(int) Timeout in seconds before an abandoned(in use) connection can be removed.
+         The default value is <code>60</code> (60 seconds). The value should be set to the longest running query your applications
+         might have.</p>
+    </attribute>
+
+    <attribute name="logAbandoned" required="false">
+      <p>(boolean) Flag to log stack traces for application code which abandoned a Connection.
+         Logging of abandoned Connections adds overhead for every Connection borrow because a stack trace has to be generated.
+         The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="connectionProperties" required="false">
+      <p>(String) 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.
+         The default value is <code>null</code>.</p>
+    </attribute>
+
+    <attribute name="poolPreparedStatements" required="false">
+      <p>(boolean) Property not used.</p>
+    </attribute>
+
+    <attribute name="maxOpenPreparedStatements" required="false">
+      <p>(int) Property not used.</p>
+    </attribute>
+
+  </attributes>
+
+  </subsection>
+
+  <subsection name="Tomcat JDBC Enhanced Attributes">
+
+  <attributes>
+
+    <attribute name="initSQL" required="false">
+      <p>(String) A custom query to be run when a connection is first created.
+         The default value is <code>null</code>.</p>
+    </attribute>
+
+    <attribute name="jdbcInterceptors" required="false">
+      <p>(String) A semicolon separated list of classnames extending
+         <code>org.apache.tomcat.jdbc.pool.JdbcInterceptor</code> class.
+         See <a href="#Configuring_JDBC_interceptors">Configuring JDBC interceptors</a>
+         below for more detailed description of syntaz and examples.
+      </p>
+      <p>
+         These interceptors will be inserted as an interceptor into the chain
+         of operations on a <code>java.sql.Connection</code> object.
+         The default value is <code>null</code>.
+      </p>
+      <p>
+         Predefined interceptors:<br/>
+         <code>org.apache.tomcat.jdbc.pool.interceptor.<br />ConnectionState</code>
+          - keeps track of auto commit, read only, catalog and transaction isolation level.<br/>
+         <code>org.apache.tomcat.jdbc.pool.interceptor.<br />StatementFinalizer</code>
+          - keeps track of opened statements, and closes them when the connection is returned to the pool.
+      </p>
+      <p>
+         More predefined interceptors are described in detail in the
+         <a href="#JDBC_interceptors">JDBC Interceptors section</a>.
+      </p>
+    </attribute>
+
+    <attribute name="validationInterval" required="false">
+      <p>(long) avoid excess validation, only run validation at most at this frequency - time in milliseconds.
+         If a connection is due for validation, but has been validated previously within this interval, it will not be validated again.
+         The default value is <code>3000</code> (3 seconds).</p>
+    </attribute>
+
+    <attribute name="jmxEnabled" required="false">
+      <p>(boolean) Register the pool with JMX or not.
+         The default value is <code>true</code>.</p>
+    </attribute>
+
+    <attribute name="fairQueue" required="false">
+      <p>(boolean) Set to true if you wish that calls to getConnection should be treated
+         fairly in a true FIFO fashion. This uses the <code>org.apache.tomcat.jdbc.pool.FairBlockingQueue</code>
+         implementation for the list of the idle connections. The default value is <code>true</code>.
+         This flag is required when you want to use asynchronous connection retrieval.<br/>
+         Setting this flag ensures that threads receive connections in the order they arrive.<br/>
+         During performance tests, there is a very large difference in how locks
+         and lock waiting is implemented. When <code>fairQueue=true</code>
+         there is a decision making process based on what operating system the system is running.
+         If the system is running on Linux (property <code>os.name=Linux</code>.
+         To disable this Linux specific behavior and still use the fair queue, simply add the property
+         <code>org.apache.tomcat.jdbc.pool.FairBlockingQueue.ignoreOS=true</code> to your system properties
+         before the connection pool classes are loaded.
+      </p>
+    </attribute>
+
+    <attribute name="abandonWhenPercentageFull" required="false">
+      <p>(int) Connections that have been abandoned (timed out) wont get closed and reported up unless
+         the number of connections in use are above the percentage defined by <code>abandonWhenPercentageFull</code>.
+         The value should be between 0-100.
+         The default value is <code>0</code>, which implies that connections are eligible for closure as soon
+         as <code>removeAbandonedTimeout</code> has been reached.</p>
+    </attribute>
+
+    <attribute name="maxAge" required="false">
+      <p>(long) Time in milliseconds to keep this connection. This attribute
+         works both when returning connection and when borrowing connection.
+         When a connection is borrowed from the pool, the pool will check to see
+         if the <code>now - time-when-connected > maxAge</code> has been reached
+         , and if so, it reconnects before borrow it. When a connection is
+         returned to the pool, the pool will check to see if the
+         <code>now - time-when-connected > maxAge</code> has been reached, and
+         if so, it closes the connection rather than returning it to the pool.
+         The default value is <code>0</code>, which implies that connections
+         will be left open and no age check will be done upon borrowing from the
+         pool and returning the connection to the pool.</p>
+    </attribute>
+
+    <attribute name="useEquals" required="false">
+      <p>(boolean) Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> and set to <code>false</code>
+         when you wish to use <code>==</code> when comparing method names. This property does not apply to added interceptors as those are configured individually.
+         The default value is <code>true</code>.
+      </p>
+    </attribute>
+    <attribute name="suspectTimeout" required="false">
+      <p>(int) Timeout value in seconds. Default value is <code>0</code>.<br/>
+           Similar to to the <code>removeAbandonedTimeout</code> value but instead of treating the connection
+           as abandoned, and potentially closing the connection, this simply logs the warning if
+           <code>logAbandoned</code> is set to true. If this value is equal or less than 0, no suspect
+           checking will be performed. Suspect checking only takes place if the timeout value is larger than 0 and
+           the connection was not abandoned or if abandon check is disabled. If a connection is suspect a WARN message gets
+           logged and a JMX notification gets sent once.
+      </p>
+    </attribute>
+    <attribute name="rollbackOnReturn" required="false">
+      <p>(boolean) If <code>autoCommit==false</code> then the pool can terminate the transaction by calling rollback on the connection as it is returned to the pool
+          Default value is <code>false</code>.<br/>
+      </p>
+    </attribute>
+    <attribute name="commitOnReturn" required="false">
+      <p>(boolean) If <code>autoCommit==false</code> then the pool can complete the transaction by calling commit on the connection as it is returned to the pool
+          If <code>rollbackOnReturn==true</code> then this attribute is ignored.
+          Default value is <code>false</code>.<br/>
+      </p>
+    </attribute>
+    <attribute name="alternateUsernameAllowed" required="false">
+      <p>(boolean) By default, the jdbc-pool will ignore the
+         <a href="http://docs.oracle.com/javase/6/docs/api/javax/sql/DataSource.html#getConnection(java.lang.String,%20java.lang.String)"><code>DataSource.getConnection(username,password)</code></a>
+         call, and simply return a previously pooled connection under the globally configured properties <code>username</code> and <code>password</code>, for performance reasons.
+      </p>
+      <p>
+         The pool can however be configured to allow use of different credentials
+         each time a connection is requested.  To enable the functionality described in the
+         <a href="http://docs.oracle.com/javase/6/docs/api/javax/sql/DataSource.html#getConnection(java.lang.String,%20java.lang.String)"><code>DataSource.getConnection(username,password)</code></a>
+         call, simply set the property <code>alternateUsernameAllowed</code>
+         to <code>true</code>.<br />
+         Should you request a connection with the credentials user1/password1 and the connection
+         was previously connected using different user2/password2, the connection will be closed,
+         and reopened with the requested credentials. This way, the pool size is still managed
+         on a global level, and not on a per schema level. <br/>
+         The default value is <code>false</code>.<br/>
+         This property was added as an enhancement to <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=50025">bug 50025</a>.
+      </p>
+    </attribute>
+    <attribute name="dataSource" required="false">
+      <p>(javax.sql.DataSource) Inject a data source to the connection pool, and the pool will use the data source to retrieve connections instead of establishing them using the <code>java.sql.Driver</code> interface.
+         This is useful when you wish to pool XA connections or connections established using a data source instead of a connection string. Default value is <code>null</code>
+      </p>
+    </attribute>
+    <attribute name="dataSourceJNDI" required="false">
+      <p>(String) The JNDI name for a data source to be looked up in JNDI and then used to establish connections to the database. See the <code>dataSource</code> attribute. Default value is <code>null</code>
+      </p>
+    </attribute>
+    <attribute name="useDisposableConnectionFacade" required="false">
+      <p>(boolean) Set this to true if you wish to put a facade on your connection so that it cannot be reused after it has been closed. This prevents a thread holding on to a
+                   reference of a connection it has already called closed on, to execute queries on it. Default value is <code>true</code>.
+      </p>
+    </attribute>
+    <attribute name="logValidationErrors" required="false">
+      <p>(boolean) Set this to true to log errors during the validation phase to the log file. If set to true, errors will be logged as SEVERE. Default value is <code>false</code> for backwards compatibility.
+      </p>
+    </attribute>
+    <attribute name="propagateInterruptState" required="false">
+      <p>(boolean) Set this to true to propagate the interrupt state for a thread that has been interrupted (not clearing the interrupt state). Default value is <code>false</code> for backwards compatibility.
+      </p>
+    </attribute>
+    <attribute name="ignoreExceptionOnPreLoad" required="false">
+      <p>(boolean) Flag whether ignore error of connection creation while initializing the pool.
+         Set to true if you want to ignore error of connection creation while initializing the pool.
+         Set to false if you want to fail the initialization of the pool by throwing exception.
+         The default value is <code>false</code>.
+      </p>
+    </attribute>
+
+  </attributes>
+  </subsection>
+</section>
+<section name="Advanced usage">
+  <subsection name="JDBC interceptors">
+    <p>To see an example of how to use an interceptor, take a look at
+    <code>org.apache.tomcat.jdbc.pool.interceptor.ConnectionState</code>.
+    This simple interceptor is a cache of three attributes, transaction isolation level, auto commit and read only state,
+    in order for the system to avoid not needed roundtrips to the database.
+    </p>
+    <p>Further interceptors will be added to the core of the pool as the need arises. Contributions are always welcome!</p>
+    <p>Interceptors are of course not limited to just <code>java.sql.Connection</code> but can be used to wrap any
+    of the results from a method invokation as well. You could build query performance analyzer that provides JMX notifications when a
+    query is running longer than the expected time.</p>
+  </subsection>
+  <subsection name="Configuring JDBC interceptors">
+    <p>Configuring JDBC interceptors is done using the <b>jdbcInterceptors</b> property.
+    The property contains a list of semicolon separated class names. If the
+    classname is not fully qualified it will be prefixed with the
+    <code>org.apache.tomcat.jdbc.pool.interceptor.</code> prefix.
+    </p>
+    <p>Example:<br/>
+      <code>
+      jdbcInterceptors=&quot;org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
+        org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer&quot;
+      </code>
+      <br/>
+      is the same as
+      <br/>
+      <code> jdbcInterceptors=&quot;ConnectionState;StatementFinalizer&quot;</code>
+    </p>
+    <p>
+    Interceptors can have properties as well. Properties for an interceptor
+    are specified within parentheses after the class name. Several properties
+    are separated by commas.
+    </p>
+    <p>Example:<br/>
+    <code>
+      jdbcInterceptors=&quot;ConnectionState;StatementFinalizer(useEquals=true)&quot;
+    </code>
+    </p>
+    <p>
+    Extra whitespace characters around class names, property names and values
+    are ignored.
+    </p>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.JdbcInterceptor">
+    <p>Abstract base class for all interceptors, cannot be instantiated.</p>
+    <attributes>
+      <attribute name="useEquals" required="false">
+        <p>(boolean) Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> and set to <code>false</code>
+         when you wish to use <code>==</code> when comparing method names.
+         The default value is <code>true</code>.
+        </p>
+      </attribute>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState">
+    <p>Caches the connection for the following attributes <code>autoCommit</code>, <code>readOnly</code>,
+       <code>transactionIsolation</code> and <code>catalog</code>.
+       It is a performance enhancement to avoid roundtrip to the database when getters are called or setters are called with an already set value.
+    </p>
+    <attributes>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer">
+    <p>Keeps track of all statements created using <code>createStatement</code>, <code>prepareStatement</code> or <code>prepareCall</code>
+       and closes these statements when the connection is returned to the pool.
+    </p>
+    <attributes>
+      <attribute name="trace" required="false">
+        <p>(boolean as String) Enable tracing of unclosed statements.
+           When enabled and a connection is closed, and statements are not closed,
+           the interceptor will log all stack traces.
+           The default value is <code>false</code>.
+        </p>
+      </attribute>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.StatementCache">
+    <p>Caches <code>PreparedStatement</code> and/or <code>CallableStatement</code>
+       instances on a connection.
+    </p>
+    <p>The statements are cached per connection.
+       The count limit is counted globally for all connections that belong to
+       the same pool. Once the count reaches <code>max</code>, subsequent
+       statements are not returned to the cache and are closed immediately.
+    </p>
+    <attributes>
+      <attribute name="prepared" required="false">
+        <p>(boolean as String) Enable caching of <code>PreparedStatement</code>
+           instances created using <code>prepareStatement</code> calls.
+           The default value is <code>true</code>.
+        </p>
+      </attribute>
+      <attribute name="callable" required="false">
+        <p>(boolean as String) Enable caching of <code>CallableStatement</code>
+           instances created using <code>prepareCall</code> calls.
+           The default value is <code>false</code>.
+        </p>
+      </attribute>
+      <attribute name="max" required="false">
+        <p>(int as String) Limit on the count of cached statements across
+           the connection pool.
+           The default value is <code>50</code>.
+        </p>
+      </attribute>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor">
+    <p>See <bug>48392</bug>. Interceptor to wrap statements and result sets in order to prevent access to the actual connection
+       using the methods <code>ResultSet.getStatement().getConnection()</code> and <code>Statement.getConnection()</code>
+    </p>
+    <attributes>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor">
+    <p>Automatically calls <code>java.sql.Statement.setQueryTimeout(seconds)</code> when a new statement is created.
+       The pool itself doesn't timeout the query, it is still up to the JDBC driver to enforce query timeouts.
+    </p>
+    <attributes>
+      <attribute name="queryTimeout" required="true">
+        <p>(int as String) The number of seconds to set for the query timeout.
+           A value less than or equal to zero will disable this feature.
+           The default value is <code>1</code> seconds.
+        </p>
+      </attribute>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport">
+    <p>Keeps track of query performance and issues log entries when queries exceed a time threshold of fail.
+       The log level used is <code>WARN</code>
+    </p>
+    <attributes>
+      <attribute name="threshold" required="false">
+        <p>(int as String) The number of milliseconds a query has to exceed before issuing a log alert.
+           The default value is <code>1000</code> milliseconds.
+        </p>
+      </attribute>
+      <attribute name="maxQueries" required="false">
+        <p>(int as String) The maximum number of queries to keep track of in order to preserve memory space.
+           A value less than or equal to 0 will disable this feature.
+           The default value is <code>1000</code>.
+        </p>
+      </attribute>
+      <attribute name="logSlow" required="false">
+        <p>(boolean as String) Set to <code>true</code> if you wish to log slow queries.
+            The default value is <code>true</code>.
+        </p>
+      </attribute>
+      <attribute name="logFailed" required="false">
+        <p>(boolean as String) Set to <code>true</code> if you wish to log failed queries.
+            The default value is <code>false</code>.
+        </p>
+      </attribute>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx">
+    <p>Extends the <code>SlowQueryReport</code> and in addition to log entries it issues JMX notification
+       for monitoring tools to react to. Inherits all the attributes from its parent class.
+       This class uses Tomcat's JMX engine so it wont work outside of the Tomcat container.
+       By default, JMX notifications are sent through the ConnectionPool mbean if it is enabled.
+       The <code>SlowQueryReportJmx</code> can also register an MBean if <code>notifyPool=false</code>
+    </p>
+    <attributes>
+      <attribute name="notifyPool" required="false">
+        <p>(boolean as String) Set to false if you want JMX notifications to go to the <code>SlowQueryReportJmx</code> MBean
+           The default value is <code>true</code>.
+        </p>
+      </attribute>
+      <attribute name="objectName" required="false">
+        <p>(String) Define a valid <code>javax.management.ObjectName</code> string that will be used to register this object with the platform mbean server
+           The default value is <code>null</code> and the object will be registered using
+           tomcat.jdbc:type=org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx,name=the-name-of-the-pool
+        </p>
+      </attribute>
+    </attributes>
+  </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer">
+    <p>
+        The abandoned timer starts when a connection is checked out from the pool.
+        This means if you have a 30second timeout and run 10x10second queries using the connection
+        it will be marked abandoned and potentially reclaimed depending on the <code>abandonWhenPercentageFull</code>
+        attribute.
+        Using this interceptor it will reset the checkout timer every time you perform an operation on the connection or execute a
+        query successfully.
+    </p>
+    <attributes>
+    </attributes>
+  </subsection>
+</section>
+
+<section name="Code Example">
+  <p>Other examples of Tomcat configuration for JDBC usage can be found <a href="http://tomcat.apache.org/tomcat-8.0-doc/jndi-datasource-examples-howto.html">in the Tomcat documentation</a>. </p>
+  <subsection name="Plain Ol' Java">
+    <p>Here is a simple example of how to create and use a data source.</p>
+<source><![CDATA[  import java.sql.Connection;
+  import java.sql.ResultSet;
+  import java.sql.Statement;
+
+  import org.apache.tomcat.jdbc.pool.DataSource;
+  import org.apache.tomcat.jdbc.pool.PoolProperties;
+
+  public class SimplePOJOExample {
+
+      public static void main(String[] args) throws Exception {
+          PoolProperties p = new PoolProperties();
+          p.setUrl("jdbc:mysql://localhost:3306/mysql");
+          p.setDriverClassName("com.mysql.jdbc.Driver");
+          p.setUsername("root");
+          p.setPassword("password");
+          p.setJmxEnabled(true);
+          p.setTestWhileIdle(false);
+          p.setTestOnBorrow(true);
+          p.setValidationQuery("SELECT 1");
+          p.setTestOnReturn(false);
+          p.setValidationInterval(30000);
+          p.setTimeBetweenEvictionRunsMillis(30000);
+          p.setMaxActive(100);
+          p.setInitialSize(10);
+          p.setMaxWait(10000);
+          p.setRemoveAbandonedTimeout(60);
+          p.setMinEvictableIdleTimeMillis(30000);
+          p.setMinIdle(10);
+          p.setLogAbandoned(true);
+          p.setRemoveAbandoned(true);
+          p.setJdbcInterceptors(
+            "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
+            "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
+          DataSource datasource = new DataSource();
+          datasource.setPoolProperties(p);
+
+          Connection con = null;
+          try {
+            con = datasource.getConnection();
+            Statement st = con.createStatement();
+            ResultSet rs = st.executeQuery("select * from user");
+            int cnt = 1;
+            while (rs.next()) {
+                System.out.println((cnt++)+". Host:" +rs.getString("Host")+
+                  " User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
+            }
+            rs.close();
+            st.close();
+          } finally {
+            if (con!=null) try {con.close();}catch (Exception ignore) {}
+          }
+      }
+
+  }]]></source>
+  </subsection>
+  <subsection name="As a Resource">
+    <p>And here is an example on how to configure a resource for JNDI lookups</p>
+<source><![CDATA[<Resource name="jdbc/TestDB"
+          auth="Container"
+          type="javax.sql.DataSource"
+          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
+          testWhileIdle="true"
+          testOnBorrow="true"
+          testOnReturn="false"
+          validationQuery="SELECT 1"
+          validationInterval="30000"
+          timeBetweenEvictionRunsMillis="30000"
+          maxActive="100"
+          minIdle="10"
+          maxWait="10000"
+          initialSize="10"
+          removeAbandonedTimeout="60"
+          removeAbandoned="true"
+          logAbandoned="true"
+          minEvictableIdleTimeMillis="30000"
+          jmxEnabled="true"
+          jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
+            org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
+          username="root"
+          password="password"
+          driverClassName="com.mysql.jdbc.Driver"
+          url="jdbc:mysql://localhost:3306/mysql"/>]]></source>
+
+  </subsection>
+  <subsection name="Asynchronous Connection Retrieval">
+    <p> The Tomcat JDBC connection pool supports asynchronous connection retrieval without adding additional threads to the
+        pool library. It does this by adding a method to the data source called <code>Future&lt;Connection&gt; getConnectionAsync()</code>.
+        In order to use the async retrieval, two conditions must be met:
+    </p>
+        <ol>
+          <li>You must configure the <code>fairQueue</code> property to be <code>true</code>.</li>
+          <li>You will have to cast the data source to <code>org.apache.tomcat.jdbc.pool.DataSource</code></li>
+        </ol>
+        An example of using the async feature is show below.
+<source><![CDATA[  Connection con = null;
+  try {
+    Future<Connection> future = datasource.getConnectionAsync();
+    while (!future.isDone()) {
+      System.out.println("Connection is not yet available. Do some background work");
+      try {
+        Thread.sleep(100); //simulate work
+      }catch (InterruptedException x) {
+        Thread.currentThread().interrupt();
+      }
+    }
+    con = future.get(); //should return instantly
+    Statement st = con.createStatement();
+    ResultSet rs = st.executeQuery("select * from user");]]></source>
+
+  </subsection>
+  <subsection name="Interceptors">
+    <p>Interceptors are a powerful way to enable, disable or modify functionality on a specific connection or its sub components.
+       There are many different use cases for when interceptors are useful. By default, and for performance reasons, the connection pool is stateless.
+       The only state the pool itself inserts are <code>defaultAutoCommit</code>, <code>defaultReadOnly</code>, <code>defaultTransactionIsolation</code>, <code>defaultCatalog</code> if
+       these are set. These 4 properties are only set upon connection creation. Should these properties be modified during the usage of the connection,
+       the pool itself will not reset them.</p>
+    <p>An interceptor has to extend the <code>org.apache.tomcat.jdbc.pool.JdbcInterceptor</code> class. This class is fairly simple,
+       You will need to have a no arg constructor</p>
+<source><![CDATA[  public JdbcInterceptor() {
+  }]]></source>
+    <p>
+       When a connection is borrowed from the pool, the interceptor can initialize or in some other way react to the event by implementing the
+    </p>
+<source><![CDATA[  public abstract void reset(ConnectionPool parent, PooledConnection con);]]></source>
+    <p>
+       method. This method gets called with two parameters, a reference to the connection pool itself <code>ConnectionPool parent</code>
+       and a reference to the underlying connection <code>PooledConnection con</code>.
+    </p>
+    <p>
+       When a method on the <code>java.sql.Connection</code> object is invoked, it will cause the
+    </p>
+<source><![CDATA[  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable]]></source>
+    <p>
+       method to get invoked. The <code>Method method</code> is the actual method invoked, and <code>Object[] args</code> are the arguments.
+       To look at a very simple example, where we demonstrate how to make the invokation to <code>java.sql.Connection.close()</code> a noop
+       if the connection has been closed
+    </p>
+<source><![CDATA[  if (CLOSE_VAL==method.getName()) {
+      if (isClosed()) return null; //noop for already closed.
+  }
+  return super.invoke(proxy,method,args);]]></source>
+    <p>
+        There is an observation being made. It is the comparison of the method name. One way to do this would be to do
+        <code>&quot;close&quot;.equals(method.getName())</code>.
+        Above we see a direct reference comparison between the method name and <code>static final String</code> reference.
+        According to the JVM spec, method names and static final String end up in a shared constant pool, so the reference comparison should work.
+        One could of course do this as well:
+    </p>
+<source><![CDATA[  if (compare(CLOSE_VAL,method)) {
+      if (isClosed()) return null; //noop for already closed.
+  }
+  return super.invoke(proxy,method,args);]]></source>
+    <p>
+        The <code>compare(String,Method)</code> will use the <code>useEquals</code> flag on an interceptor and do either reference comparison or
+        a string value comparison when the <code>useEquals=true</code> flag is set.
+    </p>
+    <p>Pool start/stop<br/>
+       When the connection pool is started or closed, you can be notifed. You will only be notified once per interceptor class
+       even though it is an instance method. and you will be notified using an interceptor currently not attached to a pool.
+    </p>
+<source><![CDATA[  public void poolStarted(ConnectionPool pool) {
+  }
+
+  public void poolClosed(ConnectionPool pool) {
+  }]]></source>
+    <p>
+       When overriding these methods, don't forget to call super if you are extending a class other than <code>JdbcInterceptor</code>
+    </p>
+    <p>Configuring interceptors<br/>
+       Interceptors are configured using the <code>jdbcInterceptors</code> property or the <code>setJdbcInterceptors</code> method.
+       An interceptor can have properties, and would be configured like this
+    </p>
+<source><![CDATA[  String jdbcInterceptors=
+    "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState(useEquals=true,fast=yes)"]]></source>
+
+    <p>Interceptor properties<br/>
+       Since interceptors can have properties, you need to be able to read the values of these properties within your
+       interceptor. Taking an example like the one above, you can override the <code>setProperties</code> method.
+    </p>
+<source><![CDATA[  public void setProperties(Map<String, InterceptorProperty> properties) {
+     super.setProperties(properties);
+     final String myprop = "myprop";
+     InterceptorProperty p1 = properties.get(myprop);
+     if (p1!=null) {
+         setMyprop(Long.parseLong(p1.getValue()));
+     }
+  }]]></source>
+
+  </subsection>
+  <subsection name="Getting the actual JDBC connection">
+    <p>Connection pools create wrappers around the actual connection in order to properly pool them.
+       We also create interceptors in these wrappers to be able to perform certain functions.
+       If there is a need to retrieve the actual connection, one can do so using the <code>javax.sql.PooledConnection</code>
+       interface.
+    </p>
+<source><![CDATA[  Connection con = datasource.getConnection();
+  Connection actual = ((javax.sql.PooledConnection)con).getConnection();]]></source>
+
+  </subsection>
+
+</section>
+
+<section name="Building">
+  <p>We build the JDBC pool code with 1.6, but it is backwards compatible down to 1.5 for runtime environment. For unit test, we use 1.6 and higher</p>
+  <p>Other examples of Tomcat configuration for JDBC usage can be found <a href="http://tomcat.apache.org/tomcat-8.0-doc/jndi-datasource-examples-howto.html">in the Tomcat documentation</a>. </p>
+  <subsection name="Building from source">
+    <p>Building is pretty simple. The pool has a dependency on <code>tomcat-juli.jar</code> and in case you want the <code>SlowQueryReportJmx</code></p>
+<source><![CDATA[  javac -classpath tomcat-juli.jar \
+        -d . \
+        org/apache/tomcat/jdbc/pool/*.java \
+        org/apache/tomcat/jdbc/pool/interceptor/*.java \
+        org/apache/tomcat/jdbc/pool/jmx/*.java]]></source>
+    <p>
+       A build file can be found in the Tomcat <a href="http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/">source repository</a>.
+    </p>
+    <p>
+      As a convenience, a build file is also included where a simple build command will generate all files needed.
+    </p>
+<source>  ant download  (downloads dependencies)
+  ant build     (compiles and generates .jar files)
+  ant dist      (creates a release package)
+  ant test      (runs tests, expects a test database to be setup)</source>
+
+    <p>
+      The system is structured for a Maven build, but does generate release artifacts. Just the library itself.
+    </p>
+  </subsection>
+</section>
+</body>
+
+</document>
diff --git a/dblib/common/doc/package.xsl b/dblib/common/doc/package.xsl
new file mode 100755 (executable)
index 0000000..cdadd53
--- /dev/null
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  Stylesheet that generates "package.html" for Javadoc tool
+  from jdbc-pool.xml documentation file.
+  It is based on "tomcat-docs" stylesheet, but it needs to avoid
+  generating complicated headers and footers, as those cannot be
+  digested by Javadoc tool and break layout of javadoc pages.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  version="1.0">
+
+
+  <!-- Output method -->
+  <xsl:output method="html"
+            encoding="UTF-8"
+              indent="no"/>
+
+
+  <!-- Defined parameters (overrideable) -->
+  <xsl:param    name="relative-path"    select="'.'"/>
+  <xsl:param    name="void-image"       select="'/images/void.gif'"/>
+  <xsl:param    name="standalone"       select="''"/>
+  <xsl:param    name="buglink"          select="'http://bz.apache.org/bugzilla/show_bug.cgi?id='"/>
+  <xsl:param    name="revlink"          select="'http://svn.apache.org/viewvc?view=rev&amp;rev='"/>
+
+  <!-- Defined variables (non-overrideable) -->
+  <xsl:variable name="body-bg"          select="'#ffffff'"/>
+  <xsl:variable name="body-fg"          select="'#000000'"/>
+  <xsl:variable name="body-link"        select="'#525D76'"/>
+  <xsl:variable name="banner-bg"        select="'#525D76'"/>
+  <xsl:variable name="banner-fg"        select="'#ffffff'"/>
+  <xsl:variable name="sub-banner-bg"    select="'#828DA6'"/>
+  <xsl:variable name="sub-banner-fg"    select="'#ffffff'"/>
+  <xsl:variable name="source-color"     select="'#023264'"/>
+  <xsl:variable name="attributes-color" select="'#023264'"/>
+  <xsl:variable name="table-th-bg"      select="'#039acc'"/>
+  <xsl:variable name="table-td-bg"      select="'#a0ddf0'"/>
+
+  <!-- Process an entire document into an HTML page -->
+  <xsl:template match="document">
+  <xsl:variable name="project"
+              select="document('project.xml')/project"/>
+    <html>
+    <head>
+    <title><xsl:value-of select="project/title"/> - <xsl:value-of select="properties/title"/></title>
+    </head>
+
+    <body bgcolor="{$body-bg}" text="{$body-fg}" link="{$body-link}"
+          alink="{$body-link}" vlink="{$body-link}">
+
+          <h2><xsl:value-of select="properties/title"/>.</h2>
+          <xsl:apply-templates select="body/section"/>
+    </body>
+    </html>
+
+  </xsl:template>
+
+
+  <!-- Process a documentation section -->
+  <xsl:template match="section">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2">
+      <!-- Section heading -->
+      <tr><td bgcolor="{$banner-bg}">
+          <font color="{$banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Section body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a documentation subsection -->
+  <xsl:template match="subsection">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2">
+      <!-- Subsection heading -->
+      <tr><td bgcolor="{$sub-banner-bg}">
+          <font color="{$sub-banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Subsection body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a source code example -->
+  <xsl:template match="source">
+    <xsl:variable name="void">
+      <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
+    </xsl:variable>
+    <div align="left">
+      <table cellspacing="4" cellpadding="0" border="0">
+        <tr>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="{$source-color}" width="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="#ffffff" height="1"><pre>
+            <xsl:value-of select="."/>
+          </pre></td>
+          <td bgcolor="{$source-color}" width="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+      </table>
+    </div>
+  </xsl:template>
+
+
+  <!-- Process an attributes list with nested attribute elements -->
+  <xsl:template match="attributes">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Attribute</font>
+        </th>
+        <th width="85%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Description</font>
+        </th>
+      </tr>
+      <xsl:for-each select="attribute">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:if test="@required = 'true'">
+              <strong><code><xsl:value-of select="@name"/></code></strong>
+            </xsl:if>
+            <xsl:if test="@required != 'true'">
+              <code><xsl:value-of select="@name"/></code>
+            </xsl:if>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+        </tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!-- Process a properties list with nested property elements -->
+  <xsl:template match="properties">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Property</font>
+        </th>
+        <th width="85%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Description</font>
+        </th>
+      </tr>
+      <xsl:for-each select="property">
+        <tr>
+          <td align="left" valign="center">
+            <code><xsl:value-of select="@name"/></code>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+        </tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!-- Fix relative links in printer friendly versions of the docs -->
+  <xsl:template match="a">
+    <xsl:variable name="href" select="@href"/>
+    <xsl:choose>
+      <xsl:when test="$standalone = 'standalone'">
+        <xsl:apply-templates/>
+      </xsl:when>
+      <xsl:when test="$href != ''">
+        <a href="{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="name" select="@name"/>
+        <a name="{$name}"><xsl:apply-templates/></a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Link to a bug report -->
+  <xsl:template match="bug">
+      <xsl:variable name="link"><xsl:value-of select="$buglink"/><xsl:value-of select="text()"/></xsl:variable>
+      <a href="{$link}"><xsl:apply-templates/></a>
+  </xsl:template>
+
+  <!-- Link to a SVN revision report -->
+  <xsl:template match="rev">
+      <xsl:variable name="link"><xsl:value-of select="$revlink"/><xsl:value-of select="text()"/></xsl:variable>
+      <a href="{$link}"><xsl:apply-templates/></a>
+  </xsl:template>
+
+  <!-- Process everything else by just passing it through -->
+  <xsl:template match="*|@*">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|*|text()"/>
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:stylesheet>
diff --git a/dblib/common/doc/project.xml b/dblib/common/doc/project.xml
new file mode 100755 (executable)
index 0000000..912903d
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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="Apache Tomcat JDBC Pool Documentation"
+        href="http://tomcat.apache.org/">
+
+    <title>Apache Tomcat JDBC Pool</title>
+
+    <logo href="/images/tomcat.gif">
+      The Apache Tomcat Servlet/JSP Container
+    </logo>
+
+    <body>
+    </body>
+
+</project>
+
diff --git a/dblib/common/pom.xml b/dblib/common/pom.xml
new file mode 100755 (executable)
index 0000000..fa25c98
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.openecomp.sdnc.core</groupId>
+               <artifactId>dblib</artifactId>
+               <version>1.1.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>dblib-common</artifactId>
+  <packaging>bundle</packaging>
+  <name>DBLIB Adaptor - Common</name>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.apache.tomcat</groupId>
+                       <artifactId>juli</artifactId>
+                       <version>6.0.32</version>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <version>4.11</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.tomcat</groupId>
+                       <artifactId>tomcat-dbcp</artifactId>
+                       <version>8.0.14</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>com.h2database</groupId>
+                       <artifactId>h2</artifactId>
+                       <version>1.3.152</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>equinoxSDK381</groupId>
+                       <artifactId>org.eclipse.osgi</artifactId>
+                       <version>${equinox.osgi.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>mysql</groupId>
+                       <artifactId>mysql-connector-java</artifactId>
+                       <version>${mysql.connector.version}</version>
+               </dependency>
+
+       </dependencies>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.7</source>
+                                       <target>1.7</target>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               <Bundle-Activator>org.openecomp.sdnc.sli.resource.common.CommonActivator</Bundle-Activator>
+                                               <Export-Package>
+                                                       org.openecomp.sdnc.sli.resource.common;version=${project.version},
+                                                       org.apache.tomcat.jdbc;version=${project.version},
+                                                       org.apache.tomcat.jdbc.pool;version=${project.version},
+                                                       org.apache.tomcat.jdbc.naming;version=${project.version},
+                                                       org.apache.tomcat.jdbc.pool.interceptor;version=${project.version},
+                                                       org.apache.tomcat.jdbc.pool.jmx;version=${project.version}</Export-Package>
+                                               <Import-Package>*</Import-Package>
+                                               <!--
+                                               <Embed-Dependency>*;scope=compile;artifactId=commons-lang|commons-lang3</Embed-Dependency>
+                                                -->
+                                               <Embed-Transitive>true</Embed-Transitive>
+                                       </instructions>
+                                       <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+</project>
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java
new file mode 100644 (file)
index 0000000..c6112a1
--- /dev/null
@@ -0,0 +1,254 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.naming;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ClassLoaderUtil;
+
+/**
+ * Simple way of configuring generic resources by using reflection.
+ * Example usage:
+ * <pre><code>
+ * &lt;Resource factory=&quot;org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory&quot;
+ *              name=&quot;jdbc/test&quot;
+ *              type=&quot;org.apache.derby.jdbc.ClientXADataSource&quot;
+ *              databaseName=&quot;sample&quot;
+ *              createDatabase=&quot;create&quot;
+ *              serverName=&quot;localhost&quot;
+ *              port=&quot;1527&quot;/&gt;
+ * </code></pre>
+ *
+ */
+public class GenericNamingResourcesFactory implements ObjectFactory {
+    private static final Log log = LogFactory.getLog(GenericNamingResourcesFactory.class);
+
+    @Override
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
+        if ((obj == null) || !(obj instanceof Reference)) {
+            return null;
+        }
+        Reference ref = (Reference) obj;
+        Enumeration<RefAddr> refs = ref.getAll();
+
+        String type = ref.getClassName();
+        Object o =
+            ClassLoaderUtil.loadClass(
+                type,
+                GenericNamingResourcesFactory.class.getClassLoader(),
+                Thread.currentThread().getContextClassLoader())
+            .newInstance();
+
+        while (refs.hasMoreElements()) {
+            RefAddr addr = refs.nextElement();
+            String param = addr.getType();
+            String value = null;
+            if (addr.getContent()!=null) {
+                value = addr.getContent().toString();
+            }
+            if (setProperty(o, param, value)) {
+
+            } else {
+                log.debug("Property not configured["+param+"]. No setter found on["+o+"].");
+            }
+        }
+        return o;
+    }
+
+    @SuppressWarnings("null") // setPropertyMethodVoid can't be null when used
+    private static boolean setProperty(Object o, String name, String value) {
+        if (log.isDebugEnabled())
+            log.debug("IntrospectionUtils: setProperty(" +
+                    o.getClass() + " " + name + "=" + value + ")");
+
+        String setter = "set" + capitalize(name);
+
+        try {
+            Method methods[] = o.getClass().getMethods();
+            Method setPropertyMethodVoid = null;
+            Method setPropertyMethodBool = null;
+
+            // First, the ideal case - a setFoo( String ) method
+            for (int i = 0; i < methods.length; i++) {
+                Class<?> paramT[] = methods[i].getParameterTypes();
+                if (setter.equals(methods[i].getName()) && paramT.length == 1
+                        && "java.lang.String".equals(paramT[0].getName())) {
+
+                    methods[i].invoke(o, new Object[] { value });
+                    return true;
+                }
+            }
+
+            // Try a setFoo ( int ) or ( boolean )
+            for (int i = 0; i < methods.length; i++) {
+                boolean ok = true;
+                if (setter.equals(methods[i].getName())
+                        && methods[i].getParameterTypes().length == 1) {
+
+                    // match - find the type and invoke it
+                    Class<?> paramType = methods[i].getParameterTypes()[0];
+                    Object params[] = new Object[1];
+
+                    // Try a setFoo ( int )
+                    if ("java.lang.Integer".equals(paramType.getName())
+                            || "int".equals(paramType.getName())) {
+                        try {
+                            params[0] = new Integer(value);
+                        } catch (NumberFormatException ex) {
+                            ok = false;
+                        }
+                    // Try a setFoo ( long )
+                    }else if ("java.lang.Long".equals(paramType.getName())
+                                || "long".equals(paramType.getName())) {
+                            try {
+                                params[0] = new Long(value);
+                            } catch (NumberFormatException ex) {
+                                ok = false;
+                            }
+
+                        // Try a setFoo ( boolean )
+                    } else if ("java.lang.Boolean".equals(paramType.getName())
+                            || "boolean".equals(paramType.getName())) {
+                        params[0] = Boolean.valueOf(value);
+
+                        // Try a setFoo ( InetAddress )
+                    } else if ("java.net.InetAddress".equals(paramType
+                            .getName())) {
+                        try {
+                            params[0] = InetAddress.getByName(value);
+                        } catch (UnknownHostException exc) {
+                            if (log.isDebugEnabled())
+                                log.debug("IntrospectionUtils: Unable to resolve host name:" + value);
+                            ok = false;
+                        }
+
+                        // Unknown type
+                    } else {
+                        if (log.isDebugEnabled())
+                            log.debug("IntrospectionUtils: Unknown type " +
+                                    paramType.getName());
+                    }
+
+                    if (ok) {
+                        methods[i].invoke(o, params);
+                        return true;
+                    }
+                }
+
+                // save "setProperty" for later
+                if ("setProperty".equals(methods[i].getName())) {
+                    if (methods[i].getReturnType()==Boolean.TYPE){
+                        setPropertyMethodBool = methods[i];
+                    }else {
+                        setPropertyMethodVoid = methods[i];
+                    }
+
+                }
+            }
+
+            // Ok, no setXXX found, try a setProperty("name", "value")
+            if (setPropertyMethodBool != null || setPropertyMethodVoid != null) {
+                Object params[] = new Object[2];
+                params[0] = name;
+                params[1] = value;
+                if (setPropertyMethodBool != null) {
+                    try {
+                        return ((Boolean) setPropertyMethodBool.invoke(o, params)).booleanValue();
+                    }catch (IllegalArgumentException biae) {
+                        //the boolean method had the wrong
+                        //parameter types. lets try the other
+                        if (setPropertyMethodVoid!=null) {
+                            setPropertyMethodVoid.invoke(o, params);
+                            return true;
+                        }else {
+                            throw biae;
+                        }
+                    }
+                } else {
+                    setPropertyMethodVoid.invoke(o, params);
+                    return true;
+                }
+            }
+
+        } catch (IllegalArgumentException ex2) {
+            log.warn("IAE " + o + " " + name + " " + value, ex2);
+        } catch (SecurityException ex1) {
+            if (log.isDebugEnabled())
+                log.debug("IntrospectionUtils: SecurityException for " +
+                        o.getClass() + " " + name + "=" + value + ")", ex1);
+        } catch (IllegalAccessException iae) {
+            if (log.isDebugEnabled())
+                log.debug("IntrospectionUtils: IllegalAccessException for " +
+                        o.getClass() + " " + name + "=" + value + ")", iae);
+        } catch (InvocationTargetException ie) {
+            Throwable cause = ie.getCause();
+            if (cause instanceof ThreadDeath) {
+                throw (ThreadDeath) cause;
+            }
+            if (cause instanceof VirtualMachineError) {
+                throw (VirtualMachineError) cause;
+            }
+            if (log.isDebugEnabled())
+                log.debug("IntrospectionUtils: InvocationTargetException for " +
+                        o.getClass() + " " + name + "=" + value + ")", ie);
+        }
+        return false;
+    }
+
+    public static String capitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toUpperCase(chars[0]);
+        return new String(chars);
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java
new file mode 100644 (file)
index 0000000..23b5668
--- /dev/null
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+public class ClassLoaderUtil {
+    private static final Log log = LogFactory.getLog(ClassLoaderUtil.class);
+
+    private static final boolean onlyAttemptFirstLoader =
+        Boolean.parseBoolean(System.getProperty("org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader", "false"));
+
+    public static Class<?> loadClass(String className, ClassLoader... classLoaders) throws ClassNotFoundException {
+        ClassNotFoundException last = null;
+        StringBuilder errorMsg = null;
+        for (ClassLoader cl : classLoaders) {
+            try {
+                if (cl!=null) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Attempting to load class["+className+"] from "+cl);
+                    }
+                    return Class.forName(className, true, cl);
+                } else {
+                    throw new ClassNotFoundException("Classloader is null");
+                }
+            } catch (ClassNotFoundException x) {
+                last = x;
+                if (errorMsg==null) {
+                    errorMsg = new StringBuilder();
+                } else {
+                    errorMsg.append(';');
+                }
+                errorMsg.append("ClassLoader:");
+                errorMsg.append(cl);
+            }
+            if (onlyAttemptFirstLoader) {
+                break;
+            }
+        }
+        throw new ClassNotFoundException("Unable to load class: "+className+" from "+errorMsg, last);
+    }
+
+
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
new file mode 100644 (file)
index 0000000..7b081df
--- /dev/null
@@ -0,0 +1,1500 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Implementation of simple connection pool.
+ * The ConnectionPool uses a {@link PoolProperties} object for storing all the meta information about the connection pool.
+ * As the underlying implementation, the connection pool uses {@link java.util.concurrent.BlockingQueue} to store active and idle connections.
+ * A custom implementation of a fair {@link FairBlockingQueue} blocking queue is provided with the connection pool itself.
+ * @version 1.0
+ */
+public class ConnectionPool {
+
+    /**
+     * Default domain for objects registering with an mbean server
+     */
+    public static final String POOL_JMX_DOMAIN = "tomcat.jdbc";
+    /**
+     * Prefix type for JMX registration
+     */
+    public static final String POOL_JMX_TYPE_PREFIX = POOL_JMX_DOMAIN+":type=";
+
+    /**
+     * Logger
+     */
+    private static final Log log = LogFactory.getLog(ConnectionPool.class);
+
+    //===============================================================================
+    //         INSTANCE/QUICK ACCESS VARIABLE
+    //===============================================================================
+    /**
+     * Carries the size of the pool, instead of relying on a queue implementation
+     * that usually iterates over to get an exact count
+     */
+    private AtomicInteger size = new AtomicInteger(0);
+
+    /**
+     * All the information about the connection pool
+     * These are the properties the pool got instantiated with
+     */
+    private PoolConfiguration poolProperties;
+
+    /**
+     * Contains all the connections that are in use
+     * TODO - this shouldn't be a blocking queue, simply a list to hold our objects
+     */
+    private BlockingQueue<PooledConnection> busy;
+
+    /**
+     * Contains all the idle connections
+     */
+    private BlockingQueue<PooledConnection> idle;
+
+    /**
+     * The thread that is responsible for checking abandoned and idle threads
+     */
+    private volatile PoolCleaner poolCleaner;
+
+    /**
+     * Pool closed flag
+     */
+    private volatile boolean closed = false;
+
+    /**
+     * Since newProxyInstance performs the same operation, over and over
+     * again, it is much more optimized if we simply store the constructor ourselves.
+     */
+    private Constructor<?> proxyClassConstructor;
+
+    /**
+     * Executor service used to cancel Futures
+     */
+    private ThreadPoolExecutor cancellator = new ThreadPoolExecutor(0,1,1000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
+
+    /**
+     * reference to the JMX mbean
+     */
+    protected org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = null;
+
+    /**
+     * counter to track how many threads are waiting for a connection
+     */
+    private AtomicInteger waitcount = new AtomicInteger(0);
+
+    private AtomicLong poolVersion = new AtomicLong(Long.MIN_VALUE);
+
+    /**
+     * The counters for statistics of the pool.
+     */
+    private final AtomicLong borrowedCount = new AtomicLong(0);
+    private final AtomicLong returnedCount = new AtomicLong(0);
+    private final AtomicLong createdCount = new AtomicLong(0);
+    private final AtomicLong releasedCount = new AtomicLong(0);
+    private final AtomicLong reconnectedCount = new AtomicLong(0);
+    private final AtomicLong removeAbandonedCount = new AtomicLong(0);
+    private final AtomicLong releasedIdleCount = new AtomicLong(0);
+
+    //===============================================================================
+    //         PUBLIC METHODS
+    //===============================================================================
+
+    /**
+     * Instantiate a connection pool. This will create connections if initialSize is larger than 0.
+     * The {@link PoolProperties} should not be reused for another connection pool.
+     * @param prop PoolProperties - all the properties for this connection pool
+     * @throws SQLException Pool initialization error
+     */
+    public ConnectionPool(PoolConfiguration prop) throws SQLException {
+        //setup quick access variables and pools
+        init(prop);
+    }
+
+
+    /**
+     * Retrieves a Connection future. If a connection is not available, one can block using future.get()
+     * until a connection has become available.
+     * If a connection is not retrieved, the Future must be cancelled in order for the connection to be returned
+     * to the pool.
+     * @return a Future containing a reference to the connection or the future connection
+     * @throws SQLException Cannot use asynchronous connect
+     */
+    public Future<Connection> getConnectionAsync() throws SQLException {
+        try {
+            PooledConnection pc = borrowConnection(0, null, null);
+            if (pc!=null) {
+                return new ConnectionFuture(pc);
+            }
+        }catch (SQLException x) {
+            if (x.getMessage().indexOf("NoWait")<0) {
+                throw x;
+            }
+        }
+        //we can only retrieve a future if the underlying queue supports it.
+        if (idle instanceof FairBlockingQueue<?>) {
+            Future<PooledConnection> pcf = ((FairBlockingQueue<PooledConnection>)idle).pollAsync();
+            return new ConnectionFuture(pcf);
+        } else if (idle instanceof MultiLockFairBlockingQueue<?>) {
+                Future<PooledConnection> pcf = ((MultiLockFairBlockingQueue<PooledConnection>)idle).pollAsync();
+                return new ConnectionFuture(pcf);
+        } else {
+            throw new SQLException("Connection pool is misconfigured, doesn't support async retrieval. Set the 'fair' property to 'true'");
+        }
+    }
+
+    /**
+     * Borrows a connection from the pool. If a connection is available (in the idle queue) or the pool has not reached
+     * {@link PoolProperties#maxActive maxActive} connections a connection is returned immediately.
+     * If no connection is available, the pool will attempt to fetch a connection for {@link PoolProperties#maxWait maxWait} milliseconds.
+     * @return Connection - a java.sql.Connection/javax.sql.PooledConnection reflection proxy, wrapping the underlying object.
+     * @throws SQLException - if the wait times out or a failure occurs creating a connection
+     */
+    public Connection getConnection() throws SQLException {
+        //check out a connection
+        PooledConnection con = borrowConnection(-1,null,null);
+        return setupConnection(con);
+    }
+
+
+    /**
+     * Borrows a connection from the pool. If a connection is available (in the
+     * idle queue) or the pool has not reached {@link PoolProperties#maxActive
+     * maxActive} connections a connection is returned immediately. If no
+     * connection is available, the pool will attempt to fetch a connection for
+     * {@link PoolProperties#maxWait maxWait} milliseconds.
+     * @param username The user name to use for the connection
+     * @param password The password for the connection
+     * @return Connection - a java.sql.Connection/javax.sql.PooledConnection
+     *         reflection proxy, wrapping the underlying object.
+     * @throws SQLException
+     *             - if the wait times out or a failure occurs creating a
+     *             connection
+     */
+    public Connection getConnection(String username, String password) throws SQLException {
+        // check out a connection
+        PooledConnection con = borrowConnection(-1, username, password);
+        return setupConnection(con);
+    }
+
+    /**
+     * Returns the name of this pool
+     * @return String - the name of the pool
+     */
+    public String getName() {
+        return getPoolProperties().getPoolName();
+    }
+
+    /**
+     * Return the number of threads waiting for a connection
+     * @return number of threads waiting for a connection
+     */
+    public int getWaitCount() {
+        return waitcount.get();
+    }
+
+    /**
+     * Returns the pool properties associated with this connection pool
+     * @return PoolProperties
+     *
+     */
+    public PoolConfiguration getPoolProperties() {
+        return this.poolProperties;
+    }
+
+    /**
+     * Returns the total size of this pool, this includes both busy and idle connections
+     * @return int - number of established connections to the database
+     */
+    public int getSize() {
+        return size.get();
+    }
+
+    /**
+     * Returns the number of connections that are in use
+     * @return int - number of established connections that are being used by the application
+     */
+    public int getActive() {
+        return busy.size();
+    }
+
+    /**
+     * Returns the number of idle connections
+     * @return int - number of established connections not being used
+     */
+    public int getIdle() {
+        return idle.size();
+    }
+
+    /**
+     * Returns true if {@link #close close} has been called, and the connection pool is unusable
+     * @return boolean
+     */
+    public  boolean isClosed() {
+        return this.closed;
+    }
+
+    //===============================================================================
+    //         PROTECTED METHODS
+    //===============================================================================
+
+
+    /**
+     * configures a pooled connection as a proxy.
+     * This Proxy implements {@link java.sql.Connection} and {@link javax.sql.PooledConnection} interfaces.
+     * All calls on {@link java.sql.Connection} methods will be propagated down to the actual JDBC connection except for the
+     * {@link java.sql.Connection#close()} method.
+     * @param con a {@link PooledConnection} to wrap in a Proxy
+     * @return a {@link java.sql.Connection} object wrapping a pooled connection.
+     * @throws SQLException if an interceptor can't be configured, if the proxy can't be instantiated
+     */
+    protected Connection setupConnection(PooledConnection con) throws SQLException {
+        //fetch previously cached interceptor proxy - one per connection
+        JdbcInterceptor handler = con.getHandler();
+        if (handler==null) {
+            //build the proxy handler
+            handler = new ProxyConnection(this,con,getPoolProperties().isUseEquals());
+            //set up the interceptor chain
+            PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
+            for (int i=proxies.length-1; i>=0; i--) {
+                try {
+                    //create a new instance
+                    JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
+                    //configure properties
+                    interceptor.setProperties(proxies[i].getProperties());
+                    //setup the chain
+                    interceptor.setNext(handler);
+                    //call reset
+                    interceptor.reset(this, con);
+                    //configure the last one to be held by the connection
+                    handler = interceptor;
+                }catch(Exception x) {
+                    SQLException sx = new SQLException("Unable to instantiate interceptor chain.");
+                    sx.initCause(x);
+                    throw sx;
+                }
+            }
+            //cache handler for the next iteration
+            con.setHandler(handler);
+        } else {
+            JdbcInterceptor next = handler;
+            //we have a cached handler, reset it
+            while (next!=null) {
+                next.reset(this, con);
+                next = next.getNext();
+            }
+        }
+
+        try {
+            getProxyConstructor(con.getXAConnection() != null);
+            //create the proxy
+            //TODO possible optimization, keep track if this connection was returned properly, and don't generate a new facade
+            Connection connection = null;
+            if (getPoolProperties().getUseDisposableConnectionFacade() ) {
+                connection = (Connection)proxyClassConstructor.newInstance(new Object[] { new DisposableConnectionFacade(handler) });
+            } else {
+                connection = (Connection)proxyClassConstructor.newInstance(new Object[] {handler});
+            }
+            //return the connection
+            return connection;
+        }catch (Exception x) {
+            SQLException s = new SQLException();
+            s.initCause(x);
+            throw s;
+        }
+
+    }
+
+    /**
+     * Creates and caches a {@link java.lang.reflect.Constructor} used to instantiate the proxy object.
+     * We cache this, since the creation of a constructor is fairly slow.
+     * @param xa Use a XA connection
+     * @return constructor used to instantiate the wrapper object
+     * @throws NoSuchMethodException Failed to get a constructor
+     */
+    public Constructor<?> getProxyConstructor(boolean xa) throws NoSuchMethodException {
+        //cache the constructor
+        if (proxyClassConstructor == null ) {
+            Class<?> proxyClass = xa ?
+                Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class, javax.sql.XAConnection.class}) :
+                Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class});
+            proxyClassConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+        }
+        return proxyClassConstructor;
+    }
+
+    /**
+     * Closes the pool and all disconnects all idle connections
+     * Active connections will be closed upon the {@link java.sql.Connection#close close} method is called
+     * on the underlying connection instead of being returned to the pool
+     * @param force - true to even close the active connections
+     */
+    protected void close(boolean force) {
+        //are we already closed
+        if (this.closed) return;
+        //prevent other threads from entering
+        this.closed = true;
+        //stop background thread
+        if (poolCleaner!=null) {
+            poolCleaner.stopRunning();
+        }
+
+        /* release all idle connections */
+        BlockingQueue<PooledConnection> pool = (idle.size()>0)?idle:(force?busy:idle);
+        while (pool.size()>0) {
+            try {
+                //retrieve the next connection
+                PooledConnection con = pool.poll(1000, TimeUnit.MILLISECONDS);
+                //close it and retrieve the next one, if one is available
+                while (con != null) {
+                    //close the connection
+                    if (pool==idle)
+                        release(con);
+                    else
+                        abandon(con);
+                    if (pool.size()>0) {
+                        con = pool.poll(1000, TimeUnit.MILLISECONDS);
+                    } else {
+                        break;
+                    }
+                } //while
+            } catch (InterruptedException ex) {
+                if (getPoolProperties().getPropagateInterruptState()) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+            if (pool.size()==0 && force && pool!=busy) pool = busy;
+        }
+        if (this.getPoolProperties().isJmxEnabled()) this.jmxPool = null;
+        PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
+        for (int i=0; i<proxies.length; i++) {
+            try {
+                JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
+                interceptor.setProperties(proxies[i].getProperties());
+                interceptor.poolClosed(this);
+            }catch (Exception x) {
+                log.debug("Unable to inform interceptor of pool closure.",x);
+            }
+        }
+    } //closePool
+
+
+    /**
+     * Initialize the connection pool - called from the constructor
+     * @param properties PoolProperties - properties used to initialize the pool with
+     * @throws SQLException if initialization fails
+     */
+    protected void init(PoolConfiguration properties) throws SQLException {
+        poolProperties = properties;
+
+        //make sure the pool is properly configured
+        checkPoolConfiguration(properties);
+
+        //make space for 10 extra in case we flow over a bit
+        busy = new LinkedBlockingQueue<>();
+        //busy = new FairBlockingQueue<PooledConnection>();
+        //make space for 10 extra in case we flow over a bit
+        if (properties.isFairQueue()) {
+            idle = new FairBlockingQueue<>();
+            //idle = new MultiLockFairBlockingQueue<PooledConnection>();
+            //idle = new LinkedTransferQueue<PooledConnection>();
+            //idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);
+        } else {
+            idle = new LinkedBlockingQueue<>();
+        }
+
+        initializePoolCleaner(properties);
+
+        //create JMX MBean
+        if (this.getPoolProperties().isJmxEnabled()) createMBean();
+
+        //Parse and create an initial set of interceptors. Letting them know the pool has started.
+        //These interceptors will not get any connection.
+        PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
+        for (int i=0; i<proxies.length; i++) {
+            try {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating interceptor instance of class:"+proxies[i].getInterceptorClass());
+                }
+                JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
+                interceptor.setProperties(proxies[i].getProperties());
+                interceptor.poolStarted(this);
+            }catch (Exception x) {
+                log.error("Unable to inform interceptor of pool start.",x);
+                if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
+                close(true);
+                SQLException ex = new SQLException();
+                ex.initCause(x);
+                throw ex;
+            }
+        }
+
+        //initialize the pool with its initial set of members
+        PooledConnection[] initialPool = new PooledConnection[poolProperties.getInitialSize()];
+        try {
+            for (int i = 0; i < initialPool.length; i++) {
+                initialPool[i] = this.borrowConnection(0, null, null); //don't wait, should be no contention
+            } //for
+
+        } catch (SQLException x) {
+            log.error("Unable to create initial connections of pool.", x);
+            if (!poolProperties.isIgnoreExceptionOnPreLoad()) {
+                if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
+                close(true);
+                throw x;
+            }
+        } finally {
+            //return the members as idle to the pool
+            for (int i = 0; i < initialPool.length; i++) {
+                if (initialPool[i] != null) {
+                    try {this.returnConnection(initialPool[i]);}catch(Exception x){/*NOOP*/}
+                } //end if
+            } //for
+        } //catch
+
+        closed = false;
+    }
+
+    public void checkPoolConfiguration(PoolConfiguration properties) {
+        //make sure the pool is properly configured
+        if (properties.getMaxActive()<1) {
+            log.warn("maxActive is smaller than 1, setting maxActive to: "+PoolProperties.DEFAULT_MAX_ACTIVE);
+            properties.setMaxActive(PoolProperties.DEFAULT_MAX_ACTIVE);
+        }
+        if (properties.getMaxActive()<properties.getInitialSize()) {
+            log.warn("initialSize is larger than maxActive, setting initialSize to: "+properties.getMaxActive());
+            properties.setInitialSize(properties.getMaxActive());
+        }
+        if (properties.getMinIdle()>properties.getMaxActive()) {
+            log.warn("minIdle is larger than maxActive, setting minIdle to: "+properties.getMaxActive());
+            properties.setMinIdle(properties.getMaxActive());
+        }
+        if (properties.getMaxIdle()>properties.getMaxActive()) {
+            log.warn("maxIdle is larger than maxActive, setting maxIdle to: "+properties.getMaxActive());
+            properties.setMaxIdle(properties.getMaxActive());
+        }
+        if (properties.getMaxIdle()<properties.getMinIdle()) {
+            log.warn("maxIdle is smaller than minIdle, setting maxIdle to: "+properties.getMinIdle());
+            properties.setMaxIdle(properties.getMinIdle());
+        }
+    }
+
+    public void initializePoolCleaner(PoolConfiguration properties) {
+        //if the evictor thread is supposed to run, start it now
+        if (properties.isPoolSweeperEnabled()) {
+            poolCleaner = new PoolCleaner(this, properties.getTimeBetweenEvictionRunsMillis());
+            poolCleaner.start();
+        } //end if
+    }
+
+    public void terminatePoolCleaner() {
+        if (poolCleaner!= null) {
+            poolCleaner.stopRunning();
+            poolCleaner = null;
+        }
+    }
+
+
+//===============================================================================
+//         CONNECTION POOLING IMPL LOGIC
+//===============================================================================
+
+    /**
+     * thread safe way to abandon a connection
+     * signals a connection to be abandoned.
+     * this will disconnect the connection, and log the stack trace if logAbandoned=true
+     * @param con PooledConnection
+     */
+    protected void abandon(PooledConnection con) {
+        if (con == null)
+            return;
+        try {
+            con.lock();
+            String trace = con.getStackTrace();
+            if (getPoolProperties().isLogAbandoned()) {
+                log.warn("Connection has been abandoned " + con + ":" + trace);
+            }
+            if (jmxPool!=null) {
+                jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_ABANDON, trace);
+            }
+            //release the connection
+            removeAbandonedCount.incrementAndGet();
+            release(con);
+        } finally {
+            con.unlock();
+        }
+    }
+
+    /**
+     * Thread safe way to suspect a connection. Similar to
+     * {@link #abandon(PooledConnection)}, but instead of actually abandoning
+     * the connection, this will log a warning and set the suspect flag on the
+     * {@link PooledConnection} if logAbandoned=true
+     *
+     * @param con PooledConnection
+     */
+    protected void suspect(PooledConnection con) {
+        if (con == null)
+            return;
+        if (con.isSuspect())
+            return;
+        try {
+            con.lock();
+            String trace = con.getStackTrace();
+            if (getPoolProperties().isLogAbandoned()) {
+                log.warn("Connection has been marked suspect, possibly abandoned " + con + "["+(System.currentTimeMillis()-con.getTimestamp())+" ms.]:" + trace);
+            }
+            if (jmxPool!=null) {
+                jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.SUSPECT_ABANDONED_NOTIFICATION, trace);
+            }
+            con.setSuspect(true);
+        } finally {
+            con.unlock();
+        }
+    }
+
+    /**
+     * thread safe way to release a connection
+     * @param con PooledConnection
+     */
+    protected void release(PooledConnection con) {
+        if (con == null)
+            return;
+        try {
+            con.lock();
+            if (con.release()) {
+                //counter only decremented once
+                size.addAndGet(-1);
+                con.setHandler(null);
+            }
+            releasedCount.incrementAndGet();
+        } finally {
+            con.unlock();
+        }
+        // we've asynchronously reduced the number of connections
+        // we could have threads stuck in idle.poll(timeout) that will never be
+        // notified
+        if (waitcount.get() > 0) {
+            idle.offer(create(true));
+        }
+    }
+
+    /**
+     * Thread safe way to retrieve a connection from the pool
+     * @param wait - time to wait, overrides the maxWait from the properties,
+     * set to -1 if you wish to use maxWait, 0 if you wish no wait time.
+     * @param username The user name to use for the connection
+     * @param password The password for the connection
+     * @return a connection
+     * @throws SQLException Failed to get a connection
+     */
+    private PooledConnection borrowConnection(int wait, String username, String password) throws SQLException {
+
+        if (isClosed()) {
+            throw new SQLException("Connection pool closed.");
+        } //end if
+
+        //get the current time stamp
+        long now = System.currentTimeMillis();
+        //see if there is one available immediately
+        PooledConnection con = idle.poll();
+
+        while (true) {
+            if (con!=null) {
+                //configure the connection and return it
+                PooledConnection result = borrowConnection(now, con, username, password);
+                borrowedCount.incrementAndGet();
+                if (result!=null) return result;
+            }
+
+            //if we get here, see if we need to create one
+            //this is not 100% accurate since it doesn't use a shared
+            //atomic variable - a connection can become idle while we are creating
+            //a new connection
+            if (size.get() < getPoolProperties().getMaxActive()) {
+                //atomic duplicate check
+                if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
+                    //if we got here, two threads passed through the first if
+                    size.decrementAndGet();
+                } else {
+                    //create a connection, we're below the limit
+                    return createConnection(now, con, username, password);
+                }
+            } //end if
+
+            //calculate wait time for this iteration
+            long maxWait = wait;
+            //if the passed in wait time is -1, means we should use the pool property value
+            if (wait==-1) {
+                maxWait = (getPoolProperties().getMaxWait()<=0)?Long.MAX_VALUE:getPoolProperties().getMaxWait();
+            }
+
+            long timetowait = Math.max(0, maxWait - (System.currentTimeMillis() - now));
+            waitcount.incrementAndGet();
+            try {
+                //retrieve an existing connection
+                con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException ex) {
+                if (getPoolProperties().getPropagateInterruptState()) {
+                    Thread.currentThread().interrupt();
+                }
+                SQLException sx = new SQLException("Pool wait interrupted.");
+                sx.initCause(ex);
+                throw sx;
+            } finally {
+                waitcount.decrementAndGet();
+            }
+            if (maxWait==0 && con == null) { //no wait, return one if we have one
+                if (jmxPool!=null) {
+                    jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.POOL_EMPTY, "Pool empty - no wait.");
+                }
+                throw new PoolExhaustedException("[" + Thread.currentThread().getName()+"] " +
+                        "NoWait: Pool empty. Unable to fetch a connection, none available["+busy.size()+" in use].");
+            }
+            //we didn't get a connection, lets see if we timed out
+            if (con == null) {
+                if ((System.currentTimeMillis() - now) >= maxWait) {
+                    if (jmxPool!=null) {
+                        jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.POOL_EMPTY, "Pool empty - timeout.");
+                    }
+                    throw new PoolExhaustedException("[" + Thread.currentThread().getName()+"] " +
+                        "Timeout: Pool empty. Unable to fetch a connection in " + (maxWait / 1000) +
+                        " seconds, none available[size:"+size.get() +"; busy:"+busy.size()+"; idle:"+idle.size()+"; lastwait:"+timetowait+"].");
+                } else {
+                    //no timeout, lets try again
+                    continue;
+                }
+            }
+        } //while
+    }
+
+    /**
+     * Creates a JDBC connection and tries to connect to the database.
+     * @param now timestamp of when this was called
+     * @param notUsed Argument not used
+     * @param username The user name to use for the connection
+     * @param password The password for the connection
+     * @return a PooledConnection that has been connected
+     * @throws SQLException Failed to get a connection
+     */
+    protected PooledConnection createConnection(long now, PooledConnection notUsed, String username, String password) throws SQLException {
+        //no connections where available we'll create one
+        PooledConnection con = create(false);
+        if (username!=null) con.getAttributes().put(PooledConnection.PROP_USER, username);
+        if (password!=null) con.getAttributes().put(PooledConnection.PROP_PASSWORD, password);
+        boolean error = false;
+        try {
+            //connect and validate the connection
+            con.lock();
+            con.connect();
+            if (con.validate(PooledConnection.VALIDATE_INIT)) {
+                //no need to lock a new one, its not contented
+                con.setTimestamp(now);
+                if (getPoolProperties().isLogAbandoned()) {
+                    con.setStackTrace(getThreadDump());
+                }
+                if (!busy.offer(con)) {
+                    log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
+                }
+                createdCount.incrementAndGet();
+                return con;
+            } else {
+                //validation failed, make sure we disconnect
+                //and clean up
+                throw new SQLException("Validation Query Failed, enable logValidationErrors for more details.");
+            } //end if
+        } catch (Exception e) {
+            error = true;
+            if (log.isDebugEnabled())
+                log.debug("Unable to create a new JDBC connection.", e);
+            if (e instanceof SQLException) {
+                throw (SQLException)e;
+            } else {
+                SQLException ex = new SQLException(e.getMessage());
+                ex.initCause(e);
+                throw ex;
+            }
+        } finally {
+            // con can never be null here
+            if (error ) {
+                release(con);
+            }
+            con.unlock();
+        }//catch
+    }
+
+    /**
+     * Validates and configures a previously idle connection
+     * @param now - timestamp
+     * @param con - the connection to validate and configure
+     * @param username The user name to use for the connection
+     * @param password The password for the connection
+     * @return a connection
+     * @throws SQLException if a validation error happens
+     */
+    protected PooledConnection borrowConnection(long now, PooledConnection con, String username, String password) throws SQLException {
+        //we have a connection, lets set it up
+
+        //flag to see if we need to nullify
+        boolean setToNull = false;
+        try {
+            con.lock();
+            if (con.isReleased()) {
+                return null;
+            }
+
+            //evaluate username/password change as well as max age functionality
+            boolean forceReconnect = con.shouldForceReconnect(username, password) || con.isMaxAgeExpired();
+
+            if (!con.isDiscarded() && !con.isInitialized()) {
+                //here it states that the connection not discarded, but the connection is null
+                //don't attempt a connect here. It will be done during the reconnect.
+                forceReconnect = true;
+            }
+
+            if (!forceReconnect) {
+                if ((!con.isDiscarded()) && con.validate(PooledConnection.VALIDATE_BORROW)) {
+                    //set the timestamp
+                    con.setTimestamp(now);
+                    if (getPoolProperties().isLogAbandoned()) {
+                        //set the stack trace for this pool
+                        con.setStackTrace(getThreadDump());
+                    }
+                    if (!busy.offer(con)) {
+                        log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
+                    }
+                    return con;
+                }
+            }
+            //if we reached here, that means the connection
+            //is either has another principal, is discarded or validation failed.
+            //we will make one more attempt
+            //in order to guarantee that the thread that just acquired
+            //the connection shouldn't have to poll again.
+            try {
+                con.reconnect();
+                reconnectedCount.incrementAndGet();
+                int validationMode = getPoolProperties().isTestOnConnect() || getPoolProperties().getInitSQL()!=null ?
+                    PooledConnection.VALIDATE_INIT :
+                    PooledConnection.VALIDATE_BORROW;
+
+                if (con.validate(validationMode)) {
+                    //set the timestamp
+                    con.setTimestamp(now);
+                    if (getPoolProperties().isLogAbandoned()) {
+                        //set the stack trace for this pool
+                        con.setStackTrace(getThreadDump());
+                    }
+                    if (!busy.offer(con)) {
+                        log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
+                    }
+                    return con;
+                } else {
+                    //validation failed.
+                    throw new SQLException("Failed to validate a newly established connection.");
+                }
+            } catch (Exception x) {
+                release(con);
+                setToNull = true;
+                if (x instanceof SQLException) {
+                    throw (SQLException)x;
+                } else {
+                    SQLException ex  = new SQLException(x.getMessage());
+                    ex.initCause(x);
+                    throw ex;
+                }
+            }
+        } finally {
+            con.unlock();
+            if (setToNull) {
+                con = null;
+            }
+        }
+    }
+    /**
+     * Terminate the current transaction for the given connection.
+     * @param con The connection
+     * @return <code>true</code> if the connection TX termination succeeded
+     *         otherwise <code>false</code>
+     */
+    protected boolean terminateTransaction(PooledConnection con) {
+        try {
+            if (Boolean.FALSE.equals(con.getPoolProperties().getDefaultAutoCommit())) {
+                if (this.getPoolProperties().getRollbackOnReturn()) {
+                    boolean autocommit = con.getConnection().getAutoCommit();
+                    if (!autocommit) con.getConnection().rollback();
+                } else if (this.getPoolProperties().getCommitOnReturn()) {
+                    boolean autocommit = con.getConnection().getAutoCommit();
+                    if (!autocommit) con.getConnection().commit();
+                }
+            }
+            return true;
+        } catch (SQLException x) {
+            log.warn("Unable to terminate transaction, connection will be closed.",x);
+            return false;
+        }
+
+    }
+
+    /**
+     * Determines if a connection should be closed upon return to the pool.
+     * @param con - the connection
+     * @param action - the validation action that should be performed
+     * @return <code>true</code> if the connection should be closed
+     */
+    protected boolean shouldClose(PooledConnection con, int action) {
+        if (con.getConnectionVersion() < getPoolVersion()) return true;
+        if (con.isDiscarded()) return true;
+        if (isClosed()) return true;
+        if (!con.validate(action)) return true;
+        if (!terminateTransaction(con)) return true;
+        if (con.isMaxAgeExpired()) return true;
+        else return false;
+    }
+
+    /**
+     * Returns a connection to the pool
+     * If the pool is closed, the connection will be released
+     * If the connection is not part of the busy queue, it will be released.
+     * If {@link PoolProperties#testOnReturn} is set to true it will be validated
+     * @param con PooledConnection to be returned to the pool
+     */
+    protected void returnConnection(PooledConnection con) {
+        if (isClosed()) {
+            //if the connection pool is closed
+            //close the connection instead of returning it
+            release(con);
+            return;
+        } //end if
+
+        if (con != null) {
+            try {
+                returnedCount.incrementAndGet();
+                con.lock();
+                if (con.isSuspect()) {
+                    if (poolProperties.isLogAbandoned() && log.isInfoEnabled()) {
+                        log.info("Connection(" + con + ") that has been marked suspect was returned."
+                                + " The processing time is " + (System.currentTimeMillis()-con.getTimestamp()) + " ms.");
+                    }
+                    if (jmxPool!=null) {
+                        jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.SUSPECT_RETURNED_NOTIFICATION,
+                                "Connection(" + con + ") that has been marked suspect was returned.");
+                    }
+                }
+                if (busy.remove(con)) {
+
+                    if (!shouldClose(con,PooledConnection.VALIDATE_RETURN)) {
+                        con.setStackTrace(null);
+                        con.setTimestamp(System.currentTimeMillis());
+                        if (((idle.size()>=poolProperties.getMaxIdle()) && !poolProperties.isPoolSweeperEnabled()) || (!idle.offer(con))) {
+                            if (log.isDebugEnabled()) {
+                                log.debug("Connection ["+con+"] will be closed and not returned to the pool, idle["+idle.size()+"]>=maxIdle["+poolProperties.getMaxIdle()+"] idle.offer failed.");
+                            }
+                            release(con);
+                        }
+                    } else {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Connection ["+con+"] will be closed and not returned to the pool.");
+                        }
+                        release(con);
+                    } //end if
+                } else {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Connection ["+con+"] will be closed and not returned to the pool, busy.remove failed.");
+                    }
+                    release(con);
+                }
+            } finally {
+                con.unlock();
+            }
+        } //end if
+    } //checkIn
+
+    /**
+     * Determines if a connection should be abandoned based on
+     * {@link PoolProperties#abandonWhenPercentageFull} setting.
+     * @return <code>true</code> if the connection should be abandoned
+     */
+    protected boolean shouldAbandon() {
+        if (!poolProperties.isRemoveAbandoned()) return false;
+        if (poolProperties.getAbandonWhenPercentageFull()==0) return true;
+        float used = busy.size();
+        float max  = poolProperties.getMaxActive();
+        float perc = poolProperties.getAbandonWhenPercentageFull();
+        return (used/max*100f)>=perc;
+    }
+
+    /**
+     * Iterates through all the busy connections and checks for connections that have timed out
+     */
+    public void checkAbandoned() {
+        try {
+            if (busy.size()==0) return;
+            Iterator<PooledConnection> locked = busy.iterator();
+            int sto = getPoolProperties().getSuspectTimeout();
+            while (locked.hasNext()) {
+                PooledConnection con = locked.next();
+                boolean setToNull = false;
+                try {
+                    con.lock();
+                    //the con has been returned to the pool or released
+                    //ignore it
+                    if (idle.contains(con) || con.isReleased())
+                        continue;
+                    long time = con.getTimestamp();
+                    long now = System.currentTimeMillis();
+                    if (shouldAbandon() && (now - time) > con.getAbandonTimeout()) {
+                        busy.remove(con);
+                        abandon(con);
+                        setToNull = true;
+                    } else if (sto > 0 && (now - time) > (sto * 1000L)) {
+                        suspect(con);
+                    } else {
+                        //do nothing
+                    } //end if
+                } finally {
+                    con.unlock();
+                    if (setToNull)
+                        con = null;
+                }
+            } //while
+        } catch (ConcurrentModificationException e) {
+            log.debug("checkAbandoned failed." ,e);
+        } catch (Exception e) {
+            log.warn("checkAbandoned failed, it will be retried.",e);
+        }
+    }
+
+    /**
+     * Iterates through the idle connections and resizes the idle pool based on parameters
+     * {@link PoolProperties#maxIdle}, {@link PoolProperties#minIdle}, {@link PoolProperties#minEvictableIdleTimeMillis}
+     */
+    public void checkIdle() {
+        checkIdle(false);
+    }
+
+    public void checkIdle(boolean ignoreMinSize) {
+
+        try {
+            if (idle.size()==0) return;
+            long now = System.currentTimeMillis();
+            Iterator<PooledConnection> unlocked = idle.iterator();
+            while ( (ignoreMinSize || (idle.size()>=getPoolProperties().getMinIdle())) && unlocked.hasNext()) {
+                PooledConnection con = unlocked.next();
+                boolean setToNull = false;
+                try {
+                    con.lock();
+                    //the con been taken out, we can't clean it up
+                    if (busy.contains(con))
+                        continue;
+                    long time = con.getTimestamp();
+                    if (shouldReleaseIdle(now, con, time)) {
+                        releasedIdleCount.incrementAndGet();
+                        release(con);
+                        idle.remove(con);
+                        setToNull = true;
+                    } else {
+                        //do nothing
+                    } //end if
+                } finally {
+                    con.unlock();
+                    if (setToNull)
+                        con = null;
+                }
+            } //while
+        } catch (ConcurrentModificationException e) {
+            log.debug("checkIdle failed." ,e);
+        } catch (Exception e) {
+            log.warn("checkIdle failed, it will be retried.",e);
+        }
+
+    }
+
+
+    protected boolean shouldReleaseIdle(long now, PooledConnection con, long time) {
+        if (con.getConnectionVersion() < getPoolVersion()) return true;
+        else return (con.getReleaseTime()>0) && ((now - time) > con.getReleaseTime()) && (getSize()>getPoolProperties().getMinIdle());
+    }
+
+    /**
+     * Forces a validation of all idle connections if {@link PoolProperties#testWhileIdle} is set.
+     */
+    public void testAllIdle() {
+        try {
+            if (idle.size()==0) return;
+            Iterator<PooledConnection> unlocked = idle.iterator();
+            while (unlocked.hasNext()) {
+                PooledConnection con = unlocked.next();
+                try {
+                    con.lock();
+                    //the con been taken out, we can't clean it up
+                    if (busy.contains(con))
+                        continue;
+                    if (!con.validate(PooledConnection.VALIDATE_IDLE)) {
+                        idle.remove(con);
+                        release(con);
+                    }
+                } finally {
+                    con.unlock();
+                }
+            } //while
+        } catch (ConcurrentModificationException e) {
+            log.debug("testAllIdle failed." ,e);
+        } catch (Exception e) {
+            log.warn("testAllIdle failed, it will be retried.",e);
+        }
+
+    }
+
+    /**
+     * Creates a stack trace representing the existing thread's current state.
+     * @return a string object representing the current state.
+     * TODO investigate if we simply should store {@link java.lang.Thread#getStackTrace()} elements
+     */
+    protected static String getThreadDump() {
+        Exception x = new Exception();
+        x.fillInStackTrace();
+        return getStackTrace(x);
+    }
+
+    /**
+     * Convert an exception into a String
+     * @param x - the throwable
+     * @return a string representing the stack trace
+     */
+    public static String getStackTrace(Throwable x) {
+        if (x == null) {
+            return null;
+        } else {
+            java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
+            java.io.PrintStream writer = new java.io.PrintStream(bout);
+            x.printStackTrace(writer);
+            String result = bout.toString();
+            return (x.getMessage()!=null && x.getMessage().length()>0)? x.getMessage()+";"+result:result;
+        } //end if
+    }
+
+
+    /**
+     * Create a new pooled connection object. Not connected nor validated.
+     * @param incrementCounter <code>true</code> to increment the connection count
+     * @return a pooled connection object
+     */
+    protected PooledConnection create(boolean incrementCounter) {
+        if (incrementCounter) size.incrementAndGet();
+        PooledConnection con = new PooledConnection(getPoolProperties(), this);
+        return con;
+    }
+
+    /**
+     * Purges all connections in the pool.
+     * For connections currently in use, these connections will be
+     * purged when returned on the pool. This call also
+     * purges connections that are idle and in the pool
+     * To only purge used/active connections see {@link #purgeOnReturn()}
+     */
+    public void purge() {
+        purgeOnReturn();
+        checkIdle(true);
+    }
+
+    /**
+     * Purges connections when they are returned from the pool.
+     * This call does not purge idle connections until they are used.
+     * To purge idle connections see {@link #purge()}
+     */
+    public void purgeOnReturn() {
+        poolVersion.incrementAndGet();
+    }
+
+    /**
+     * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
+     * @param con The connection
+     */
+    protected void finalize(PooledConnection con) {
+        JdbcInterceptor handler = con.getHandler();
+        while (handler!=null) {
+            handler.reset(null, null);
+            handler=handler.getNext();
+        }
+    }
+
+    /**
+     * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
+     * @param con The connection
+     * @param finalizing <code>true</code> if finalizing the connection
+     */
+    protected void disconnectEvent(PooledConnection con, boolean finalizing) {
+        JdbcInterceptor handler = con.getHandler();
+        while (handler!=null) {
+            handler.disconnected(this, con, finalizing);
+            handler=handler.getNext();
+        }
+    }
+
+    /**
+     * Return the object that is potentially registered in JMX for notifications
+     * @return the object implementing the {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} interface
+     */
+    public org.apache.tomcat.jdbc.pool.jmx.ConnectionPool getJmxPool() {
+        return jmxPool;
+    }
+
+    /**
+     * Create MBean object that can be registered.
+     */
+    protected void createMBean() {
+        try {
+            jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this);
+        } catch (Exception x) {
+            log.warn("Unable to start JMX integration for connection pool. Instance["+getName()+"] can't be monitored.",x);
+        }
+    }
+
+    /**
+     * The total number of connections borrowed from this pool.
+     * @return the borrowed connection count
+     */
+    public long getBorrowedCount() {
+        return borrowedCount.get();
+    }
+
+    /**
+     * The total number of connections returned to this pool.
+     * @return the returned connection count
+     */
+    public long getReturnedCount() {
+        return returnedCount.get();
+    }
+
+    /**
+     * The total number of connections created by this pool.
+     * @return the created connection count
+     */
+    public long getCreatedCount() {
+        return createdCount.get();
+    }
+
+    /**
+     * The total number of connections released from this pool.
+     * @return the released connection count
+     */
+    public long getReleasedCount() {
+        return releasedCount.get();
+    }
+
+    /**
+     * The total number of connections reconnected by this pool.
+     * @return the reconnected connection count
+     */
+    public long getReconnectedCount() {
+        return reconnectedCount.get();
+    }
+
+    /**
+     * The total number of connections released by remove abandoned.
+     * @return the PoolCleaner removed abandoned connection count
+     */
+    public long getRemoveAbandonedCount() {
+        return removeAbandonedCount.get();
+    }
+
+    /**
+     * The total number of connections released by eviction.
+     * @return the PoolCleaner evicted idle connection count
+     */
+    public long getReleasedIdleCount() {
+        return releasedIdleCount.get();
+    }
+
+    /**
+     * reset the statistics of this pool.
+     */
+    public void resetStats() {
+        borrowedCount.set(0);
+        returnedCount.set(0);
+        createdCount.set(0);
+        releasedCount.set(0);
+        reconnectedCount.set(0);
+        removeAbandonedCount.set(0);
+        releasedIdleCount.set(0);
+    }
+
+    /**
+     * Tread safe wrapper around a future for the regular queue
+     * This one retrieves the pooled connection object
+     * and performs the initialization according to
+     * interceptors and validation rules.
+     * This class is thread safe and is cancellable
+     *
+     */
+    protected class ConnectionFuture implements Future<Connection>, Runnable {
+        Future<PooledConnection> pcFuture = null;
+        AtomicBoolean configured = new AtomicBoolean(false);
+        CountDownLatch latch = new CountDownLatch(1);
+        volatile Connection result = null;
+        SQLException cause = null;
+        AtomicBoolean cancelled = new AtomicBoolean(false);
+        volatile PooledConnection pc = null;
+        public ConnectionFuture(Future<PooledConnection> pcf) {
+            this.pcFuture = pcf;
+        }
+
+        public ConnectionFuture(PooledConnection pc) throws SQLException {
+            this.pc = pc;
+            result = ConnectionPool.this.setupConnection(pc);
+            configured.set(true);
+        }
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            if (pc!=null) {
+                return false;
+            } else if ((!cancelled.get()) && cancelled.compareAndSet(false, true)) {
+                //cancel by retrieving the connection and returning it to the pool
+                ConnectionPool.this.cancellator.execute(this);
+            }
+            return true;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Connection get() throws InterruptedException, ExecutionException {
+            try {
+                return get(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+            }catch (TimeoutException x) {
+                throw new ExecutionException(x);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Connection get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+            PooledConnection pc = this.pc!=null?this.pc:pcFuture.get(timeout,unit);
+            if (pc!=null) {
+                if (result!=null) return result;
+                if (configured.compareAndSet(false, true)) {
+                    try {
+                        pc = borrowConnection(System.currentTimeMillis(),pc, null, null);
+                        result = ConnectionPool.this.setupConnection(pc);
+                    } catch (SQLException x) {
+                        cause = x;
+                    } finally {
+                        latch.countDown();
+                    }
+                } else {
+                    //if we reach here, another thread is configuring the actual connection
+                    latch.await(timeout,unit); //this shouldn't block for long
+                }
+                if (result==null) throw new ExecutionException(cause);
+                return result;
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isCancelled() {
+            return pc==null && (pcFuture.isCancelled() || cancelled.get());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isDone() {
+            return pc!=null || pcFuture.isDone();
+        }
+
+        /**
+         * run method to be executed when cancelled by an executor
+         */
+        @Override
+        public void run() {
+            try {
+                Connection con = get(); //complete this future
+                con.close(); //return to the pool
+            }catch (ExecutionException ex) {
+                //we can ignore this
+            }catch (Exception x) {
+                ConnectionPool.log.error("Unable to cancel ConnectionFuture.",x);
+            }
+        }
+
+    }
+
+
+
+    private static volatile Timer poolCleanTimer = null;
+    private static HashSet<PoolCleaner> cleaners = new HashSet<>();
+
+    private static synchronized void registerCleaner(PoolCleaner cleaner) {
+        unregisterCleaner(cleaner);
+        cleaners.add(cleaner);
+        if (poolCleanTimer == null) {
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(ConnectionPool.class.getClassLoader());
+                // Create the timer thread in a PrivilegedAction so that a
+                // reference to the web application class loader is not created
+                // via Thread.inheritedAccessControlContext
+                PrivilegedAction<Timer> pa = new PrivilegedNewTimer();
+                poolCleanTimer = AccessController.doPrivileged(pa);
+            } finally {
+                Thread.currentThread().setContextClassLoader(loader);
+            }
+        }
+        poolCleanTimer.schedule(cleaner, cleaner.sleepTime,cleaner.sleepTime);
+    }
+
+    private static synchronized void unregisterCleaner(PoolCleaner cleaner) {
+        boolean removed = cleaners.remove(cleaner);
+        if (removed) {
+            cleaner.cancel();
+            if (poolCleanTimer != null) {
+                poolCleanTimer.purge();
+                if (cleaners.size() == 0) {
+                    poolCleanTimer.cancel();
+                    poolCleanTimer = null;
+                }
+            }
+        }
+    }
+
+    private static class PrivilegedNewTimer implements PrivilegedAction<Timer> {
+        @Override
+        public Timer run() {
+            return new Timer("Tomcat JDBC Pool Cleaner["+ System.identityHashCode(ConnectionPool.class.getClassLoader()) + ":"+
+                    System.currentTimeMillis() + "]", true);
+        }
+    }
+
+    public static Set<TimerTask> getPoolCleaners() {
+        return Collections.<TimerTask>unmodifiableSet(cleaners);
+    }
+
+    public long getPoolVersion() {
+        return poolVersion.get();
+    }
+
+    public static Timer getPoolTimer() {
+        return poolCleanTimer;
+    }
+
+    protected static class PoolCleaner extends TimerTask {
+        protected WeakReference<ConnectionPool> pool;
+        protected long sleepTime;
+
+        PoolCleaner(ConnectionPool pool, long sleepTime) {
+            this.pool = new WeakReference<>(pool);
+            this.sleepTime = sleepTime;
+            if (sleepTime <= 0) {
+                log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds");
+                this.sleepTime = 1000 * 30;
+            } else if (sleepTime < 1000) {
+                log.warn("Database connection pool evicter thread interval is set to lower than 1 second.");
+            }
+        }
+
+        @Override
+        public void run() {
+            ConnectionPool pool = this.pool.get();
+            if (pool == null) {
+                stopRunning();
+            } else if (!pool.isClosed()) {
+                try {
+                    if (pool.getPoolProperties().isRemoveAbandoned()
+                            || pool.getPoolProperties().getSuspectTimeout() > 0)
+                        pool.checkAbandoned();
+                    if (pool.getPoolProperties().getMinIdle() < pool.idle
+                            .size())
+                        pool.checkIdle();
+                    if (pool.getPoolProperties().isTestWhileIdle())
+                        pool.testAllIdle();
+                } catch (Exception x) {
+                    log.error("", x);
+                }
+            }
+        }
+
+        public void start() {
+            registerCleaner(this);
+        }
+
+        public void stopRunning() {
+            unregisterCleaner(this);
+        }
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSource.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSource.java
new file mode 100644 (file)
index 0000000..4922bf0
--- /dev/null
@@ -0,0 +1,180 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.lang.management.ManagementFactory;
+import java.util.Hashtable;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+
+/**
+ * A DataSource that can be instantiated through IoC and implements the DataSource interface
+ * since the DataSourceProxy is used as a generic proxy.
+ * The DataSource simply wraps a {@link ConnectionPool} in order to provide a standard interface to the user.
+ * @version 1.0
+ */
+public class DataSource extends DataSourceProxy implements javax.sql.DataSource,MBeanRegistration, org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean, javax.sql.ConnectionPoolDataSource {
+    private static final Log log = LogFactory.getLog(DataSource.class);
+
+    /**
+     * Constructor for reflection only. A default set of pool properties will be created.
+     */
+    public DataSource() {
+        super();
+    }
+
+    /**
+     * Constructs a DataSource object wrapping a connection
+     * @param poolProperties The pool properties
+     */
+    public DataSource(PoolConfiguration poolProperties) {
+        super(poolProperties);
+    }
+
+
+
+
+
+//===============================================================================
+//  JMX Operations - Register the actual pool itself under the tomcat.jdbc domain
+//===============================================================================
+    protected volatile ObjectName oname = null;
+
+    /**
+     * Unregisters the underlying connection pool mbean.<br>
+     * {@inheritDoc}
+     */
+    @Override
+    public void postDeregister() {
+        if (oname!=null) unregisterJmx();
+    }
+
+    /**
+     * no-op<br>
+     * {@inheritDoc}
+     */
+    @Override
+    public void postRegister(Boolean registrationDone) {
+        // NOOP
+    }
+
+
+    /**
+     * no-op<br>
+     * {@inheritDoc}
+     */
+    @Override
+    public void preDeregister() throws Exception {
+        // NOOP
+    }
+
+    /**
+     * If the connection pool MBean exists, it will be registered during this operation.<br>
+     * {@inheritDoc}
+     */
+    @Override
+    public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
+        try {
+            if ( isJmxEnabled() ) {
+                this.oname = createObjectName(name);
+                if (oname!=null) registerJmx();
+            }
+        }catch (MalformedObjectNameException x) {
+            log.error("Unable to create object name for JDBC pool.",x);
+        }
+        return name;
+    }
+
+    /**
+     * Creates the ObjectName for the ConnectionPoolMBean object to be registered
+     * @param original the ObjectName for the DataSource
+     * @return the ObjectName for the ConnectionPoolMBean
+     * @throws MalformedObjectNameException Invalid object name
+     */
+    public ObjectName createObjectName(ObjectName original) throws MalformedObjectNameException {
+        String domain = ConnectionPool.POOL_JMX_DOMAIN;
+        Hashtable<String,String> properties = original.getKeyPropertyList();
+        String origDomain = original.getDomain();
+        properties.put("type", "ConnectionPool");
+        properties.put("class", this.getClass().getName());
+        if (original.getKeyProperty("path")!=null || properties.get("context")!=null) {
+            //this ensures that if the registration came from tomcat, we're not losing
+            //the unique domain, but putting that into as an engine attribute
+            properties.put("engine", origDomain);
+        }
+        ObjectName name = new ObjectName(domain,properties);
+        return name;
+    }
+
+    /**
+     * Registers the ConnectionPoolMBean under a unique name based on the ObjectName for the DataSource
+     */
+    protected void registerJmx() {
+        try {
+            if (pool.getJmxPool()!=null) {
+                MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+                mbs.registerMBean(pool.getJmxPool(), oname);
+            }
+        } catch (Exception e) {
+            log.error("Unable to register JDBC pool with JMX",e);
+        }
+    }
+
+    /**
+     *
+     */
+    protected void unregisterJmx() {
+        try {
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+            mbs.unregisterMBean(oname);
+        } catch (InstanceNotFoundException ignore) {
+            // NOOP
+        } catch (Exception e) {
+            log.error("Unable to unregister JDBC pool with JMX",e);
+        }
+    }
+
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
new file mode 100644 (file)
index 0000000..d0a5127
--- /dev/null
@@ -0,0 +1,612 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+
+import java.sql.Connection;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.management.ObjectName;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+import javax.sql.DataSource;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * <p>JNDI object factory that creates an instance of
+ * <code>BasicDataSource</code> that has been configured based on the
+ * <code>RefAddr</code> values of the specified <code>Reference</code>,
+ * which must match the names and data types of the
+ * <code>BasicDataSource</code> bean properties.</p>
+ * <br>
+ * Properties available for configuration:<br>
+ * <a href="http://commons.apache.org/dbcp/configuration.html">Commons DBCP properties</a><br>
+ *<ol>
+ *  <li>initSQL - A query that gets executed once, right after the connection is established.</li>
+ *  <li>testOnConnect - run validationQuery after connection has been established.</li>
+ *  <li>validationInterval - avoid excess validation, only run validation at most at this frequency - time in milliseconds.</li>
+ *  <li>jdbcInterceptors - a semicolon separated list of classnames extending {@link JdbcInterceptor} class.</li>
+ *  <li>jmxEnabled - true of false, whether to register the pool with JMX.</li>
+ *  <li>fairQueue - true of false, whether the pool should sacrifice a little bit of performance for true fairness.</li>
+ *</ol>
+ * @author Craig R. McClanahan
+ * @author Dirk Verbeeck
+ */
+public class DataSourceFactory implements ObjectFactory {
+    private static final Log log = LogFactory.getLog(DataSourceFactory.class);
+
+    protected static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
+    protected static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
+    protected static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
+    protected static final String PROP_DEFAULTCATALOG = "defaultCatalog";
+
+    protected static final String PROP_DRIVERCLASSNAME = "driverClassName";
+    protected static final String PROP_PASSWORD = "password";
+    protected static final String PROP_URL = "url";
+    protected static final String PROP_USERNAME = "username";
+
+    protected static final String PROP_MAXACTIVE = "maxActive";
+    protected static final String PROP_MAXIDLE = "maxIdle";
+    protected static final String PROP_MINIDLE = "minIdle";
+    protected static final String PROP_INITIALSIZE = "initialSize";
+    protected static final String PROP_MAXWAIT = "maxWait";
+    protected static final String PROP_MAXAGE = "maxAge";
+
+    protected static final String PROP_TESTONBORROW = "testOnBorrow";
+    protected static final String PROP_TESTONRETURN = "testOnReturn";
+    protected static final String PROP_TESTWHILEIDLE = "testWhileIdle";
+    protected static final String PROP_TESTONCONNECT = "testOnConnect";
+    protected static final String PROP_VALIDATIONQUERY = "validationQuery";
+    protected static final String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";
+    protected static final String PROP_VALIDATOR_CLASS_NAME = "validatorClassName";
+
+    protected static final String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
+    protected static final String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
+    protected static final String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
+
+    protected static final String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
+
+    protected static final String PROP_REMOVEABANDONED = "removeAbandoned";
+    protected static final String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
+    protected static final String PROP_LOGABANDONED = "logAbandoned";
+    protected static final String PROP_ABANDONWHENPERCENTAGEFULL = "abandonWhenPercentageFull";
+
+    protected static final String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
+    protected static final String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
+    protected static final String PROP_CONNECTIONPROPERTIES = "connectionProperties";
+
+    protected static final String PROP_INITSQL = "initSQL";
+    protected static final String PROP_INTERCEPTORS = "jdbcInterceptors";
+    protected static final String PROP_VALIDATIONINTERVAL = "validationInterval";
+    protected static final String PROP_JMX_ENABLED = "jmxEnabled";
+    protected static final String PROP_FAIR_QUEUE = "fairQueue";
+
+    protected static final String PROP_USE_EQUALS = "useEquals";
+    protected static final String PROP_USE_CON_LOCK = "useLock";
+
+    protected static final String PROP_DATASOURCE= "dataSource";
+    protected static final String PROP_DATASOURCE_JNDI = "dataSourceJNDI";
+
+    protected static final String PROP_SUSPECT_TIMEOUT = "suspectTimeout";
+
+    protected static final String PROP_ALTERNATE_USERNAME_ALLOWED = "alternateUsernameAllowed";
+
+    protected static final String PROP_COMMITONRETURN = "commitOnReturn";
+    protected static final String PROP_ROLLBACKONRETURN = "rollbackOnReturn";
+
+    protected static final String PROP_USEDISPOSABLECONNECTIONFACADE = "useDisposableConnectionFacade";
+
+    protected static final String PROP_LOGVALIDATIONERRORS = "logValidationErrors";
+
+    protected static final String PROP_PROPAGATEINTERRUPTSTATE = "propagateInterruptState";
+
+    protected static final String PROP_IGNOREEXCEPTIONONPRELOAD = "ignoreExceptionOnPreLoad";
+
+    public static final int UNKNOWN_TRANSACTIONISOLATION = -1;
+
+    public static final String OBJECT_NAME = "object_name";
+
+
+    protected static final String[] ALL_PROPERTIES = {
+        PROP_DEFAULTAUTOCOMMIT,
+        PROP_DEFAULTREADONLY,
+        PROP_DEFAULTTRANSACTIONISOLATION,
+        PROP_DEFAULTCATALOG,
+        PROP_DRIVERCLASSNAME,
+        PROP_MAXACTIVE,
+        PROP_MAXIDLE,
+        PROP_MINIDLE,
+        PROP_INITIALSIZE,
+        PROP_MAXWAIT,
+        PROP_TESTONBORROW,
+        PROP_TESTONRETURN,
+        PROP_TIMEBETWEENEVICTIONRUNSMILLIS,
+        PROP_NUMTESTSPEREVICTIONRUN,
+        PROP_MINEVICTABLEIDLETIMEMILLIS,
+        PROP_TESTWHILEIDLE,
+        PROP_TESTONCONNECT,
+        PROP_PASSWORD,
+        PROP_URL,
+        PROP_USERNAME,
+        PROP_VALIDATIONQUERY,
+        PROP_VALIDATIONQUERY_TIMEOUT,
+        PROP_VALIDATOR_CLASS_NAME,
+        PROP_VALIDATIONINTERVAL,
+        PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
+        PROP_REMOVEABANDONED,
+        PROP_REMOVEABANDONEDTIMEOUT,
+        PROP_LOGABANDONED,
+        PROP_POOLPREPAREDSTATEMENTS,
+        PROP_MAXOPENPREPAREDSTATEMENTS,
+        PROP_CONNECTIONPROPERTIES,
+        PROP_INITSQL,
+        PROP_INTERCEPTORS,
+        PROP_JMX_ENABLED,
+        PROP_FAIR_QUEUE,
+        PROP_USE_EQUALS,
+        OBJECT_NAME,
+        PROP_ABANDONWHENPERCENTAGEFULL,
+        PROP_MAXAGE,
+        PROP_USE_CON_LOCK,
+        PROP_DATASOURCE,
+        PROP_DATASOURCE_JNDI,
+        PROP_SUSPECT_TIMEOUT,
+        PROP_ALTERNATE_USERNAME_ALLOWED,
+        PROP_COMMITONRETURN,
+        PROP_ROLLBACKONRETURN,
+        PROP_USEDISPOSABLECONNECTIONFACADE,
+        PROP_LOGVALIDATIONERRORS,
+        PROP_PROPAGATEINTERRUPTSTATE,
+        PROP_IGNOREEXCEPTIONONPRELOAD
+    };
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+    /**
+     * <p>Create and return a new <code>BasicDataSource</code> instance.  If no
+     * instance can be created, return <code>null</code> instead.</p>
+     *
+     * @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</code>
+     * @param nameCtx The context relative to which the <code>name</code>
+     *  parameter is specified, or <code>null</code> if <code>name</code>
+     *  is relative to the default initial context
+     * @param environment The possibly null environment that is used in
+     *  creating this object
+     *
+     * @exception Exception if an exception occurs creating the instance
+     */
+    @Override
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable<?,?> environment) throws Exception {
+
+        // We only know how to deal with <code>javax.naming.Reference</code>s
+        // that specify a class name of "javax.sql.DataSource"
+        if ((obj == null) || !(obj instanceof Reference)) {
+            return null;
+        }
+        Reference ref = (Reference) obj;
+        boolean XA = false;
+        boolean ok = false;
+        if ("javax.sql.DataSource".equals(ref.getClassName())) {
+            ok = true;
+        }
+        if ("javax.sql.XADataSource".equals(ref.getClassName())) {
+            ok = true;
+            XA = true;
+        }
+        if (org.apache.tomcat.jdbc.pool.DataSource.class.getName().equals(ref.getClassName())) {
+            ok = true;
+        }
+
+        if (!ok) {
+            log.warn(ref.getClassName()+" is not a valid class name/type for this JNDI factory.");
+            return null;
+        }
+
+
+        Properties properties = new Properties();
+        for (int i = 0; i < ALL_PROPERTIES.length; i++) {
+            String propertyName = ALL_PROPERTIES[i];
+            RefAddr ra = ref.get(propertyName);
+            if (ra != null) {
+                String propertyValue = ra.getContent().toString();
+                properties.setProperty(propertyName, propertyValue);
+            }
+        }
+
+        return createDataSource(properties,nameCtx,XA);
+    }
+
+    public static PoolConfiguration parsePoolProperties(Properties properties) {
+        PoolConfiguration poolProperties = new PoolProperties();
+        String value = null;
+
+        value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
+        if (value != null) {
+            poolProperties.setDefaultAutoCommit(Boolean.valueOf(value));
+        }
+
+        value = properties.getProperty(PROP_DEFAULTREADONLY);
+        if (value != null) {
+            poolProperties.setDefaultReadOnly(Boolean.valueOf(value));
+        }
+
+        value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION);
+        if (value != null) {
+            int level = UNKNOWN_TRANSACTIONISOLATION;
+            if ("NONE".equalsIgnoreCase(value)) {
+                level = Connection.TRANSACTION_NONE;
+            } else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
+                level = Connection.TRANSACTION_READ_COMMITTED;
+            } else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
+                level = Connection.TRANSACTION_READ_UNCOMMITTED;
+            } else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
+                level = Connection.TRANSACTION_REPEATABLE_READ;
+            } else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
+                level = Connection.TRANSACTION_SERIALIZABLE;
+            } else {
+                try {
+                    level = Integer.parseInt(value);
+                } catch (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 = UNKNOWN_TRANSACTIONISOLATION;
+                }
+            }
+            poolProperties.setDefaultTransactionIsolation(level);
+        }
+
+        value = properties.getProperty(PROP_DEFAULTCATALOG);
+        if (value != null) {
+            poolProperties.setDefaultCatalog(value);
+        }
+
+        value = properties.getProperty(PROP_DRIVERCLASSNAME);
+        if (value != null) {
+            poolProperties.setDriverClassName(value);
+        }
+
+        value = properties.getProperty(PROP_MAXACTIVE);
+        if (value != null) {
+            poolProperties.setMaxActive(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_MAXIDLE);
+        if (value != null) {
+            poolProperties.setMaxIdle(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_MINIDLE);
+        if (value != null) {
+            poolProperties.setMinIdle(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_INITIALSIZE);
+        if (value != null) {
+            poolProperties.setInitialSize(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_MAXWAIT);
+        if (value != null) {
+            poolProperties.setMaxWait(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_TESTONBORROW);
+        if (value != null) {
+            poolProperties.setTestOnBorrow(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_TESTONRETURN);
+        if (value != null) {
+            poolProperties.setTestOnReturn(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_TESTONCONNECT);
+        if (value != null) {
+            poolProperties.setTestOnConnect(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
+        if (value != null) {
+            poolProperties.setTimeBetweenEvictionRunsMillis(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
+        if (value != null) {
+            poolProperties.setNumTestsPerEvictionRun(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
+        if (value != null) {
+            poolProperties.setMinEvictableIdleTimeMillis(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_TESTWHILEIDLE);
+        if (value != null) {
+            poolProperties.setTestWhileIdle(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_PASSWORD);
+        if (value != null) {
+            poolProperties.setPassword(value);
+        }
+
+        value = properties.getProperty(PROP_URL);
+        if (value != null) {
+            poolProperties.setUrl(value);
+        }
+
+        value = properties.getProperty(PROP_USERNAME);
+        if (value != null) {
+            poolProperties.setUsername(value);
+        }
+
+        value = properties.getProperty(PROP_VALIDATIONQUERY);
+        if (value != null) {
+            poolProperties.setValidationQuery(value);
+        }
+
+        value = properties.getProperty(PROP_VALIDATIONQUERY_TIMEOUT);
+        if (value != null) {
+            poolProperties.setValidationQueryTimeout(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_VALIDATOR_CLASS_NAME);
+        if (value != null) {
+            poolProperties.setValidatorClassName(value);
+        }
+
+        value = properties.getProperty(PROP_VALIDATIONINTERVAL);
+        if (value != null) {
+            poolProperties.setValidationInterval(Long.parseLong(value));
+        }
+
+        value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
+        if (value != null) {
+            poolProperties.setAccessToUnderlyingConnectionAllowed(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_REMOVEABANDONED);
+        if (value != null) {
+            poolProperties.setRemoveAbandoned(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
+        if (value != null) {
+            poolProperties.setRemoveAbandonedTimeout(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_LOGABANDONED);
+        if (value != null) {
+            poolProperties.setLogAbandoned(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS);
+        if (value != null) {
+            log.warn(PROP_POOLPREPAREDSTATEMENTS + " is not a valid setting, it will have no effect.");
+        }
+
+        value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS);
+        if (value != null) {
+            log.warn(PROP_MAXOPENPREPAREDSTATEMENTS + " is not a valid setting, it will have no effect.");
+        }
+
+        value = properties.getProperty(PROP_CONNECTIONPROPERTIES);
+        if (value != null) {
+            Properties p = getProperties(value);
+            poolProperties.setDbProperties(p);
+        } else {
+            poolProperties.setDbProperties(new Properties());
+        }
+
+        if (poolProperties.getUsername()!=null) {
+            poolProperties.getDbProperties().setProperty("user",poolProperties.getUsername());
+        }
+        if (poolProperties.getPassword()!=null) {
+            poolProperties.getDbProperties().setProperty("password",poolProperties.getPassword());
+        }
+
+        value = properties.getProperty(PROP_INITSQL);
+        if (value != null) {
+            poolProperties.setInitSQL(value);
+        }
+
+        value = properties.getProperty(PROP_INTERCEPTORS);
+        if (value != null) {
+            poolProperties.setJdbcInterceptors(value);
+        }
+
+        value = properties.getProperty(PROP_JMX_ENABLED);
+        if (value != null) {
+            poolProperties.setJmxEnabled(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_FAIR_QUEUE);
+        if (value != null) {
+            poolProperties.setFairQueue(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_USE_EQUALS);
+        if (value != null) {
+            poolProperties.setUseEquals(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(OBJECT_NAME);
+        if (value != null) {
+            poolProperties.setName(ObjectName.quote(value));
+        }
+
+        value = properties.getProperty(PROP_ABANDONWHENPERCENTAGEFULL);
+        if (value != null) {
+            poolProperties.setAbandonWhenPercentageFull(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_MAXAGE);
+        if (value != null) {
+            poolProperties.setMaxAge(Long.parseLong(value));
+        }
+
+        value = properties.getProperty(PROP_USE_CON_LOCK);
+        if (value != null) {
+            poolProperties.setUseLock(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_DATASOURCE);
+        if (value != null) {
+            //this should never happen
+            throw new IllegalArgumentException("Can't set dataSource property as a string, this must be a javax.sql.DataSource object.");
+
+        }
+
+        value = properties.getProperty(PROP_DATASOURCE_JNDI);
+        if (value != null) {
+            poolProperties.setDataSourceJNDI(value);
+        }
+
+        value = properties.getProperty(PROP_SUSPECT_TIMEOUT);
+        if (value != null) {
+            poolProperties.setSuspectTimeout(Integer.parseInt(value));
+        }
+
+        value = properties.getProperty(PROP_ALTERNATE_USERNAME_ALLOWED);
+        if (value != null) {
+            poolProperties.setAlternateUsernameAllowed(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_COMMITONRETURN);
+        if (value != null) {
+            poolProperties.setCommitOnReturn(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_ROLLBACKONRETURN);
+        if (value != null) {
+            poolProperties.setRollbackOnReturn(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_USEDISPOSABLECONNECTIONFACADE);
+        if (value != null) {
+            poolProperties.setUseDisposableConnectionFacade(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_LOGVALIDATIONERRORS);
+        if (value != null) {
+            poolProperties.setLogValidationErrors(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_PROPAGATEINTERRUPTSTATE);
+        if (value != null) {
+            poolProperties.setPropagateInterruptState(Boolean.parseBoolean(value));
+        }
+
+        value = properties.getProperty(PROP_IGNOREEXCEPTIONONPRELOAD);
+        if (value != null) {
+            poolProperties.setIgnoreExceptionOnPreLoad(Boolean.parseBoolean(value));
+        }
+
+        return poolProperties;
+    }
+
+    /**
+     * Creates and configures a {@link DataSource} instance based on the
+     * given properties.
+     *
+     * @param properties the datasource configuration properties
+     * @return the datasource
+     * @throws Exception if an error occurs creating the data source
+     */
+    public DataSource createDataSource(Properties properties) throws Exception {
+        return createDataSource(properties,null,false);
+    }
+    public DataSource createDataSource(Properties properties,Context context, boolean XA) throws Exception {
+        PoolConfiguration poolProperties = DataSourceFactory.parsePoolProperties(properties);
+        if (poolProperties.getDataSourceJNDI()!=null && poolProperties.getDataSource()==null) {
+            performJNDILookup(context, poolProperties);
+        }
+        org.apache.tomcat.jdbc.pool.DataSource dataSource = XA?
+                new org.apache.tomcat.jdbc.pool.XADataSource(poolProperties) :
+                new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
+        //initialise the pool itself
+        dataSource.createPool();
+        // Return the configured DataSource instance
+        return dataSource;
+    }
+
+    public void performJNDILookup(Context context, PoolConfiguration poolProperties) {
+        Object jndiDS = null;
+        try {
+            if (context!=null) {
+                jndiDS = context.lookup(poolProperties.getDataSourceJNDI());
+            } else {
+                log.warn("dataSourceJNDI property is configured, but local JNDI context is null.");
+            }
+        } catch (NamingException e) {
+            log.debug("The name \""+poolProperties.getDataSourceJNDI()+"\" cannot be found in the local context.");
+        }
+        if (jndiDS==null) {
+            try {
+                context = new InitialContext();
+                jndiDS = context.lookup(poolProperties.getDataSourceJNDI());
+            } catch (NamingException e) {
+                log.warn("The name \""+poolProperties.getDataSourceJNDI()+"\" cannot be found in the InitialContext.");
+            }
+        }
+        if (jndiDS!=null) {
+            poolProperties.setDataSource(jndiDS);
+        }
+    }
+
+    /**
+     * Parse properties from the string. Format of the string must be [propertyName=property;]*.
+     * @param propText The properties string
+     * @return the properties
+     */
+    protected static Properties getProperties(String propText) {
+        return PoolProperties.getProperties(propText,null);
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
new file mode 100644 (file)
index 0000000..3e9b8ae
--- /dev/null
@@ -0,0 +1,1496 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.concurrent.Future;
+import java.util.logging.Logger;
+
+import javax.sql.XAConnection;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
+
+/**
+ *
+ * The DataSource proxy lets us implements methods that don't exist in the current
+ * compiler JDK but might be methods that are part of a future JDK DataSource interface.
+ * <br>
+ * It's a trick to work around compiler issues when implementing interfaces. For example,
+ * I could put in Java 6 methods of javax.sql.DataSource here, and compile it with JDK 1.5
+ * and still be able to run under Java 6 without getting NoSuchMethodException.
+ *
+ * @version 1.0
+ */
+
+public class DataSourceProxy implements PoolConfiguration {
+    private static final Log log = LogFactory.getLog(DataSourceProxy.class);
+
+    protected volatile ConnectionPool pool = null;
+
+    protected volatile PoolConfiguration poolProperties = null;
+
+    public DataSourceProxy() {
+        this(new PoolProperties());
+    }
+
+    public DataSourceProxy(PoolConfiguration poolProperties) {
+        if (poolProperties == null) throw new NullPointerException("PoolConfiguration cannot be null.");
+        this.poolProperties = poolProperties;
+    }
+
+
+    @SuppressWarnings("unused") // Has to match signature in DataSource
+    public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        // we are not a wrapper of anything
+        return false;
+    }
+
+
+    @SuppressWarnings("unused") // Has to match signature in DataSource
+    public <T> T unwrap(Class<T> iface) throws SQLException {
+        //we can't unwrap anything
+        return null;
+    }
+
+    /**
+     * Get a database connection.
+     * {@link javax.sql.DataSource#getConnection()}
+     * @param username The user name
+     * @param password The password
+     * @return the connection
+     * @throws SQLException Connection error
+     */
+    public Connection getConnection(String username, String password) throws SQLException {
+        if (this.getPoolProperties().isAlternateUsernameAllowed()) {
+            if (pool == null)
+                return createPool().getConnection(username,password);
+            return pool.getConnection(username,password);
+        } else {
+            return getConnection();
+        }
+    }
+
+    public PoolConfiguration getPoolProperties() {
+        return poolProperties;
+    }
+
+    /**
+     * Sets up the connection pool, by creating a pooling driver.
+     * @return the connection pool
+     * @throws SQLException Error creating pool
+     */
+    public ConnectionPool createPool() throws SQLException {
+        if (pool != null) {
+            return pool;
+        } else {
+            return pCreatePool();
+        }
+    }
+
+    /**
+     * Sets up the connection pool, by creating a pooling driver.
+     */
+    private synchronized ConnectionPool pCreatePool() throws SQLException {
+        if (pool != null) {
+            return pool;
+        } else {
+            pool = new ConnectionPool(poolProperties);
+            return pool;
+        }
+    }
+
+    /**
+     * Get a database connection.
+     * {@link javax.sql.DataSource#getConnection()}
+     * @return the connection
+     * @throws SQLException Connection error
+     */
+    public Connection getConnection() throws SQLException {
+        if (pool == null)
+            return createPool().getConnection();
+        return pool.getConnection();
+    }
+
+    /**
+     * Invokes an sync operation to retrieve the connection.
+     * @return a Future containing a reference to the connection when it becomes available
+     * @throws SQLException Connection error
+     */
+    public Future<Connection> getConnectionAsync() throws SQLException {
+        if (pool == null)
+            return createPool().getConnectionAsync();
+        return pool.getConnectionAsync();
+    }
+
+    /**
+     * Get a database connection.
+     * {@link javax.sql.XADataSource#getXAConnection()}
+     * @return the connection
+     * @throws SQLException Connection error
+     */
+    public XAConnection getXAConnection() throws SQLException {
+        Connection con = getConnection();
+        if (con instanceof XAConnection) {
+            return (XAConnection)con;
+        } else {
+            try {
+                con.close();
+            } catch (Exception ignore) {
+                // Ignore
+            }
+            throw new SQLException("Connection from pool does not implement javax.sql.XAConnection");
+        }
+    }
+
+    /**
+     * Get a database connection.
+     * {@link javax.sql.XADataSource#getXAConnection(String, String)}
+     * @param username The user name
+     * @param password The password
+     * @return the connection
+     * @throws SQLException Connection error
+     */
+    public XAConnection getXAConnection(String username, String password) throws SQLException {
+        Connection con = getConnection(username, password);
+        if (con instanceof XAConnection) {
+            return (XAConnection)con;
+        } else {
+            try {
+                con.close();
+            } catch (Exception ignore) {
+                // Ignore
+            }
+            throw new SQLException("Connection from pool does not implement javax.sql.XAConnection");
+        }
+    }
+
+
+    /**
+     * Get a database connection.
+     * {@link javax.sql.DataSource#getConnection()}
+     * @return the connection
+     * @throws SQLException Connection error
+     */
+    public javax.sql.PooledConnection getPooledConnection() throws SQLException {
+        return (javax.sql.PooledConnection) getConnection();
+    }
+
+    /**
+     * Get a database connection.
+     * {@link javax.sql.DataSource#getConnection()}
+     * @param username unused
+     * @param password unused
+     * @return the connection
+     * @throws SQLException Connection error
+     */
+    public javax.sql.PooledConnection getPooledConnection(String username,
+            String password) throws SQLException {
+        return (javax.sql.PooledConnection) getConnection();
+    }
+
+    public ConnectionPool getPool() {
+        try {
+            return createPool();
+        }catch (SQLException x) {
+            log.error("Error during connection pool creation.", x);
+            return null;
+        }
+    }
+
+
+    public void close() {
+        close(false);
+    }
+    public void close(boolean all) {
+        try {
+            if (pool != null) {
+                final ConnectionPool p = pool;
+                pool = null;
+                if (p!=null) {
+                    p.close(all);
+                }
+            }
+        }catch (Exception x) {
+            log.warn("Error during connection pool closure.", x);
+        }
+    }
+
+    public int getPoolSize() {
+        final ConnectionPool p = pool;
+        if (p == null) return 0;
+        else return p.getSize();
+    }
+
+
+    @Override
+    public String toString() {
+        return super.toString()+"{"+getPoolProperties()+"}";
+    }
+
+
+/*-----------------------------------------------------------------------*/
+//      PROPERTIES WHEN NOT USED WITH FACTORY
+/*------------------------------------------------------------------------*/
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getPoolName() {
+        return pool.getName();
+    }
+
+
+    public void setPoolProperties(PoolConfiguration poolProperties) {
+        this.poolProperties = poolProperties;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDriverClassName(String driverClassName) {
+        this.poolProperties.setDriverClassName(driverClassName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setInitialSize(int initialSize) {
+        this.poolProperties.setInitialSize(initialSize);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setInitSQL(String initSQL) {
+        this.poolProperties.setInitSQL(initSQL);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setLogAbandoned(boolean logAbandoned) {
+        this.poolProperties.setLogAbandoned(logAbandoned);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxActive(int maxActive) {
+        this.poolProperties.setMaxActive(maxActive);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxIdle(int maxIdle) {
+        this.poolProperties.setMaxIdle(maxIdle);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxWait(int maxWait) {
+        this.poolProperties.setMaxWait(maxWait);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+        this.poolProperties.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMinIdle(int minIdle) {
+        this.poolProperties.setMinIdle(minIdle);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+        this.poolProperties.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setPassword(String password) {
+        this.poolProperties.setPassword(password);
+        this.poolProperties.getDbProperties().setProperty("password",this.poolProperties.getPassword());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setRemoveAbandoned(boolean removeAbandoned) {
+        this.poolProperties.setRemoveAbandoned(removeAbandoned);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
+        this.poolProperties.setRemoveAbandonedTimeout(removeAbandonedTimeout);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestOnBorrow(boolean testOnBorrow) {
+        this.poolProperties.setTestOnBorrow(testOnBorrow);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestOnConnect(boolean testOnConnect) {
+        this.poolProperties.setTestOnConnect(testOnConnect);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestOnReturn(boolean testOnReturn) {
+        this.poolProperties.setTestOnReturn(testOnReturn);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestWhileIdle(boolean testWhileIdle) {
+        this.poolProperties.setTestWhileIdle(testWhileIdle);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
+        this.poolProperties.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUrl(String url) {
+        this.poolProperties.setUrl(url);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUsername(String username) {
+        this.poolProperties.setUsername(username);
+        this.poolProperties.getDbProperties().setProperty("user",getPoolProperties().getUsername());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidationInterval(long validationInterval) {
+        this.poolProperties.setValidationInterval(validationInterval);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidationQuery(String validationQuery) {
+        this.poolProperties.setValidationQuery(validationQuery);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidatorClassName(String className) {
+        this.poolProperties.setValidatorClassName(className);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidationQueryTimeout(int validationQueryTimeout) {
+        this.poolProperties.setValidationQueryTimeout(validationQueryTimeout);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setJdbcInterceptors(String interceptors) {
+        this.getPoolProperties().setJdbcInterceptors(interceptors);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setJmxEnabled(boolean enabled) {
+        this.getPoolProperties().setJmxEnabled(enabled);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setFairQueue(boolean fairQueue) {
+        this.getPoolProperties().setFairQueue(fairQueue);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUseLock(boolean useLock) {
+        this.getPoolProperties().setUseLock(useLock);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultCatalog(String catalog) {
+        this.getPoolProperties().setDefaultCatalog(catalog);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultAutoCommit(Boolean autocommit) {
+        this.getPoolProperties().setDefaultAutoCommit(autocommit);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
+        this.getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setConnectionProperties(String properties) {
+        try {
+            java.util.Properties prop = DataSourceFactory
+                    .getProperties(properties);
+            Iterator<?> i = prop.keySet().iterator();
+            while (i.hasNext()) {
+                String key = (String) i.next();
+                String value = prop.getProperty(key);
+                getPoolProperties().getDbProperties().setProperty(key, value);
+            }
+
+        } catch (Exception x) {
+            log.error("Unable to parse connection properties.", x);
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUseEquals(boolean useEquals) {
+        this.getPoolProperties().setUseEquals(useEquals);
+    }
+
+    /**
+     * no-op
+     * {@link javax.sql.DataSource#getParentLogger}
+     * @return no return value
+     * @throws SQLFeatureNotSupportedException Unsupported
+     */
+    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    /**
+     * no-op
+     * {@link javax.sql.DataSource#getLogWriter}
+     * @return null
+     * @throws SQLException No exception
+     */
+    public PrintWriter getLogWriter() throws SQLException {
+        return null;
+    }
+
+
+    /**
+     * no-op
+     * {@link javax.sql.DataSource#setLogWriter(PrintWriter)}
+     * @param out Ignored
+     * @throws SQLException No exception
+     */
+    public void setLogWriter(PrintWriter out) throws SQLException {
+        // NOOP
+    }
+
+    /**
+     * no-op
+     * {@link javax.sql.DataSource#getLoginTimeout}
+     * @return the timeout
+     */
+    public int getLoginTimeout() {
+        if (poolProperties == null) {
+            return 0;
+        } else {
+            return poolProperties.getMaxWait() / 1000;
+        }
+    }
+
+    /**
+     * {@link javax.sql.DataSource#setLoginTimeout(int)}
+     * @param i The timeout value
+     */
+    public void setLoginTimeout(int i) {
+        if (poolProperties == null) {
+            return;
+        } else {
+            poolProperties.setMaxWait(1000 * i);
+        }
+
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getSuspectTimeout() {
+        return getPoolProperties().getSuspectTimeout();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setSuspectTimeout(int seconds) {
+        getPoolProperties().setSuspectTimeout(seconds);
+    }
+
+  //===============================================================================
+//  Expose JMX attributes through Tomcat's dynamic reflection
+//===============================================================================
+    /**
+     * If the pool has not been created, it will be created during this call.
+     * @return the number of established but idle connections
+     */
+    public int getIdle() {
+        try {
+            return createPool().getIdle();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * {@link #getIdle()}
+     * @return the number of established but idle connections
+     */
+    public int getNumIdle() {
+        return getIdle();
+    }
+
+    /**
+     * Forces an abandon check on the connection pool.
+     * If connections that have been abandoned exists, they will be closed during this run
+     */
+    public void checkAbandoned() {
+        try {
+            createPool().checkAbandoned();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * Forces a check for resizing of the idle connections
+     */
+    public void checkIdle() {
+        try {
+            createPool().checkIdle();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * @return number of connections in use by the application
+     */
+    public int getActive() {
+        try {
+            return createPool().getActive();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * @return number of connections in use by the application
+     * {@link DataSource#getActive()}
+     */
+    public int getNumActive() {
+        return getActive();
+    }
+
+    /**
+     * @return number of threads waiting for a connection
+     */
+    public int getWaitCount() {
+        try {
+            return createPool().getWaitCount();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * @return the current size of the pool
+     */
+    public int getSize() {
+        try {
+            return createPool().getSize();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * Performs a validation on idle connections
+     */
+    public void testIdle() {
+        try {
+            createPool().testAllIdle();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * The total number of connections borrowed from this pool.
+     * @return the borrowed connection count
+     */
+    public long getBorrowedCount() {
+        try {
+            return createPool().getBorrowedCount();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * The total number of connections returned to this pool.
+     * @return the returned connection count
+     */
+    public long getReturnedCount() {
+        try {
+            return createPool().getReturnedCount();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * The total number of connections created by this pool.
+     * @return the created connection count
+     */
+    public long getCreatedCount() {
+        try {
+            return createPool().getCreatedCount();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * The total number of connections released from this pool.
+     * @return the released connection count
+     */
+    public long getReleasedCount() {
+        try {
+            return createPool().getReleasedCount();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * The total number of connections reconnected by this pool.
+     * @return the reconnected connection count
+     */
+    public long getReconnectedCount() {
+        try {
+            return createPool().getReconnectedCount();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * The total number of connections released by remove abandoned.
+     * @return the PoolCleaner removed abandoned connection count
+     */
+    public long getRemoveAbandonedCount() {
+        try {
+            return createPool().getRemoveAbandonedCount();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * The total number of connections released by eviction.
+     * @return the PoolCleaner evicted idle connection count
+     */
+    public long getReleasedIdleCount() {
+        try {
+            return createPool().getReleasedIdleCount();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    /**
+     * reset the statistics of this pool.
+     */
+    public void resetStats() {
+        try {
+            createPool().resetStats();
+        } catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+    //=========================================================
+    //  PROPERTIES / CONFIGURATION
+    //=========================================================
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getConnectionProperties() {
+        return getPoolProperties().getConnectionProperties();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Properties getDbProperties() {
+        return getPoolProperties().getDbProperties();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getDefaultCatalog() {
+        return getPoolProperties().getDefaultCatalog();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getDefaultTransactionIsolation() {
+        return getPoolProperties().getDefaultTransactionIsolation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getDriverClassName() {
+        return getPoolProperties().getDriverClassName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getInitialSize() {
+        return getPoolProperties().getInitialSize();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getInitSQL() {
+        return getPoolProperties().getInitSQL();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getJdbcInterceptors() {
+        return getPoolProperties().getJdbcInterceptors();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMaxActive() {
+        return getPoolProperties().getMaxActive();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMaxIdle() {
+        return getPoolProperties().getMaxIdle();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMaxWait() {
+        return getPoolProperties().getMaxWait();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMinEvictableIdleTimeMillis() {
+        return getPoolProperties().getMinEvictableIdleTimeMillis();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMinIdle() {
+        return getPoolProperties().getMinIdle();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public long getMaxAge() {
+        return getPoolProperties().getMaxAge();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getName() {
+        return getPoolProperties().getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getNumTestsPerEvictionRun() {
+        return getPoolProperties().getNumTestsPerEvictionRun();
+    }
+
+    /**
+     * @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
+     */
+    @Override
+    public String getPassword() {
+        return "Password not available as DataSource/JMX operation.";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getRemoveAbandonedTimeout() {
+        return getPoolProperties().getRemoveAbandonedTimeout();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getTimeBetweenEvictionRunsMillis() {
+        return getPoolProperties().getTimeBetweenEvictionRunsMillis();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getUrl() {
+        return getPoolProperties().getUrl();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getUsername() {
+        return getPoolProperties().getUsername();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public long getValidationInterval() {
+        return getPoolProperties().getValidationInterval();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getValidationQuery() {
+        return getPoolProperties().getValidationQuery();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getValidationQueryTimeout() {
+        return getPoolProperties().getValidationQueryTimeout();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getValidatorClassName() {
+        return getPoolProperties().getValidatorClassName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Validator getValidator() {
+        return getPoolProperties().getValidator();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValidator(Validator validator) {
+        getPoolProperties().setValidator(validator);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isAccessToUnderlyingConnectionAllowed() {
+        return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean isDefaultAutoCommit() {
+        return getPoolProperties().isDefaultAutoCommit();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean isDefaultReadOnly() {
+        return getPoolProperties().isDefaultReadOnly();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isLogAbandoned() {
+        return getPoolProperties().isLogAbandoned();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isPoolSweeperEnabled() {
+        return getPoolProperties().isPoolSweeperEnabled();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isRemoveAbandoned() {
+        return getPoolProperties().isRemoveAbandoned();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getAbandonWhenPercentageFull() {
+        return getPoolProperties().getAbandonWhenPercentageFull();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestOnBorrow() {
+        return getPoolProperties().isTestOnBorrow();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestOnConnect() {
+        return getPoolProperties().isTestOnConnect();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestOnReturn() {
+        return getPoolProperties().isTestOnReturn();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestWhileIdle() {
+        return getPoolProperties().isTestWhileIdle();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean getDefaultAutoCommit() {
+        return getPoolProperties().getDefaultAutoCommit();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean getDefaultReadOnly() {
+        return getPoolProperties().getDefaultReadOnly();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
+        return getPoolProperties().getJdbcInterceptorsAsArray();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean getUseLock() {
+        return getPoolProperties().getUseLock();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isFairQueue() {
+        return getPoolProperties().isFairQueue();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isJmxEnabled() {
+        return getPoolProperties().isJmxEnabled();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isUseEquals() {
+        return getPoolProperties().isUseEquals();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setAbandonWhenPercentageFull(int percentage) {
+        getPoolProperties().setAbandonWhenPercentageFull(percentage);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
+        getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDbProperties(Properties dbProperties) {
+        getPoolProperties().setDbProperties(dbProperties);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultReadOnly(Boolean defaultReadOnly) {
+        getPoolProperties().setDefaultReadOnly(defaultReadOnly);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxAge(long maxAge) {
+        getPoolProperties().setMaxAge(maxAge);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setName(String name) {
+        getPoolProperties().setName(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDataSource(Object ds) {
+        getPoolProperties().setDataSource(ds);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object getDataSource() {
+        return getPoolProperties().getDataSource();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDataSourceJNDI(String jndiDS) {
+        getPoolProperties().setDataSourceJNDI(jndiDS);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getDataSourceJNDI() {
+        return getPoolProperties().getDataSourceJNDI();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAlternateUsernameAllowed() {
+        return getPoolProperties().isAlternateUsernameAllowed();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
+        getPoolProperties().setAlternateUsernameAllowed(alternateUsernameAllowed);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setCommitOnReturn(boolean commitOnReturn) {
+        getPoolProperties().setCommitOnReturn(commitOnReturn);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getCommitOnReturn() {
+        return getPoolProperties().getCommitOnReturn();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setRollbackOnReturn(boolean rollbackOnReturn) {
+        getPoolProperties().setRollbackOnReturn(rollbackOnReturn);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getRollbackOnReturn() {
+        return getPoolProperties().getRollbackOnReturn();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUseDisposableConnectionFacade(boolean useDisposableConnectionFacade) {
+        getPoolProperties().setUseDisposableConnectionFacade(useDisposableConnectionFacade);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getUseDisposableConnectionFacade() {
+        return getPoolProperties().getUseDisposableConnectionFacade();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setLogValidationErrors(boolean logValidationErrors) {
+        getPoolProperties().setLogValidationErrors(logValidationErrors);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getLogValidationErrors() {
+        return getPoolProperties().getLogValidationErrors();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getPropagateInterruptState() {
+        return getPoolProperties().getPropagateInterruptState();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setPropagateInterruptState(boolean propagateInterruptState) {
+        getPoolProperties().setPropagateInterruptState(propagateInterruptState);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isIgnoreExceptionOnPreLoad() {
+        return getPoolProperties().isIgnoreExceptionOnPreLoad();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setIgnoreExceptionOnPreLoad(boolean ignoreExceptionOnPreLoad) {
+        getPoolProperties().setIgnoreExceptionOnPreLoad(ignoreExceptionOnPreLoad);
+    }
+
+    public void purge()  {
+        try {
+            createPool().purge();
+        }catch (SQLException x) {
+            log.error("Unable to purge pool.",x);
+        }
+    }
+
+    public void purgeOnReturn() {
+        try {
+            createPool().purgeOnReturn();
+        }catch (SQLException x) {
+            log.error("Unable to purge pool.",x);
+        }
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DisposableConnectionFacade.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/DisposableConnectionFacade.java
new file mode 100644 (file)
index 0000000..ed0e9db
--- /dev/null
@@ -0,0 +1,118 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.SQLException;
+
+/**
+ * A DisposableConnectionFacade object is the top most interceptor that wraps an
+ * object of type {@link PooledConnection}. The ProxyCutOffConnection intercepts
+ * two methods:
+ * <ul>
+ *   <li>{@link java.sql.Connection#close()} - returns the connection to the
+ *       pool then breaks the link between cutoff and the next interceptor.
+ *       May be called multiple times.</li>
+ *   <li>{@link java.lang.Object#toString()} - returns a custom string for this
+ *       object</li>
+ * </ul>
+ * By default method comparisons is done on a String reference level, unless the
+ * {@link PoolConfiguration#setUseEquals(boolean)} has been called with a
+ * <code>true</code> argument.
+ */
+public class DisposableConnectionFacade extends JdbcInterceptor {
+    protected DisposableConnectionFacade(JdbcInterceptor interceptor) {
+        setUseEquals(interceptor.isUseEquals());
+        setNext(interceptor);
+    }
+
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+    }
+
+
+
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return this==obj;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        if (compare(EQUALS_VAL, method)) {
+            return Boolean.valueOf(
+                    this.equals(Proxy.getInvocationHandler(args[0])));
+        } else if (compare(HASHCODE_VAL, method)) {
+            return Integer.valueOf(this.hashCode());
+        } else if (getNext()==null) {
+            if (compare(ISCLOSED_VAL, method)) {
+                return Boolean.TRUE;
+            }
+            else if (compare(CLOSE_VAL, method)) {
+                return null;
+            }
+            else if (compare(ISVALID_VAL, method)) {
+                return Boolean.FALSE;
+            }
+        }
+
+        try {
+            return super.invoke(proxy, method, args);
+        } catch (NullPointerException e) {
+            if (getNext() == null) {
+                if (compare(TOSTRING_VAL, method)) {
+                    return "DisposableConnectionFacade[null]";
+                }
+                throw new SQLException(
+                        "PooledConnection has already been closed.");
+            }
+
+            throw e;
+        } finally {
+            if (compare(CLOSE_VAL, method)) {
+                setNext(null);
+            }
+        }
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java
new file mode 100644 (file)
index 0000000..c02bfa3
--- /dev/null
@@ -0,0 +1,579 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ *
+ * A simple implementation of a blocking queue with fairness waiting.
+ * invocations to method poll(...) will get handed out in the order they were received.
+ * Locking is fine grained, a shared lock is only used during the first level of contention, waiting is done in a
+ * lock per thread basis so that order is guaranteed once the thread goes into a suspended monitor state.
+ * <br>
+ * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented.
+ *
+ * @param <E> Type of element in the queue
+ */
+
+public class FairBlockingQueue<E> implements BlockingQueue<E> {
+
+    /**
+     * This little sucker is used to reorder the way to do
+     * {@link java.util.concurrent.locks.Lock#lock()},
+     * {@link java.util.concurrent.locks.Lock#unlock()}
+     * and
+     * {@link java.util.concurrent.CountDownLatch#countDown()}
+     * during the {@link #poll(long, TimeUnit)} operation.
+     * On Linux, it performs much better if we count down while we hold the global
+     * lock, on Solaris its the other way around.
+     * Until we have tested other platforms we only check for Linux.
+     */
+    static final boolean isLinux = "Linux".equals(System.getProperty("os.name")) &&
+                                   (!Boolean.getBoolean(FairBlockingQueue.class.getName()+".ignoreOS"));
+
+    /**
+     * Phase one entry lock in order to give out
+     * per-thread-locks for the waiting phase we have
+     * a phase one lock during the contention period.
+     */
+    final ReentrantLock lock = new ReentrantLock(false);
+
+    /**
+     * All the objects in the pool are stored in a simple linked list
+     */
+    final LinkedList<E> items;
+
+    /**
+     * All threads waiting for an object are stored in a linked list
+     */
+    final LinkedList<ExchangeCountDownLatch<E>> waiters;
+
+    /**
+     * Creates a new fair blocking queue.
+     */
+    public FairBlockingQueue() {
+        items = new LinkedList<>();
+        waiters = new LinkedList<>();
+    }
+
+    //------------------------------------------------------------------
+    // USED BY CONPOOL IMPLEMENTATION
+    //------------------------------------------------------------------
+    /**
+     * Will always return true, queue is unbounded.
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean offer(E e) {
+        //during the offer, we will grab the main lock
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        ExchangeCountDownLatch<E> c = null;
+        try {
+            //check to see if threads are waiting for an object
+            if (waiters.size() > 0) {
+                //if threads are waiting grab the latch for that thread
+                c = waiters.poll();
+                //give the object to the thread instead of adding it to the pool
+                c.setItem(e);
+                if (isLinux) c.countDown();
+            } else {
+                //we always add first, so that the most recently used object will be given out
+                items.addFirst(e);
+            }
+        } finally {
+            lock.unlock();
+        }
+        //if we exchanged an object with another thread, wake it up.
+        if (!isLinux && c!=null) c.countDown();
+        //we have an unbounded queue, so always return true
+        return true;
+    }
+
+    /**
+     * Will never timeout, as it invokes the {@link #offer(Object)} method.
+     * Once a lock has been acquired, the
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
+        return offer(e);
+    }
+
+    /**
+     * Fair retrieval of an object in the queue.
+     * Objects are returned in the order the threads requested them.
+     * {@inheritDoc}
+     */
+    @Override
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E result = null;
+        final ReentrantLock lock = this.lock;
+        //acquire the global lock until we know what to do
+        lock.lock();
+        try {
+            //check to see if we have objects
+            result = items.poll();
+            if (result==null && timeout>0) {
+                //the queue is empty we will wait for an object
+                ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<>(1);
+                //add to the bottom of the wait list
+                waiters.addLast(c);
+                //unlock the global lock
+                lock.unlock();
+                boolean didtimeout = true;
+                InterruptedException interruptedException = null;
+                try {
+                    //wait for the specified timeout
+                    didtimeout = !c.await(timeout, unit);
+                } catch (InterruptedException ix) {
+                    interruptedException = ix;
+                }
+                if (didtimeout) {
+                    //if we timed out, or got interrupted
+                    // remove ourselves from the waitlist
+                    lock.lock();
+                    try {
+                        waiters.remove(c);
+                    } finally {
+                        lock.unlock();
+                    }
+                }
+                //return the item we received, can be null if we timed out
+                result = c.getItem();
+                if (null!=interruptedException) {
+                    //we got interrupted
+                    if ( null!=result) {
+                        //we got a result - clear the interrupt status
+                        //don't propagate cause we have removed a connection from pool
+                        Thread.interrupted();
+                    } else {
+                        throw interruptedException;
+                    }
+                }
+            } else {
+                //we have an object, release
+                lock.unlock();
+            }
+        } finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Request an item from the queue asynchronously
+     * @return - a future pending the result from the queue poll request
+     */
+    public Future<E> pollAsync() {
+        Future<E> result = null;
+        final ReentrantLock lock = this.lock;
+        //grab the global lock
+        lock.lock();
+        try {
+            //check to see if we have objects in the queue
+            E item = items.poll();
+            if (item==null) {
+                //queue is empty, add ourselves as waiters
+                ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<>(1);
+                waiters.addLast(c);
+                //return a future that will wait for the object
+                result = new ItemFuture<>(c);
+            } else {
+                //return a future with the item
+                result = new ItemFuture<>(item);
+            }
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean remove(Object e) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return items.remove(e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int size() {
+        return items.size();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterator<E> iterator() {
+        return new FairIterator();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return items.poll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean contains(Object e) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return items.contains(e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+
+    //------------------------------------------------------------------
+    // NOT USED BY CONPOOL IMPLEMENTATION
+    //------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        throw new UnsupportedOperationException("int drainTo(Collection<? super E> c, int maxElements)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+
+    @Override
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c,Integer.MAX_VALUE);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void put(E e) throws InterruptedException {
+        offer(e);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE - size();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public E take() throws InterruptedException {
+        return this.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+        Iterator<? extends E> i = c.iterator();
+        while (i.hasNext()) {
+            E e = i.next();
+            offer(e);
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public void clear() {
+        throw new UnsupportedOperationException("void clear()");
+
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        throw new UnsupportedOperationException("boolean containsAll(Collection<?> c)");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        throw new UnsupportedOperationException("boolean removeAll(Collection<?> c)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        throw new UnsupportedOperationException("boolean retainAll(Collection<?> c)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public Object[] toArray() {
+        throw new UnsupportedOperationException("Object[] toArray()");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        throw new UnsupportedOperationException("<T> T[] toArray(T[] a)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public E element() {
+        throw new UnsupportedOperationException("E element()");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public E peek() {
+        throw new UnsupportedOperationException("E peek()");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public E remove() {
+        throw new UnsupportedOperationException("E remove()");
+    }
+
+
+
+    //------------------------------------------------------------------
+    // Non cancellable Future used to check and see if a connection has been made available
+    //------------------------------------------------------------------
+    protected class ItemFuture<T> implements Future<T> {
+        protected volatile T item = null;
+        protected volatile ExchangeCountDownLatch<T> latch = null;
+        protected volatile boolean canceled = false;
+
+        public ItemFuture(T item) {
+            this.item = item;
+        }
+
+        public ItemFuture(ExchangeCountDownLatch<T> latch) {
+            this.latch = latch;
+        }
+
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            return false; //don't allow cancel for now
+        }
+
+        @Override
+        public T get() throws InterruptedException, ExecutionException {
+            if (item!=null) {
+                return item;
+            } else if (latch!=null) {
+                latch.await();
+                return latch.getItem();
+            } else {
+                throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+            }
+        }
+
+        @Override
+        public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+            if (item!=null) {
+                return item;
+            } else if (latch!=null) {
+                boolean timedout = !latch.await(timeout, unit);
+                if (timedout) throw new TimeoutException();
+                else return latch.getItem();
+            } else {
+                throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+            }
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return false;
+        }
+
+        @Override
+        public boolean isDone() {
+            return (item!=null || latch.getItem()!=null);
+        }
+
+    }
+
+    //------------------------------------------------------------------
+    // Count down latch that can be used to exchange information
+    //------------------------------------------------------------------
+    protected class ExchangeCountDownLatch<T> extends CountDownLatch {
+        protected volatile T item;
+        public ExchangeCountDownLatch(int i) {
+            super(i);
+        }
+        public T getItem() {
+            return item;
+        }
+        public void setItem(T item) {
+            this.item = item;
+        }
+    }
+
+    //------------------------------------------------------------------
+    // Iterator safe from concurrent modification exceptions
+    //------------------------------------------------------------------
+    protected class FairIterator implements Iterator<E> {
+        E[] elements = null;
+        int index;
+        E element = null;
+
+        @SuppressWarnings("unchecked") // Can't create arrays of generic types
+        public FairIterator() {
+            final ReentrantLock lock = FairBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                elements = (E[]) new Object[FairBlockingQueue.this.items.size()];
+                FairBlockingQueue.this.items.toArray(elements);
+                index = 0;
+            } finally {
+                lock.unlock();
+            }
+        }
+        @Override
+        public boolean hasNext() {
+            return index<elements.length;
+        }
+
+        @Override
+        public E next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            element = elements[index++];
+            return element;
+        }
+
+        @Override
+        public void remove() {
+            final ReentrantLock lock = FairBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (element!=null) {
+                    FairBlockingQueue.this.items.remove(element);
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
new file mode 100644 (file)
index 0000000..46bc0b1
--- /dev/null
@@ -0,0 +1,259 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+
+/**
+ * Abstract class that is to be extended for implementations of interceptors.
+ * Everytime an operation is called on the {@link java.sql.Connection} object the
+ * {@link #invoke(Object, Method, Object[])} method on the interceptor will be called.
+ * Interceptors are useful to change or improve behavior of the connection pool.<br>
+ * Interceptors can receive a set of properties. Each sub class is responsible for parsing the properties during runtime when they
+ * are needed or simply override the {@link #setProperties(Map)} method.
+ * Properties arrive in a key-value pair of Strings as they were received through the configuration.
+ * This method is called once per cached connection object when the object is first configured.
+ *
+ * @version 1.0
+ */
+public abstract class JdbcInterceptor implements InvocationHandler {
+    /**
+     * {@link java.sql.Connection#close()} method name
+     */
+    public static final String CLOSE_VAL = "close";
+    /**
+     * {@link Object#toString()} method name
+     */
+    public static final String TOSTRING_VAL = "toString";
+    /**
+     * {@link java.sql.Connection#isClosed()} method name
+     */
+    public static final String ISCLOSED_VAL = "isClosed";
+    /**
+     * {@link javax.sql.PooledConnection#getConnection()} method name
+     */
+    public static final String GETCONNECTION_VAL = "getConnection";
+    /**
+     * {@link java.sql.Wrapper#unwrap(Class)} method name
+     */
+    public static final String UNWRAP_VAL = "unwrap";
+    /**
+     * {@link java.sql.Wrapper#isWrapperFor(Class)} method name
+     */
+    public static final String ISWRAPPERFOR_VAL = "isWrapperFor";
+
+    /**
+     * {@link java.sql.Connection#isValid(int)} method name
+     */
+    public static final String ISVALID_VAL = "isValid";
+
+    /**
+     * {@link java.lang.Object#equals(Object)}
+     */
+    public static final String EQUALS_VAL = "equals";
+
+    /**
+     * {@link java.lang.Object#hashCode()}
+     */
+    public static final String HASHCODE_VAL = "hashCode";
+
+    /**
+     * Properties for this interceptor.
+     */
+    protected Map<String,InterceptorProperty> properties = null;
+
+    /**
+     * The next interceptor in the chain
+     */
+    private volatile JdbcInterceptor next = null;
+    /**
+     * Property that decides how we do string comparison, default is to use
+     * {@link String#equals(Object)}. If set to <code>false</code> then the
+     * equality operator (==) is used.
+     */
+    private boolean useEquals = true;
+
+    /**
+     * Public constructor for instantiation through reflection
+     */
+    public JdbcInterceptor() {
+        // NOOP
+    }
+
+    /**
+     * Gets invoked each time an operation on {@link java.sql.Connection} is invoked.
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (getNext()!=null) return getNext().invoke(proxy,method,args);
+        else throw new NullPointerException();
+    }
+
+    /**
+     * Returns the next interceptor in the chain
+     * @return the next interceptor in the chain
+     */
+    public JdbcInterceptor getNext() {
+        return next;
+    }
+
+    /**
+     * configures the next interceptor in the chain
+     * @param next The next chain item
+     */
+    public void setNext(JdbcInterceptor next) {
+        this.next = next;
+    }
+
+    /**
+     * Performs a string comparison, using references unless the useEquals property is set to true.
+     * @param name1 The first name
+     * @param name2 The second name
+     * @return true if name1 is equal to name2 based on {@link #useEquals}
+     */
+    public boolean compare(String name1, String name2) {
+        if (isUseEquals()) {
+            return name1.equals(name2);
+        } else {
+            return name1==name2;
+        }
+    }
+
+    /**
+     * Compares a method name (String) to a method (Method)
+     * {@link #compare(String,String)}
+     * Uses reference comparison unless the useEquals property is set to true
+     * @param methodName The method name
+     * @param method The method
+     * @return <code>true</code> if the name matches
+     */
+    public boolean compare(String methodName, Method method) {
+        return compare(methodName, method.getName());
+    }
+
+    /**
+     * Gets called each time the connection is borrowed from the pool
+     * This means that if an interceptor holds a reference to the connection
+     * the interceptor can be reused for another connection.
+     * <br>
+     * This method may be called with null as both arguments when we are closing down the connection.
+     * @param parent - the connection pool owning the connection
+     * @param con - the pooled connection
+     */
+    public abstract void reset(ConnectionPool parent, PooledConnection con);
+
+    /**
+     * Called when {@link java.sql.Connection#close()} is called on the underlying connection.
+     * This is to notify the interceptors, that the physical connection has been released.
+     * Implementation of this method should be thought through with care, as no actions should trigger an exception.
+     * @param parent - the connection pool that this connection belongs to
+     * @param con    - the pooled connection that holds this connection
+     * @param finalizing - if this connection is finalizing. True means that the pooled connection will not reconnect the underlying connection
+     */
+    public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
+    }
+
+
+    /**
+     * Returns the properties configured for this interceptor
+     * @return the configured properties for this interceptor
+     */
+    public Map<String,InterceptorProperty> getProperties() {
+        return properties;
+    }
+
+    /**
+     * Called during the creation of an interceptor
+     * The properties can be set during the configuration of an interceptor
+     * Override this method to perform type casts between string values and object properties
+     * @param properties The properties
+     */
+    public void setProperties(Map<String,InterceptorProperty> properties) {
+        this.properties = properties;
+        final String useEquals = "useEquals";
+        InterceptorProperty p = properties.get(useEquals);
+        if (p!=null) {
+            setUseEquals(Boolean.parseBoolean(p.getValue()));
+        }
+    }
+
+    /**
+     * @return true if the compare method uses the Object.equals(Object) method
+     *         false if comparison is done on a reference level
+     */
+    public boolean isUseEquals() {
+        return useEquals;
+    }
+
+    /**
+     * Set to true if string comparisons (for the {@link #compare(String, Method)} and {@link #compare(String, String)} methods) should use the Object.equals(Object) method
+     * The default is false
+     * @param useEquals <code>true</code> if equals will be used for comparisons
+     */
+    public void setUseEquals(boolean useEquals) {
+        this.useEquals = useEquals;
+    }
+
+    /**
+     * This method is invoked by a connection pool when the pool is closed.
+     * Interceptor classes can override this method if they keep static
+     * variables or other tracking means around.
+     * <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
+     * @param pool - the pool that is being closed.
+     */
+    public void poolClosed(ConnectionPool pool) {
+        // NOOP
+    }
+
+    /**
+     * This method is invoked by a connection pool when the pool is first started up, usually when the first connection is requested.
+     * Interceptor classes can override this method if they keep static
+     * variables or other tracking means around.
+     * <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
+     * @param pool - the pool that is being closed.
+     */
+    public void poolStarted(ConnectionPool pool) {
+        // NOOP
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java
new file mode 100644 (file)
index 0000000..a4b1f73
--- /dev/null
@@ -0,0 +1,584 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * <b>EXPERIMENTAL AND NOT YET COMPLETE!</b>
+ *
+ *
+ * An implementation of a blocking queue with fairness waiting and lock dispersal to avoid contention.
+ * invocations to method poll(...) will get handed out in the order they were received.
+ * Locking is fine grained, a shared lock is only used during the first level of contention, waiting is done in a
+ * lock per thread basis so that order is guaranteed once the thread goes into a suspended monitor state.
+ * <br>
+ * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented.
+ *
+ * @param <E> Type of element in the queue
+ */
+
+public class MultiLockFairBlockingQueue<E> implements BlockingQueue<E> {
+
+    final int LOCK_COUNT = Runtime.getRuntime().availableProcessors();
+
+    final AtomicInteger putQueue = new AtomicInteger(0);
+    final AtomicInteger pollQueue = new AtomicInteger(0);
+
+    public int getNextPut() {
+        int idx = Math.abs(putQueue.incrementAndGet()) % LOCK_COUNT;
+        return idx;
+    }
+
+    public int getNextPoll() {
+        int idx = Math.abs(pollQueue.incrementAndGet()) % LOCK_COUNT;
+        return idx;
+    }
+    /**
+     * Phase one entry lock in order to give out
+     * per-thread-locks for the waiting phase we have
+     * a phase one lock during the contention period.
+     */
+    private final ReentrantLock[] locks = new ReentrantLock[LOCK_COUNT];
+
+    /**
+     * All the objects in the pool are stored in a simple linked list
+     */
+    final LinkedList<E>[] items;
+
+    /**
+     * All threads waiting for an object are stored in a linked list
+     */
+    final LinkedList<ExchangeCountDownLatch<E>>[] waiters;
+
+    /**
+     * Creates a new fair blocking queue.
+     */
+    @SuppressWarnings("unchecked") // Can create arrays of generic types
+    public MultiLockFairBlockingQueue() {
+        items = new LinkedList[LOCK_COUNT];
+        waiters = new LinkedList[LOCK_COUNT];
+        for (int i=0; i<LOCK_COUNT; i++) {
+            items[i] = new LinkedList<>();
+            waiters[i] = new LinkedList<>();
+            locks[i] = new ReentrantLock(false);
+        }
+    }
+
+    //------------------------------------------------------------------
+    // USED BY CONPOOL IMPLEMENTATION
+    //------------------------------------------------------------------
+    /**
+     * Will always return true, queue is unbounded.
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean offer(E e) {
+        int idx = getNextPut();
+        //during the offer, we will grab the main lock
+        final ReentrantLock lock = this.locks[idx];
+        lock.lock();
+        ExchangeCountDownLatch<E> c = null;
+        try {
+            //check to see if threads are waiting for an object
+            if (waiters[idx].size() > 0) {
+                //if threads are waiting grab the latch for that thread
+                c = waiters[idx].poll();
+                //give the object to the thread instead of adding it to the pool
+                c.setItem(e);
+            } else {
+                //we always add first, so that the most recently used object will be given out
+                items[idx].addFirst(e);
+            }
+        } finally {
+            lock.unlock();
+        }
+        //if we exchanged an object with another thread, wake it up.
+        if (c!=null) c.countDown();
+        //we have an unbounded queue, so always return true
+        return true;
+    }
+
+    /**
+     * Will never timeout, as it invokes the {@link #offer(Object)} method.
+     * Once a lock has been acquired, the
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
+        return offer(e);
+    }
+
+    /**
+     * Fair retrieval of an object in the queue.
+     * Objects are returned in the order the threads requested them.
+     * {@inheritDoc}
+     */
+    @Override
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        int idx = getNextPoll();
+        E result = null;
+        final ReentrantLock lock = this.locks[idx];
+        try {
+            //acquire the global lock until we know what to do
+            lock.lock();
+            //check to see if we have objects
+            result = items[idx].poll();
+            if (result==null && timeout>0) {
+                //the queue is empty we will wait for an object
+                ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<>(1);
+                //add to the bottom of the wait list
+                waiters[idx].addLast(c);
+                //unlock the global lock
+                lock.unlock();
+                //wait for the specified timeout
+                if (!c.await(timeout, unit)) {
+                    //if we timed out, remove ourselves from the waitlist
+                    lock.lock();
+                    waiters[idx].remove(c);
+                    lock.unlock();
+                }
+                //return the item we received, can be null if we timed out
+                result = c.getItem();
+            } else {
+                //we have an object, release
+                lock.unlock();
+            }
+        } finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Request an item from the queue asynchronously
+     * @return - a future pending the result from the queue poll request
+     */
+    public Future<E> pollAsync() {
+        int idx = getNextPoll();
+        Future<E> result = null;
+        final ReentrantLock lock = this.locks[idx];
+        try {
+            //grab the global lock
+            lock.lock();
+            //check to see if we have objects in the queue
+            E item = items[idx].poll();
+            if (item==null) {
+                //queue is empty, add ourselves as waiters
+                ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<>(1);
+                waiters[idx].addLast(c);
+                //return a future that will wait for the object
+                result = new ItemFuture<>(c);
+            } else {
+                //return a future with the item
+                result = new ItemFuture<>(item);
+            }
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean remove(Object e) {
+        for (int idx=0; idx<LOCK_COUNT; idx++) {
+            final ReentrantLock lock = this.locks[idx];
+            lock.lock();
+            try {
+                boolean result = items[idx].remove(e);
+                if (result) return result;
+            } finally {
+                lock.unlock();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int size() {
+        int size = 0;
+        for (int idx=0; idx<LOCK_COUNT; idx++) {
+            size += items[idx].size();
+        }
+        return size;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterator<E> iterator() {
+        return new FairIterator();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public E poll() {
+        int idx = getNextPoll();
+        final ReentrantLock lock = this.locks[idx];
+        lock.lock();
+        try {
+            return items[idx].poll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean contains(Object e) {
+        for (int idx=0; idx<LOCK_COUNT; idx++) {
+            boolean result = items[idx].contains(e);
+            if (result) return result;
+        }
+        return false;
+    }
+
+
+    //------------------------------------------------------------------
+    // NOT USED BY CONPOOL IMPLEMENTATION
+    //------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        throw new UnsupportedOperationException("int drainTo(Collection<? super E> c, int maxElements)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c,Integer.MAX_VALUE);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void put(E e) throws InterruptedException {
+        offer(e);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE - size();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public E take() throws InterruptedException {
+        return this.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+        Iterator<? extends E> i = c.iterator();
+        while (i.hasNext()) {
+            E e = i.next();
+            offer(e);
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public void clear() {
+        throw new UnsupportedOperationException("void clear()");
+
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        throw new UnsupportedOperationException("boolean containsAll(Collection<?> c)");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        throw new UnsupportedOperationException("boolean removeAll(Collection<?> c)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        throw new UnsupportedOperationException("boolean retainAll(Collection<?> c)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public Object[] toArray() {
+        throw new UnsupportedOperationException("Object[] toArray()");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        throw new UnsupportedOperationException("<T> T[] toArray(T[] a)");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public E element() {
+        throw new UnsupportedOperationException("E element()");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public E peek() {
+        throw new UnsupportedOperationException("E peek()");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws UnsupportedOperationException - this operation is not supported
+     */
+    @Override
+    public E remove() {
+        throw new UnsupportedOperationException("E remove()");
+    }
+
+
+
+    //------------------------------------------------------------------
+    // Non cancellable Future used to check and see if a connection has been made available
+    //------------------------------------------------------------------
+    protected class ItemFuture<T> implements Future<T> {
+        protected volatile T item = null;
+        protected volatile ExchangeCountDownLatch<T> latch = null;
+        protected volatile boolean canceled = false;
+
+        public ItemFuture(T item) {
+            this.item = item;
+        }
+
+        public ItemFuture(ExchangeCountDownLatch<T> latch) {
+            this.latch = latch;
+        }
+
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            return false; //don't allow cancel for now
+        }
+
+        @Override
+        public T get() throws InterruptedException, ExecutionException {
+            if (item!=null) {
+                return item;
+            } else if (latch!=null) {
+                latch.await();
+                return latch.getItem();
+            } else {
+                throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+            }
+        }
+
+        @Override
+        public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+            if (item!=null) {
+                return item;
+            } else if (latch!=null) {
+                boolean timedout = !latch.await(timeout, unit);
+                if (timedout) throw new TimeoutException();
+                else return latch.getItem();
+            } else {
+                throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+            }
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return false;
+        }
+
+        @Override
+        public boolean isDone() {
+            return (item!=null || latch.getItem()!=null);
+        }
+
+    }
+
+    //------------------------------------------------------------------
+    // Count down latch that can be used to exchange information
+    //------------------------------------------------------------------
+    protected class ExchangeCountDownLatch<T> extends CountDownLatch {
+        protected volatile T item;
+        public ExchangeCountDownLatch(int i) {
+            super(i);
+        }
+        public T getItem() {
+            return item;
+        }
+        public void setItem(T item) {
+            this.item = item;
+        }
+    }
+
+    //------------------------------------------------------------------
+    // Iterator safe from concurrent modification exceptions
+    //------------------------------------------------------------------
+    protected class FairIterator implements Iterator<E> {
+        E[] elements = null;
+        int index;
+        E element = null;
+
+        @SuppressWarnings("unchecked") // Can't create arrays of generic types
+        public FairIterator() {
+            ArrayList<E> list = new ArrayList<>(MultiLockFairBlockingQueue.this.size());
+            for (int idx=0; idx<LOCK_COUNT; idx++) {
+                final ReentrantLock lock = MultiLockFairBlockingQueue.this.locks[idx];
+                lock.lock();
+                try {
+                    elements = (E[]) new Object[MultiLockFairBlockingQueue.this.items[idx].size()];
+                    MultiLockFairBlockingQueue.this.items[idx].toArray(elements);
+
+                } finally {
+                    lock.unlock();
+                }
+            }
+            index = 0;
+            elements = (E[]) new Object[list.size()];
+            list.toArray(elements);
+        }
+        @Override
+        public boolean hasNext() {
+            return index<elements.length;
+        }
+
+        @Override
+        public E next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            element = elements[index++];
+            return element;
+        }
+
+        @Override
+        public void remove() {
+            for (int idx=0; idx<LOCK_COUNT; idx++) {
+                final ReentrantLock lock = MultiLockFairBlockingQueue.this.locks[idx];
+                lock.lock();
+                try {
+                    boolean result = MultiLockFairBlockingQueue.this.items[idx].remove(elements[index]);
+                    if (result) break;
+                } finally {
+                    lock.unlock();
+                }
+            }
+
+        }
+
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
new file mode 100644 (file)
index 0000000..42cf11d
--- /dev/null
@@ -0,0 +1,917 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.util.Properties;
+
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
+
+/**
+ * A list of properties that are configurable for a connection pool.
+ * The {@link DataSource} object also implements this interface so that it can be easily configured through
+ * an IoC container without having to specify a secondary object with a setter method.
+ *
+ */
+
+public interface PoolConfiguration {
+
+    /**
+     * JMX prefix for interceptors that register themselves with JMX
+     */
+    public static final String PKG_PREFIX = "org.apache.tomcat.jdbc.pool.interceptor.";
+
+    /**
+     * Connections that have been abandoned (timed out) wont get closed and reported up unless the number of connections in use are
+     * above the percentage defined by abandonWhenPercentageFull.
+     * The value should be between 0-100.
+     * The default value is 0, which implies that connections are eligible for
+     * closure as soon as removeAbandonedTimeout has been reached.
+     * @param percentage a value between 0 and 100 to indicate when connections that have been abandoned/timed out are considered abandoned
+     */
+    public void setAbandonWhenPercentageFull(int percentage);
+
+    /**
+     * Connections that have been abandoned (timed out) wont get closed and reported up unless the number of connections in use are
+     * above the percentage defined by abandonWhenPercentageFull.
+     * The value should be between 0-100.
+     * The default value is 0, which implies that connections are eligible for
+     * closure as soon as removeAbandonedTimeout has been reached.
+     * @return percentage - a value between 0 and 100 to indicate when connections that have been abandoned/timed out are considered abandoned
+     */
+    public int getAbandonWhenPercentageFull();
+
+    /**
+     * Returns <code>true</code> if a fair queue is being used by the connection pool
+     * @return <code>true</code> if a fair waiting queue is being used
+     */
+    public boolean isFairQueue();
+
+    /**
+     * Set to true if you wish that calls to getConnection
+     * should be treated fairly in a true FIFO fashion.
+     * This uses the {@link FairBlockingQueue} implementation for the list of the idle connections.
+     * The default value is true.
+     * This flag is required when you want to use asynchronous connection retrieval.
+     * @param fairQueue <code>true</code> to use a fair queue
+     */
+    public void setFairQueue(boolean fairQueue);
+
+    /**
+     * Property not used. Access is always allowed.
+     * Access can be achieved by calling unwrap on the pooled connection. see {@link javax.sql.DataSource} interface
+     * or call getConnection through reflection or cast the object as {@link javax.sql.PooledConnection}
+     * @return <code>true</code>
+     */
+    public boolean isAccessToUnderlyingConnectionAllowed();
+
+    /**
+     * No-op
+     * @param accessToUnderlyingConnectionAllowed parameter ignored
+     */
+    public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed);
+
+    /**
+     * The connection properties that will be sent to the JDBC driver when establishing new connections.
+     * Format of the string is [propertyName=property;] <br>
+     * NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be included here.
+     * The default value is null.
+     * @return the connection properties
+     */
+    public String getConnectionProperties();
+
+    /**
+     * The properties that will be passed into {@link java.sql.Driver#connect(String, Properties)} method.
+     * Username and password do not need to be stored here, they will be passed into the properties right before the connection is established.
+     * @param connectionProperties properties - Format of the string is [propertyName=property;]*
+     * Example: prop1=value1;prop2=value2
+     */
+    public void setConnectionProperties(String connectionProperties);
+
+    /**
+     * Returns the database properties that are passed into the {@link java.sql.Driver#connect(String, Properties)} method.
+     * @return database properties that are passed into the {@link java.sql.Driver#connect(String, Properties)} method.
+     */
+    public Properties getDbProperties();
+
+    /**
+     * Overrides the database properties passed into the  {@link java.sql.Driver#connect(String, Properties)} method.
+     * @param dbProperties The database properties
+     */
+    public void setDbProperties(Properties dbProperties);
+
+    /**
+     * The default auto-commit state of connections created by this pool.
+     * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
+     * @return the default auto commit setting, null is Driver default.
+     */
+    public Boolean isDefaultAutoCommit();
+
+    /**
+     * The default auto-commit state of connections created by this pool.
+     * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
+     * @return the default auto commit setting, null is Driver default.
+     */
+    public Boolean getDefaultAutoCommit();
+
+    /**
+     * The default auto-commit state of connections created by this pool.
+     * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
+     * @param defaultAutoCommit default auto commit setting, null is Driver default.
+     */
+    public void setDefaultAutoCommit(Boolean defaultAutoCommit);
+
+    /**
+     * If non null, during connection creation the method {@link java.sql.Connection#setCatalog(String)} will be called with the set value.
+     * @return the default catalog, null if not set and accepting the driver default.
+     */
+    public String getDefaultCatalog();
+
+    /**
+     * If non null, during connection creation the method {@link java.sql.Connection#setCatalog(String)} will be called with the set value.
+     * @param defaultCatalog null if not set and accepting the driver default.
+     */
+    public void setDefaultCatalog(String defaultCatalog);
+
+    /**
+     * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
+     * @return null if not set and accepting the driver default otherwise the read only value
+     */
+    public Boolean isDefaultReadOnly();
+
+    /**
+     * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
+     * @return null if not set and accepting the driver default otherwise the read only value
+     */
+    public Boolean getDefaultReadOnly();
+
+    /**
+     * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
+     * @param defaultReadOnly null if not set and accepting the driver default.
+     */
+    public void setDefaultReadOnly(Boolean defaultReadOnly);
+
+
+    /**
+     * Returns the default transaction isolation level. If set to {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} the method
+     * {@link java.sql.Connection#setTransactionIsolation(int)} will not be called during connection creation.
+     * @return driver transaction isolation level, or -1 {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} if not set.
+     */
+    public int getDefaultTransactionIsolation();
+
+    /**
+     * If set to {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} the method
+     * {@link java.sql.Connection#setTransactionIsolation(int)} will not be called during connection creation. Otherwise the method
+     * will be called with the isolation level set by this property.
+     * @param defaultTransactionIsolation a value of {@link java.sql.Connection#TRANSACTION_NONE}, {@link java.sql.Connection#TRANSACTION_READ_COMMITTED},
+     * {@link java.sql.Connection#TRANSACTION_READ_UNCOMMITTED}, {@link java.sql.Connection#TRANSACTION_REPEATABLE_READ},
+     * {@link java.sql.Connection#TRANSACTION_SERIALIZABLE} or {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION}
+     * The last value will not be set on the connection.
+     */
+    public void setDefaultTransactionIsolation(int defaultTransactionIsolation);
+
+    /**
+     * The fully qualified Java class name of the JDBC driver to be used. The driver has to be accessible from the same classloader as tomcat-jdbc.jar
+     * @return fully qualified JDBC driver name.
+     */
+    public String getDriverClassName();
+
+    /**
+     * The fully qualified Java class name of the JDBC driver to be used. The driver has to be accessible from the same classloader as tomcat-jdbc.jar
+     * @param driverClassName a fully qualified Java class name of a {@link java.sql.Driver} implementation.
+     */
+    public void setDriverClassName(String driverClassName);
+
+    /**
+     * Returns the number of connections that will be established when the connection pool is started.
+     * Default value is 10
+     * @return number of connections to be started when pool is started
+     */
+    public int getInitialSize();
+
+    /**
+     * Set the number of connections that will be established when the connection pool is started.
+     * Default value is 10.
+     * If this value exceeds {@link #setMaxActive(int)} it will automatically be lowered.
+     * @param initialSize the number of connections to be established.
+     *
+     */
+    public void setInitialSize(int initialSize);
+
+    /**
+     * boolean flag to set if stack traces should be logged for application code which abandoned a Connection.
+     * Logging of abandoned Connections adds overhead for every Connection borrow because a stack trace has to be generated.
+     * The default value is false.
+     * @return true if the connection pool logs stack traces when connections are borrowed from the pool.
+     */
+    public boolean isLogAbandoned();
+
+    /**
+     * boolean flag to set if stack traces should be logged for application code which abandoned a Connection.
+     * Logging of abandoned Connections adds overhead for every Connection borrow because a stack trace has to be generated.
+     * The default value is false.
+     * @param logAbandoned set to true if stack traces should be recorded when {@link DataSource#getConnection()} is called.
+     */
+    public void setLogAbandoned(boolean logAbandoned);
+
+    /**
+     * The maximum number of active connections that can be allocated from this pool at the same time. The default value is 100
+     * @return the maximum number of connections used by this pool
+     */
+    public int getMaxActive();
+
+    /**
+     * The maximum number of active connections that can be allocated from this pool at the same time. The default value is 100
+     * @param maxActive hard limit for number of managed connections by this pool
+     */
+    public void setMaxActive(int maxActive);
+
+
+    /**
+     * The maximum number of connections that should be kept in the idle pool if {@link #isPoolSweeperEnabled()} returns false.
+     * If the If {@link #isPoolSweeperEnabled()} returns true, then the idle pool can grow up to {@link #getMaxActive}
+     * and will be shrunk according to {@link #getMinEvictableIdleTimeMillis()} setting.
+     * Default value is maxActive:100
+     * @return the maximum number of idle connections.
+     */
+    public int getMaxIdle();
+
+    /**
+     * The maximum number of connections that should be kept in the idle pool if {@link #isPoolSweeperEnabled()} returns false.
+     * If the If {@link #isPoolSweeperEnabled()} returns true, then the idle pool can grow up to {@link #getMaxActive}
+     * and will be shrunk according to {@link #getMinEvictableIdleTimeMillis()} setting.
+     * Default value is maxActive:100
+     * @param maxIdle the maximum size of the idle pool
+     */
+    public void setMaxIdle(int maxIdle);
+
+    /**
+     * The maximum number of milliseconds that the pool will wait (when there are no available connections and the
+     * {@link #getMaxActive} has been reached) for a connection to be returned
+     * before throwing an exception. Default value is 30000 (30 seconds)
+     * @return the number of milliseconds to wait for a connection to become available if the pool is maxed out.
+     */
+    public int getMaxWait();
+
+    /**
+     * The maximum number of milliseconds that the pool will wait (when there are no available connections and the
+     * {@link #getMaxActive} has been reached) for a connection to be returned
+     * before throwing an exception. Default value is 30000 (30 seconds)
+     * @param maxWait the maximum number of milliseconds to wait.
+     */
+    public void setMaxWait(int maxWait);
+
+    /**
+     * The minimum amount of time an object must sit idle in the pool before it is eligible for eviction.
+     * The default value is 60000 (60 seconds).
+     * @return the minimum amount of idle time in milliseconds before a connection is considered idle and eligible for eviction.
+     */
+    public int getMinEvictableIdleTimeMillis();
+
+    /**
+     * The minimum amount of time an object must sit idle in the pool before it is eligible for eviction.
+     * The default value is 60000 (60 seconds).
+     * @param minEvictableIdleTimeMillis the number of milliseconds a connection must be idle to be eligible for eviction.
+     */
+    public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis);
+
+    /**
+     * The minimum number of established connections that should be kept in the pool at all times.
+     * The connection pool can shrink below this number if validation queries fail and connections get closed.
+     * Default value is derived from {@link #getInitialSize()} (also see {@link #setTestWhileIdle(boolean)}
+     * The idle pool will not shrink below this value during an eviction run, hence the number of actual connections
+     * can be between {@link #getMinIdle()} and somewhere between {@link #getMaxIdle()} and {@link #getMaxActive()}
+     * @return the minimum number of idle or established connections
+     */
+    public int getMinIdle();
+
+    /**
+     * The minimum number of established connections that should be kept in the pool at all times.
+     * The connection pool can shrink below this number if validation queries fail and connections get closed.
+     * Default value is derived from {@link #getInitialSize()} (also see {@link #setTestWhileIdle(boolean)}
+     * The idle pool will not shrink below this value during an eviction run, hence the number of actual connections
+     * can be between {@link #getMinIdle()} and somewhere between {@link #getMaxIdle()} and {@link #getMaxActive()}
+     *
+     * @param minIdle the minimum number of idle or established connections
+     */
+    public void setMinIdle(int minIdle);
+
+    /**
+     * Returns the name of the connection pool. By default a JVM unique random name is assigned.
+     * @return the name of the pool, should be unique in a JVM
+     */
+    public String getName();
+
+    /**
+     * Sets the name of the connection pool
+     * @param name the name of the pool, should be unique in a runtime JVM
+     */
+    public void setName(String name);
+
+    /**
+     * Property not used
+     * @return unknown value
+     */
+    public int getNumTestsPerEvictionRun();
+
+    /**
+     * Property not used
+     * @param numTestsPerEvictionRun parameter ignored.
+     */
+    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun);
+
+    /**
+     * Returns the password used when establishing connections to the database.
+     * @return the password in string format
+     */
+    public String getPassword();
+
+    /**
+     * Sets the password to establish the connection with.
+     * The password will be included as a database property with the name 'password'.
+     * @param password The password
+     * @see #getDbProperties()
+     */
+    public void setPassword(String password);
+
+    /**
+     * @see #getName()
+     * @return the pool name
+     */
+    public String getPoolName();
+
+    /**
+     * Returns the username used to establish the connection with
+     * @return the username used to establish the connection with
+     */
+    public String getUsername();
+
+    /**
+     * Sets the username used to establish the connection with
+     * It will also be a property called 'user' in the database properties.
+     * @param username The user name
+     * @see #getDbProperties()
+     */
+    public void setUsername(String username);
+
+
+    /**
+     * boolean flag to remove abandoned connections if they exceed the removeAbandonedTimout.
+     * If set to true a connection is considered abandoned and eligible for removal if it has
+     * been in use longer than the {@link #getRemoveAbandonedTimeout()} and the condition for
+     * {@link #getAbandonWhenPercentageFull()} is met.
+     * Setting this to true can recover db connections from applications that fail to close a connection.
+     * See also {@link #isLogAbandoned()} The default value is false.
+     * @return true if abandoned connections can be closed and expelled out of the pool
+     */
+    public boolean isRemoveAbandoned();
+
+    /**
+     * boolean flag to remove abandoned connections if they exceed the removeAbandonedTimout.
+     * If set to true a connection is considered abandoned and eligible for removal if it has
+     * been in use longer than the {@link #getRemoveAbandonedTimeout()} and the condition for
+     * {@link #getAbandonWhenPercentageFull()} is met.
+     * Setting this to true can recover db connections from applications that fail to close a connection.
+     * See also {@link #isLogAbandoned()} The default value is false.
+     * @param removeAbandoned set to true if abandoned connections can be closed and expelled out of the pool
+     */
+    public void setRemoveAbandoned(boolean removeAbandoned);
+
+    /**
+     * The time in seconds before a connection can be considered abandoned.
+     * The timer can be reset upon queries using an interceptor.
+     * @param removeAbandonedTimeout the time in seconds before a used connection can be considered abandoned
+     * @see org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
+     */
+    public void setRemoveAbandonedTimeout(int removeAbandonedTimeout);
+
+    /**
+     * The time in seconds before a connection can be considered abandoned.
+     * The timer can be reset upon queries using an interceptor.
+     * @see org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
+     * @return the time in seconds before a used connection can be considered abandoned
+     */
+    public int getRemoveAbandonedTimeout();
+
+    /**
+     * 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.
+     * NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
+     * Default value is false
+     * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+     * @return true if the connection is to be validated upon borrowing a connection from the pool
+     * @see #getValidationInterval()
+     */
+    public boolean isTestOnBorrow();
+
+    /**
+     * 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.
+     * NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
+     * Default value is false
+     * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+     * @param testOnBorrow set to true if validation should take place before a connection is handed out to the application
+     * @see #getValidationInterval()
+     */
+    public void setTestOnBorrow(boolean testOnBorrow);
+
+    /**
+     * The indication of whether objects will be validated after being returned to the pool.
+     * If the object fails to validate, it will be dropped from the pool.
+     * NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
+     * Default value is false
+     * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+     * @return true if validation should take place after a connection is returned to the pool
+     * @see #getValidationInterval()
+     */
+    public boolean isTestOnReturn();
+
+    /**
+     * The indication of whether objects will be validated after being returned to the pool.
+     * If the object fails to validate, it will be dropped from the pool.
+     * NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
+     * Default value is false
+     * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+     * @param testOnReturn true if validation should take place after a connection is returned to the pool
+     * @see #getValidationInterval()
+     */
+    public void setTestOnReturn(boolean testOnReturn);
+
+
+    /**
+     * Set to true if query validation should take place while the connection is idle.
+     * @return true if validation should take place during idle checks
+     * @see #setTimeBetweenEvictionRunsMillis(int)
+     */
+    public boolean isTestWhileIdle();
+
+    /**
+     * Set to true if query validation should take place while the connection is idle.
+     * @param testWhileIdle true if validation should take place during idle checks
+     * @see #setTimeBetweenEvictionRunsMillis(int)
+     */
+    public void setTestWhileIdle(boolean testWhileIdle);
+
+    /**
+     * The number of milliseconds to sleep between runs of the idle connection validation, abandoned cleaner
+     * and idle pool resizing. This value should not be set under 1 second.
+     * It dictates how often we check for idle, abandoned connections, and how often we validate idle connection and resize the idle pool.
+     * The default value is 5000 (5 seconds)
+     * @return the sleep time in between validations in milliseconds
+     */
+    public int getTimeBetweenEvictionRunsMillis();
+
+    /**
+     * The number of milliseconds to sleep between runs of the idle connection validation, abandoned cleaner
+     * and idle pool resizing. This value should not be set under 1 second.
+     * It dictates how often we check for idle, abandoned connections, and how often we validate idle connection and resize the idle pool.
+     * The default value is 5000 (5 seconds)
+     * @param timeBetweenEvictionRunsMillis the sleep time in between validations in milliseconds
+     */
+    public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis);
+
+    /**
+     * The URL used to connect to the database
+     * @return the configured URL for this connection pool
+     * @see java.sql.Driver#connect(String, Properties)
+     */
+    public String getUrl();
+
+    /**
+     * Sets the URL used to connect to the database
+     * @param url the configured URL for this connection pool
+     * @see java.sql.Driver#connect(String, Properties)
+     */
+    public void setUrl(String url);
+
+    /**
+     * The SQL query that will be used to validate connections from this
+     * pool before returning them to the caller or pool.
+     * If specified, this query does not have to return any data,
+     * it just can't throw a SQLException.
+     * The default value is null.
+     * Example values are SELECT 1(mysql),
+     * select 1 from dual(oracle),
+     * SELECT 1(MS Sql Server)
+     * @return the query used for validation or null if no validation is performed
+     */
+    public String getValidationQuery();
+
+    /**
+     * The SQL query that will be used to validate connections from this
+     * pool before returning them to the caller or pool.
+     * If specified, this query does not have to return any data,
+     * it just can't throw a SQLException.
+     * The default value is null.
+     * Example values are SELECT 1(mysql),
+     * select 1 from dual(oracle),
+     * SELECT 1(MS Sql Server)
+     * @param validationQuery the query used for validation or null if no validation is performed
+     */
+    public void setValidationQuery(String validationQuery);
+
+    /**
+     * The timeout in seconds before a connection validation queries fail.
+     * A value less than or equal to zero will disable this feature.  Defaults to -1.
+     * @return the timeout value in seconds
+     */
+    public int getValidationQueryTimeout();
+
+    /**
+     * The timeout in seconds before a connection validation queries fail.
+     * A value less than or equal to zero will disable this feature.  Defaults to -1.
+     * @param validationQueryTimeout The timeout value
+     */
+    public void setValidationQueryTimeout(int validationQueryTimeout);
+
+    /**
+     * Return the name of the optional validator class - may be null.
+     *
+     * @return the name of the optional validator class - may be null
+     */
+    public String getValidatorClassName();
+
+    /**
+     * Set the name for an optional validator class which will be used in place of test queries. If set to
+     * null, standard validation will be used.
+     *
+     * @param className the name of the optional validator class
+     */
+    public void setValidatorClassName(String className);
+
+    /**
+     * @return the optional validator object - may be null
+     */
+    public Validator getValidator();
+
+    /**
+     * Sets the validator object
+     * If this is a non null object, it will be used as a validator instead of the validationQuery
+     * If this is null, remove the usage of the validator.
+     * @param validator The validator object
+     */
+    public void setValidator(Validator validator);
+
+    /**
+     * avoid excess validation, only run validation at most at this frequency - time in milliseconds.
+     * If a connection is due for validation, but has been validated previously
+     * within this interval, it will not be validated again.
+     * The default value is 3000 (3 seconds).
+     * @return the validation interval in milliseconds
+     */
+    public long getValidationInterval();
+
+    /**
+     * avoid excess validation, only run validation at most at this frequency - time in milliseconds.
+     * If a connection is due for validation, but has been validated previously
+     * within this interval, it will not be validated again.
+     * The default value is 3000 (3 seconds).
+     * @param validationInterval the validation interval in milliseconds
+     */
+    public void setValidationInterval(long validationInterval);
+
+    /**
+     * A custom query to be run when a connection is first created. The default value is null.
+     * This query only runs once per connection, and that is when a new connection is established to the database.
+     * If this value is non null, it will replace the validation query during connection creation.
+     * @return the init SQL used to run against the DB or null if not set
+     */
+    public String getInitSQL();
+
+    /**
+     * A custom query to be run when a connection is first created. The default value is null.
+     * This query only runs once per connection, and that is when a new connection is established to the database.
+     * If this value is non null, it will replace the validation query during connection creation.
+     * @param initSQL the init SQL used to run against the DB or null if no query should be executed
+     */
+    public void setInitSQL(String initSQL);
+
+    /**
+     * Returns true if we should run the validation query when connecting to the database for the first time on a connection.
+     * Normally this is always set to false, unless one wants to use the validationQuery as an init query.
+     * @return true if we should run the validation query upon connect
+     */
+    public boolean isTestOnConnect();
+
+    /**
+     * Set to true if we should run the validation query when connecting to the database for the first time on a connection.
+     * Normally this is always set to false, unless one wants to use the validationQuery as an init query.
+     * Setting an {@link #setInitSQL(String)} will override this setting, as the init SQL will be used instead of the validation query
+     * @param testOnConnect set to true if we should run the validation query upon connect
+     */
+    public void setTestOnConnect(boolean testOnConnect);
+
+    /**
+     * A semicolon separated list of classnames extending {@link org.apache.tomcat.jdbc.pool.JdbcInterceptor} class.
+     * These interceptors will be inserted as an interceptor into the chain of operations on a java.sql.Connection object.
+     * Example interceptors are {@link org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer StatementFinalizer} to close all
+     * used statements during the session.
+     * {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer ResetAbandonedTimer} resets the timer upon every operation
+     * on the connection or a statement.
+     * {@link org.apache.tomcat.jdbc.pool.interceptor.ConnectionState ConnectionState} caches the auto commit, read only and catalog settings to avoid round trips to the DB.
+     * The default value is null.
+     * @return the interceptors that are used for connections.
+     * Example format: 'ConnectionState(useEquals=true,fast=yes);ResetAbandonedTimer'
+     */
+    public String getJdbcInterceptors();
+
+    /**
+     * A semicolon separated list of classnames extending {@link org.apache.tomcat.jdbc.pool.JdbcInterceptor} class.
+     * These interceptors will be inserted as an interceptor into the chain of operations on a java.sql.Connection object.
+     * Example interceptors are {@link org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer StatementFinalizer} to close all
+     * used statements during the session.
+     * {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer ResetAbandonedTimer} resets the timer upon every operation
+     * on the connection or a statement.
+     * {@link org.apache.tomcat.jdbc.pool.interceptor.ConnectionState ConnectionState} caches the auto commit, read only and catalog settings to avoid round trips to the DB.
+     * The default value is null.
+     * @param jdbcInterceptors the interceptors that are used for connections.
+     * Example format: 'ConnectionState(useEquals=true,fast=yes);ResetAbandonedTimer'
+     */
+    public void setJdbcInterceptors(String jdbcInterceptors);
+
+    /**
+     * Returns the {@link #getJdbcInterceptors()} as an array of objects with properties and the classes.
+     * @return an array of interceptors that have been configured
+     */
+    public InterceptorDefinition[] getJdbcInterceptorsAsArray();
+
+
+    /**
+     * If set to true, the connection pool creates a {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} object
+     * that can be registered with JMX to receive notifications and state about the pool.
+     * The ConnectionPool object doesn't register itself, as there is no way to keep a static non changing ObjectName across JVM restarts.
+     * @return true if the mbean object will be created upon startup.
+     */
+    public boolean isJmxEnabled();
+
+    /**
+     * If set to true, the connection pool creates a {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} object
+     * that can be registered with JMX to receive notifications and state about the pool.
+     * The ConnectionPool object doesn't register itself, as there is no way to keep a static non changing ObjectName across JVM restarts.
+     * @param jmxEnabled set to to if the mbean object should be created upon startup.
+     */
+    public void setJmxEnabled(boolean jmxEnabled);
+
+    /**
+     * Returns true if the pool sweeper is enabled for the connection pool.
+     * The pool sweeper is enabled if any settings that require async intervention in the pool are turned on
+     * <code>
+        boolean result = getTimeBetweenEvictionRunsMillis()&gt;0;
+        result = result &amp;&amp; (isRemoveAbandoned() &amp;&amp; getRemoveAbandonedTimeout()&gt;0);
+        result = result || (isTestWhileIdle() &amp;&amp; getValidationQuery()!=null);
+        return result;
+       </code>
+     *
+     * @return true if a background thread is or will be enabled for this pool
+     */
+    public boolean isPoolSweeperEnabled();
+
+    /**
+     * Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of
+     * <code>==</code> when comparing method names.
+     * This property does not apply to added interceptors as those are configured individually.
+     * The default value is <code>false</code>.
+     * @return true if pool uses {@link String#equals(Object)} instead of == when comparing method names on {@link java.sql.Connection} methods
+     */
+    public boolean isUseEquals();
+
+    /**
+     * Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of
+     * <code>==</code> when comparing method names.
+     * This property does not apply to added interceptors as those are configured individually.
+     * The default value is <code>false</code>.
+     * @param useEquals set to true if the pool should use {@link String#equals(Object)} instead of ==
+     * when comparing method names on {@link java.sql.Connection} methods
+     */
+    public void setUseEquals(boolean useEquals);
+
+    /**
+     * Time in milliseconds to keep this connection alive even when used.
+     * When a connection is returned to the pool, the pool will check to see if the
+     * ((now - time-when-connected) &gt; maxAge) has been reached, and if so,
+     * it closes the connection rather than returning it to the pool.
+     * The default value is 0, which implies that connections will be left open and no
+     * age check will be done upon returning the connection to the pool.
+     * This is a useful setting for database sessions that leak memory as it ensures that the session
+     * will have a finite life span.
+     * @return the time in milliseconds a connection will be open for when used
+     */
+    public long getMaxAge();
+
+    /**
+     * Time in milliseconds to keep this connection alive even when used.
+     * When a connection is returned to the pool, the pool will check to see if the
+     * ((now - time-when-connected) &gt; maxAge) has been reached, and if so,
+     * it closes the connection rather than returning it to the pool.
+     * The default value is 0, which implies that connections will be left open and no
+     * age check will be done upon returning the connection to the pool.
+     * This is a useful setting for database sessions that leak memory as it ensures that the session
+     * will have a finite life span.
+     * @param maxAge the time in milliseconds a connection will be open for when used
+     */
+    public void setMaxAge(long maxAge);
+
+    /**
+     * Return true if a lock should be used when operations are performed on the connection object.
+     * Should be set to false unless you plan to have a background thread of your own doing idle and abandon checking
+     * such as JMX clients. If the pool sweeper is enabled, then the lock will automatically be used regardless of this setting.
+     * @return true if a lock is used.
+     */
+    public boolean getUseLock();
+
+    /**
+     * Set to true if a lock should be used when operations are performed on the connection object.
+     * Should be set to false unless you plan to have a background thread of your own doing idle and abandon checking
+     * such as JMX clients. If the pool sweeper is enabled, then the lock will automatically be used regardless of this setting.
+     * @param useLock set to true if a lock should be used on connection operations
+     */
+    public void setUseLock(boolean useLock);
+
+    /**
+     * Similar to {@link #setRemoveAbandonedTimeout(int)} but instead of treating the connection
+     * as abandoned, and potentially closing the connection, this simply logs the warning if
+     * {@link #isLogAbandoned()} returns true. If this value is equal or less than 0, no suspect
+     * checking will be performed. Suspect checking only takes place if the timeout value is larger than 0 and
+     * the connection was not abandoned or if abandon check is disabled. If a connection is suspect a WARN message gets
+     * logged and a JMX notification gets sent once.
+     * @param seconds - the amount of time in seconds that has to pass before a connection is marked suspect.
+     */
+    public void setSuspectTimeout(int seconds);
+
+    /**
+     * Returns the time in seconds to pass before a connection is marked an abandoned suspect.
+     * Any value lesser than or equal to 0 means the check is disabled.
+     * @return Returns the time in seconds to pass before a connection is marked an abandoned suspect.
+     */
+    public int getSuspectTimeout();
+
+    /**
+     * Injects a datasource that will be used to retrieve/create connections.
+     * If a data source is set, the {@link PoolConfiguration#getUrl()} and {@link PoolConfiguration#getDriverClassName()} methods are ignored
+     * and not used by the pool. If the {@link PoolConfiguration#getUsername()} and {@link PoolConfiguration#getPassword()}
+     * values are set, the method {@link javax.sql.DataSource#getConnection(String, String)} method will be called instead of the
+     * {@link javax.sql.DataSource#getConnection()} method.
+     * If the data source implements {@link javax.sql.XADataSource} the methods
+     * {@link javax.sql.XADataSource#getXAConnection()} and {@link javax.sql.XADataSource#getXAConnection(String,String)}
+     * will be invoked.
+     * @param ds the {@link javax.sql.DataSource} to be used for creating connections to be pooled.
+     */
+    public void setDataSource(Object ds);
+
+    /**
+     * Returns a datasource, if one exists that is being used to create connections.
+     * This method will return null if the pool is using a {@link java.sql.Driver}
+     * @return the {@link javax.sql.DataSource} to be used for creating connections to be pooled or null if a Driver is used.
+     */
+    public Object getDataSource();
+
+    /**
+     * Configure the connection pool to use a DataSource according to {@link PoolConfiguration#setDataSource(Object)}
+     * But instead of injecting the object, specify the JNDI location.
+     * After a successful JNDI look, the {@link PoolConfiguration#getDataSource()} will not return null.
+     * @param jndiDS -the JNDI string @TODO specify the rules here.
+     */
+    public void setDataSourceJNDI(String jndiDS);
+
+    /**
+     * Returns the JNDI string configured for data source usage.
+     * @return the JNDI string or null if not set
+     */
+    public String getDataSourceJNDI();
+
+    /**
+     * Returns true if the call {@link DataSource#getConnection(String, String) getConnection(username,password)} is
+     * allowed. This is used for when the pool is used by an application accessing multiple schemas.
+     * There is a performance impact turning this option on.
+     * @return true if {@link DataSource#getConnection(String, String) getConnection(username,password)} is honored, false if it is ignored.
+     */
+    public boolean isAlternateUsernameAllowed();
+
+    /**
+     * Set to true if the call {@link DataSource#getConnection(String, String) getConnection(username,password)} is
+     * allowed and honored.. This is used for when the pool is used by an application accessing multiple schemas.
+     * There is a performance impact turning this option on, even when not used due to username checks.
+     * @param alternateUsernameAllowed - set true if {@link DataSource#getConnection(String, String) getConnection(username,password)} is honored,
+     * false if it is to be ignored.
+     */
+    public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed);
+    /**
+     * Set to true if you want the connection pool to commit any pending transaction when a connection is returned.
+     * The default value is false, as this could result in committing data.
+     * This parameter is only looked at if the {@link #getDefaultAutoCommit()} returns false
+     * @param commitOnReturn set to true if the pool should call {@link java.sql.Connection#commit()} when a connection is returned to the pool.
+     * Default is false
+     */
+    public void setCommitOnReturn(boolean commitOnReturn);
+
+    /**
+     * @see PoolConfiguration#setCommitOnReturn(boolean)
+     * @return <code>true</code> if the pool should commit when a connection is returned to it
+     */
+    public boolean getCommitOnReturn();
+
+    /**
+     * Set to true if you want the connection pool to rollback any pending transaction when a connection is returned.
+     * The default value is false, as this could result in committing data.
+     * This parameter is only looked at if the {@link #getDefaultAutoCommit()} returns false
+     * @param rollbackOnReturn set to true if the pool should call {@link java.sql.Connection#rollback()} when a connection is returned to the pool.
+     * Default is false
+     */
+    public void setRollbackOnReturn(boolean rollbackOnReturn);
+
+    /**
+     * @see PoolConfiguration#setRollbackOnReturn(boolean)
+     * @return <code>true</code> if the pool should rollback when a connection is returned to it
+     */
+    public boolean getRollbackOnReturn();
+
+    /**
+     * If set to <code>true</code>, the connection will be wrapped with facade that will disallow the connection to be used after
+     * {@link java.sql.Connection#close()} is called. If set to <code>true</code>, after {@link java.sql.Connection#close()} all calls except
+     * {@link java.sql.Connection#close()} and {@link java.sql.Connection#isClosed()} will throw an exception.
+     * @param useDisposableConnectionFacade <code>true</code> to use a facade
+     */
+    public void setUseDisposableConnectionFacade(boolean useDisposableConnectionFacade);
+    /**
+     * Returns <code>true</code> if this connection pool is configured to use a connection facade to prevent re-use of connection after
+     * {@link java.sql.Connection#close()} has been invoked
+     * @return <code>true</code> if {@link java.sql.Connection#close()} has been invoked.
+     */
+    public boolean getUseDisposableConnectionFacade();
+
+    /**
+     * Set to true if you wish that errors from validation should be logged as error messages.
+     * @param logValidationErrors set to true to log validation errors
+     */
+    public void setLogValidationErrors(boolean logValidationErrors);
+
+    /**
+     * Returns true if errors that happen during validation will be logged
+     * @return true if errors that happen during validation will be logged
+     */
+    public boolean getLogValidationErrors();
+
+    /**
+     * Returns true if the pool is configured to propagate interrupt state of a thread.
+     * A thread waiting for a connection, can have its wait interrupted, and by default
+     * will clear the interrupt flag and throw a {@link PoolExhaustedException}
+     * @return true if the pool is configured to propagate and not clear the thread interrupt state
+     */
+    public boolean getPropagateInterruptState();
+
+    /**
+     * Configure the pool to propagate interrupt state for interrupted threads waiting for a connection
+     * A thread waiting for a connection, can have its wait interrupted, and by default
+     * will clear the interrupt flag and throw a {@link PoolExhaustedException}
+     * If set to true, this behavior will change, while the {@link PoolExhaustedException} is still thrown, the threads interrupted state is still set.
+     * @param propagateInterruptState - set to true to not clear, but propagate, a threads interrupted state.
+     */
+    public void setPropagateInterruptState(boolean propagateInterruptState);
+
+    /**
+     * Set to true if you want to ignore error of connection creation while initializing the pool.
+     * Set to false if you want to fail the initialization of the pool by throwing exception.
+     * @param ignoreExceptionOnPreLoad set to true if you want to ignore error of connection creation while initializing the pool.
+     */
+    public void setIgnoreExceptionOnPreLoad(boolean ignoreExceptionOnPreLoad);
+
+    /**
+     * @return <code>true</code> to ignore exceptions
+     * @see PoolConfiguration#setIgnoreExceptionOnPreLoad(boolean)
+     */
+    public boolean isIgnoreExceptionOnPreLoad();
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolExhaustedException.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolExhaustedException.java
new file mode 100644 (file)
index 0000000..9352581
--- /dev/null
@@ -0,0 +1,76 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.sql.SQLException;
+
+public class PoolExhaustedException extends SQLException {
+
+    private static final long serialVersionUID = 3501536931777262475L;
+
+    public PoolExhaustedException() {
+    }
+
+    public PoolExhaustedException(String reason) {
+        super(reason);
+    }
+
+    public PoolExhaustedException(Throwable cause) {
+        super(cause);
+    }
+
+    public PoolExhaustedException(String reason, String SQLState) {
+        super(reason, SQLState);
+    }
+
+    public PoolExhaustedException(String reason, Throwable cause) {
+        super(reason, cause);
+    }
+
+    public PoolExhaustedException(String reason, String SQLState, int vendorCode) {
+        super(reason, SQLState, vendorCode);
+    }
+
+    public PoolExhaustedException(String reason, String sqlState, Throwable cause) {
+        super(reason, sqlState, cause);
+    }
+
+    public PoolExhaustedException(String reason, String sqlState, int vendorCode, Throwable cause) {
+        super(reason, sqlState, vendorCode, cause);
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
new file mode 100644 (file)
index 0000000..9d64c26
--- /dev/null
@@ -0,0 +1,1332 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+public class PoolProperties implements PoolConfiguration, Cloneable, Serializable {
+
+    private static final long serialVersionUID = -8519283440854213745L;
+    private static final Log log = LogFactory.getLog(PoolProperties.class);
+
+    public static final int DEFAULT_MAX_ACTIVE = 100;
+
+    protected static final AtomicInteger poolCounter = new AtomicInteger(0);
+    private volatile Properties dbProperties = new Properties();
+    private volatile String url = null;
+    private volatile String driverClassName = null;
+    private volatile Boolean defaultAutoCommit = null;
+    private volatile Boolean defaultReadOnly = null;
+    private volatile int defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION;
+    private volatile String defaultCatalog = null;
+    private volatile String connectionProperties;
+    private volatile int initialSize = 10;
+    private volatile int maxActive = DEFAULT_MAX_ACTIVE;
+    private volatile int maxIdle = maxActive;
+    private volatile int minIdle = initialSize;
+    private volatile int maxWait = 30000;
+    private volatile String validationQuery;
+    private volatile int validationQueryTimeout = -1;
+    private volatile String validatorClassName;
+    private volatile Validator validator;
+    private volatile boolean testOnBorrow = false;
+    private volatile boolean testOnReturn = false;
+    private volatile boolean testWhileIdle = false;
+    private volatile int timeBetweenEvictionRunsMillis = 5000;
+    private volatile int numTestsPerEvictionRun;
+    private volatile int minEvictableIdleTimeMillis = 60000;
+    private volatile boolean accessToUnderlyingConnectionAllowed = true;
+    private volatile boolean removeAbandoned = false;
+    private volatile int removeAbandonedTimeout = 60;
+    private volatile boolean logAbandoned = false;
+    private volatile String name = "Tomcat Connection Pool["+(poolCounter.addAndGet(1))+"-"+System.identityHashCode(PoolProperties.class)+"]";
+    private volatile String password;
+    private volatile String username;
+    private volatile long validationInterval = 3000;
+    private volatile boolean jmxEnabled = true;
+    private volatile String initSQL;
+    private volatile boolean testOnConnect =false;
+    private volatile String jdbcInterceptors=null;
+    private volatile boolean fairQueue = true;
+    private volatile boolean useEquals = true;
+    private volatile int abandonWhenPercentageFull = 0;
+    private volatile long maxAge = 0;
+    private volatile boolean useLock = false;
+    private volatile InterceptorDefinition[] interceptors = null;
+    private volatile int suspectTimeout = 0;
+    private volatile Object dataSource = null;
+    private volatile String dataSourceJNDI = null;
+    private volatile boolean alternateUsernameAllowed = false;
+    private volatile boolean commitOnReturn = false;
+    private volatile boolean rollbackOnReturn = false;
+    private volatile boolean useDisposableConnectionFacade = true;
+    private volatile boolean logValidationErrors = false;
+    private volatile boolean propagateInterruptState = false;
+    private volatile boolean ignoreExceptionOnPreLoad = false;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAbandonWhenPercentageFull(int percentage) {
+        if (percentage<0) abandonWhenPercentageFull = 0;
+        else if (percentage>100) abandonWhenPercentageFull = 100;
+        else abandonWhenPercentageFull = percentage;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getAbandonWhenPercentageFull() {
+        return abandonWhenPercentageFull;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isFairQueue() {
+        return fairQueue;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setFairQueue(boolean fairQueue) {
+        this.fairQueue = fairQueue;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAccessToUnderlyingConnectionAllowed() {
+        return accessToUnderlyingConnectionAllowed;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getConnectionProperties() {
+        return connectionProperties;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Properties getDbProperties() {
+        return dbProperties;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean isDefaultAutoCommit() {
+        return defaultAutoCommit;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getDefaultCatalog() {
+        return defaultCatalog;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean isDefaultReadOnly() {
+        return defaultReadOnly;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getDefaultTransactionIsolation() {
+        return defaultTransactionIsolation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getDriverClassName() {
+        return driverClassName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getInitialSize() {
+        return initialSize;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isLogAbandoned() {
+        return logAbandoned;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMaxActive() {
+        return maxActive;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMaxIdle() {
+        return maxIdle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMaxWait() {
+        return maxWait;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMinEvictableIdleTimeMillis() {
+        return minEvictableIdleTimeMillis;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getMinIdle() {
+        return minIdle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getNumTestsPerEvictionRun() {
+        return numTestsPerEvictionRun;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getPassword() {
+        return password;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getPoolName() {
+        return getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isRemoveAbandoned() {
+        return removeAbandoned;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getRemoveAbandonedTimeout() {
+        return removeAbandonedTimeout;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestOnBorrow() {
+        return testOnBorrow;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestOnReturn() {
+        return testOnReturn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestWhileIdle() {
+        return testWhileIdle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getTimeBetweenEvictionRunsMillis() {
+        return timeBetweenEvictionRunsMillis;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getUrl() {
+        return url;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getValidationQuery() {
+        return validationQuery;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getValidationQueryTimeout() {
+        return validationQueryTimeout;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValidationQueryTimeout(int validationQueryTimeout) {
+        this.validationQueryTimeout = validationQueryTimeout;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getValidatorClassName() {
+        return validatorClassName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Validator getValidator() {
+        return validator;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValidator(Validator validator) {
+        this.validator = validator;
+        if (validator!=null) {
+            this.validatorClassName = validator.getClass().getName();
+        } else {
+            this.validatorClassName = null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public long getValidationInterval() {
+        return validationInterval;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getInitSQL() {
+        return initSQL;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isTestOnConnect() {
+        return testOnConnect;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getJdbcInterceptors() {
+        return jdbcInterceptors;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
+        if (interceptors == null) {
+            if (jdbcInterceptors==null) {
+                interceptors = new InterceptorDefinition[0];
+            } else {
+                String[] interceptorValues = jdbcInterceptors.split(";");
+                InterceptorDefinition[] definitions = new InterceptorDefinition[interceptorValues.length+1];
+                //always add the trap interceptor to the mix
+                definitions[0] = new InterceptorDefinition(TrapException.class);
+                for (int i=0; i<interceptorValues.length; i++) {
+                    int propIndex = interceptorValues[i].indexOf('(');
+                    int endIndex = interceptorValues[i].indexOf(')');
+                    if (propIndex<0 || endIndex<0 || endIndex <= propIndex) {
+                        definitions[i+1] = new InterceptorDefinition(interceptorValues[i].trim());
+                    } else {
+                        String name = interceptorValues[i].substring(0,propIndex).trim();
+                        definitions[i+1] = new InterceptorDefinition(name);
+                        String propsAsString = interceptorValues[i].substring(propIndex+1, endIndex);
+                        String[] props = propsAsString.split(",");
+                        for (int j=0; j<props.length; j++) {
+                            int pidx = props[j].indexOf('=');
+                            String propName = props[j].substring(0,pidx).trim();
+                            String propValue = props[j].substring(pidx+1).trim();
+                            definitions[i+1].addProperty(new InterceptorProperty(propName,propValue));
+                        }
+                    }
+                }
+                interceptors = definitions;
+            }
+        }
+        return interceptors;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
+        // NOOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setConnectionProperties(String connectionProperties) {
+        this.connectionProperties = connectionProperties;
+        getProperties(connectionProperties, getDbProperties());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDbProperties(Properties dbProperties) {
+        this.dbProperties = dbProperties;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
+        this.defaultAutoCommit = defaultAutoCommit;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultCatalog(String defaultCatalog) {
+        this.defaultCatalog = defaultCatalog;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultReadOnly(Boolean defaultReadOnly) {
+        this.defaultReadOnly = defaultReadOnly;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
+        this.defaultTransactionIsolation = defaultTransactionIsolation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setDriverClassName(String driverClassName) {
+        this.driverClassName = driverClassName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setInitialSize(int initialSize) {
+        this.initialSize = initialSize;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setLogAbandoned(boolean logAbandoned) {
+        this.logAbandoned = logAbandoned;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxActive(int maxActive) {
+        this.maxActive = maxActive;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxIdle(int maxIdle) {
+        this.maxIdle = maxIdle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxWait(int maxWait) {
+        this.maxWait = maxWait;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMinIdle(int minIdle) {
+        this.minIdle = minIdle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setRemoveAbandoned(boolean removeAbandoned) {
+        this.removeAbandoned = removeAbandoned;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
+        this.removeAbandonedTimeout = removeAbandonedTimeout;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestOnBorrow(boolean testOnBorrow) {
+        this.testOnBorrow = testOnBorrow;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestWhileIdle(boolean testWhileIdle) {
+        this.testWhileIdle = testWhileIdle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestOnReturn(boolean testOnReturn) {
+        this.testOnReturn = testOnReturn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTimeBetweenEvictionRunsMillis(int
+                                                 timeBetweenEvictionRunsMillis) {
+        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidationInterval(long validationInterval) {
+        this.validationInterval = validationInterval;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidationQuery(String validationQuery) {
+        this.validationQuery = validationQuery;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidatorClassName(String className) {
+        this.validatorClassName = className;
+
+        validator = null;
+
+        if (className == null) {
+            return;
+        }
+
+        try {
+            @SuppressWarnings("unchecked")
+            Class<Validator> validatorClass = (Class<Validator>)ClassLoaderUtil.loadClass(
+                className,
+                PoolProperties.class.getClassLoader(),
+                Thread.currentThread().getContextClassLoader()
+            );
+            validator = validatorClass.newInstance();
+        } catch (ClassNotFoundException e) {
+            log.warn("The class "+className+" cannot be found.", e);
+        } catch (ClassCastException e) {
+            log.warn("The class "+className+" does not implement the Validator interface.", e);
+        } catch (InstantiationException e) {
+            log.warn("An object of class "+className+" cannot be instantiated. Make sure that "+
+                     "it includes an implicit or explicit no-arg constructor.", e);
+        } catch (IllegalAccessException e) {
+            log.warn("The class "+className+" or its no-arg constructor are inaccessible.", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setInitSQL(String initSQL) {
+        this.initSQL = initSQL!=null && initSQL.trim().length()>0 ? initSQL : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setTestOnConnect(boolean testOnConnect) {
+        this.testOnConnect = testOnConnect;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setJdbcInterceptors(String jdbcInterceptors) {
+        this.jdbcInterceptors = jdbcInterceptors;
+        this.interceptors = null;
+    }
+
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("ConnectionPool[");
+        try {
+            String[] fields = DataSourceFactory.ALL_PROPERTIES;
+            for (String field: fields) {
+                final String[] prefix = new String[] {"get","is"};
+                for (int j=0; j<prefix.length; j++) {
+
+                    String name = prefix[j]
+                            + field.substring(0, 1).toUpperCase(Locale.ENGLISH)
+                            + field.substring(1);
+                    Method m = null;
+                    try {
+                        m = getClass().getMethod(name);
+                    }catch (NoSuchMethodException nm) {
+                        continue;
+                    }
+                    buf.append(field);
+                    buf.append("=");
+                    if (DataSourceFactory.PROP_PASSWORD.equals(field)) {
+                        buf.append("********");
+                    } else {
+                        buf.append(m.invoke(this, new Object[0]));
+                    }
+                    buf.append("; ");
+                    break;
+                }
+            }
+        }catch (Exception x) {
+            //shouldn't happen
+            log.debug("toString() call failed", x);
+        }
+        return buf.toString();
+    }
+
+    public static int getPoolCounter() {
+        return poolCounter.get();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isJmxEnabled() {
+        return jmxEnabled;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setJmxEnabled(boolean jmxEnabled) {
+        this.jmxEnabled = jmxEnabled;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean getDefaultAutoCommit() {
+        return defaultAutoCommit;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Boolean getDefaultReadOnly() {
+        return defaultReadOnly;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getSuspectTimeout() {
+        return this.suspectTimeout;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setSuspectTimeout(int seconds) {
+        this.suspectTimeout = seconds;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isPoolSweeperEnabled() {
+        boolean timer = getTimeBetweenEvictionRunsMillis()>0;
+        boolean result = timer && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
+        result = result || (timer && getSuspectTimeout()>0);
+        result = result || (timer && isTestWhileIdle() && getValidationQuery()!=null);
+        result = result || (timer && getMinEvictableIdleTimeMillis()>0);
+        return result;
+    }
+
+
+    public static class InterceptorDefinition implements Serializable {
+        private static final long serialVersionUID = 1L;
+        protected String className;
+        protected Map<String,InterceptorProperty> properties = new HashMap<>();
+        protected volatile Class<?> clazz = null;
+        public InterceptorDefinition(String className) {
+            this.className = className;
+        }
+
+        public InterceptorDefinition(Class<?> cl) {
+            this(cl.getName());
+            clazz = cl;
+        }
+
+        public String getClassName() {
+            return className;
+        }
+        public void addProperty(String name, String value) {
+            InterceptorProperty p = new InterceptorProperty(name,value);
+            addProperty(p);
+        }
+
+        public void addProperty(InterceptorProperty p) {
+            properties.put(p.getName(), p);
+        }
+
+        public Map<String,InterceptorProperty> getProperties() {
+            return properties;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Class<? extends JdbcInterceptor> getInterceptorClass() throws ClassNotFoundException {
+            if (clazz==null) {
+                if (getClassName().indexOf('.')<0) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Loading interceptor class:"+PoolConfiguration.PKG_PREFIX+getClassName());
+                    }
+                    clazz = ClassLoaderUtil.loadClass(
+                        PoolConfiguration.PKG_PREFIX+getClassName(),
+                        PoolProperties.class.getClassLoader(),
+                        Thread.currentThread().getContextClassLoader()
+                    );
+                } else {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Loading interceptor class:"+getClassName());
+                    }
+                    clazz = ClassLoaderUtil.loadClass(
+                        getClassName(),
+                        PoolProperties.class.getClassLoader(),
+                        Thread.currentThread().getContextClassLoader()
+                    );
+                }
+            }
+            return (Class<? extends JdbcInterceptor>)clazz;
+        }
+    }
+
+    public static class InterceptorProperty implements Serializable {
+        private static final long serialVersionUID = 1L;
+        String name;
+        String value;
+        public InterceptorProperty(String name, String value) {
+            assert(name!=null);
+            this.name = name;
+            this.value = value;
+        }
+        public String getName() {
+            return name;
+        }
+        public String getValue() {
+            return value;
+        }
+
+        public boolean getValueAsBoolean(boolean def) {
+            if (value==null) return def;
+            if ("true".equals(value)) return true;
+            if ("false".equals(value)) return false;
+            return def;
+        }
+
+        public int getValueAsInt(int def) {
+            if (value==null) return def;
+            try {
+                int v = Integer.parseInt(value);
+                return v;
+            }catch (NumberFormatException nfe) {
+                return def;
+            }
+        }
+
+        public long getValueAsLong(long def) {
+            if (value==null) return def;
+            try {
+                return Long.parseLong(value);
+            }catch (NumberFormatException nfe) {
+                return def;
+            }
+        }
+
+        public byte getValueAsByte(byte def) {
+            if (value==null) return def;
+            try {
+                return Byte.parseByte(value);
+            }catch (NumberFormatException nfe) {
+                return def;
+            }
+        }
+
+        public short getValueAsShort(short def) {
+            if (value==null) return def;
+            try {
+                return Short.parseShort(value);
+            }catch (NumberFormatException nfe) {
+                return def;
+            }
+        }
+
+        public float getValueAsFloat(float def) {
+            if (value==null) return def;
+            try {
+                return Float.parseFloat(value);
+            }catch (NumberFormatException nfe) {
+                return def;
+            }
+        }
+
+        public double getValueAsDouble(double def) {
+            if (value==null) return def;
+            try {
+                return Double.parseDouble(value);
+            }catch (NumberFormatException nfe) {
+                return def;
+            }
+        }
+
+        public char getValueAschar(char def) {
+            if (value==null) return def;
+            try {
+                return value.charAt(0);
+            }catch (StringIndexOutOfBoundsException nfe) {
+                return def;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o==this) return true;
+            if (o instanceof InterceptorProperty) {
+                InterceptorProperty other = (InterceptorProperty)o;
+                return other.name.equals(this.name);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean isUseEquals() {
+        return useEquals;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUseEquals(boolean useEquals) {
+        this.useEquals = useEquals;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public long getMaxAge() {
+        return maxAge;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setMaxAge(long maxAge) {
+        this.maxAge = maxAge;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public boolean getUseLock() {
+        return useLock;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setUseLock(boolean useLock) {
+        this.useLock = useLock;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDataSource(Object ds) {
+        if (ds instanceof DataSourceProxy) {
+            throw new IllegalArgumentException("Layered pools are not allowed.");
+        }
+        this.dataSource = ds;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object getDataSource() {
+        return dataSource;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDataSourceJNDI(String jndiDS) {
+        this.dataSourceJNDI = jndiDS;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getDataSourceJNDI() {
+        return this.dataSourceJNDI;
+    }
+
+
+    public static Properties getProperties(String propText, Properties props) {
+        if (props==null) props = new Properties();
+        if (propText != null) {
+            try {
+                props.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
+            }catch (IOException x) {
+                throw new RuntimeException(x);
+            }
+        }
+        return props;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAlternateUsernameAllowed() {
+        return alternateUsernameAllowed;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
+        this.alternateUsernameAllowed = alternateUsernameAllowed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setCommitOnReturn(boolean commitOnReturn) {
+        this.commitOnReturn = commitOnReturn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getCommitOnReturn() {
+        return this.commitOnReturn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setRollbackOnReturn(boolean rollbackOnReturn) {
+        this.rollbackOnReturn = rollbackOnReturn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getRollbackOnReturn() {
+        return this.rollbackOnReturn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUseDisposableConnectionFacade(boolean useDisposableConnectionFacade) {
+        this.useDisposableConnectionFacade = useDisposableConnectionFacade;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getUseDisposableConnectionFacade() {
+        return useDisposableConnectionFacade;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setLogValidationErrors(boolean logValidationErrors) {
+        this.logValidationErrors = logValidationErrors;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getLogValidationErrors() {
+        return this.logValidationErrors;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getPropagateInterruptState() {
+        return propagateInterruptState;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setPropagateInterruptState(boolean propagateInterruptState) {
+        this.propagateInterruptState = propagateInterruptState;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isIgnoreExceptionOnPreLoad() {
+        return ignoreExceptionOnPreLoad;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setIgnoreExceptionOnPreLoad(boolean ignoreExceptionOnPreLoad) {
+        this.ignoreExceptionOnPreLoad = ignoreExceptionOnPreLoad;
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException {
+        // TODO Auto-generated method stub
+        return super.clone();
+    }
+
+
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java
new file mode 100644 (file)
index 0000000..cd0d3b2
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.util.Properties;
+
+public class PoolUtilities {
+
+    public static final String PROP_USER = "user";
+
+    public static final String PROP_PASSWORD = "password";
+
+    public static Properties clone(Properties p) {
+        Properties c = new Properties();
+        c.putAll(p);
+        return c;
+    }
+
+    public static Properties cloneWithoutPassword(Properties p) {
+        Properties result = clone(p);
+        result.remove(PROP_PASSWORD);
+        return result;
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
new file mode 100644 (file)
index 0000000..b704c7f
--- /dev/null
@@ -0,0 +1,795 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
+
+import com.mysql.jdbc.Driver;
+
+/**
+ * Represents a pooled connection
+ * and holds a reference to the {@link java.sql.Connection} object
+ * @version 1.0
+ */
+public class PooledConnection {
+    /**
+     * Logger
+     */
+    private static final Log log = LogFactory.getLog(PooledConnection.class);
+
+    public static final String PROP_USER = PoolUtilities.PROP_USER;
+
+    public static final String PROP_PASSWORD = PoolUtilities.PROP_PASSWORD;
+
+    /**
+     * Validate when connection is borrowed flag
+     */
+    public static final int VALIDATE_BORROW = 1;
+    /**
+     * Validate when connection is returned flag
+     */
+    public static final int VALIDATE_RETURN = 2;
+    /**
+     * Validate when connection is idle flag
+     */
+    public static final int VALIDATE_IDLE = 3;
+    /**
+     * Validate when connection is initialized flag
+     */
+    public static final int VALIDATE_INIT = 4;
+    /**
+     * The properties for the connection pool
+     */
+    protected PoolConfiguration poolProperties;
+    /**
+     * The underlying database connection
+     */
+    private volatile java.sql.Connection connection;
+
+    /**
+     * If using a XAConnection underneath.
+     */
+    protected volatile javax.sql.XAConnection xaConnection;
+    /**
+     * When we track abandon traces, this string holds the thread dump
+     */
+    private String abandonTrace = null;
+    /**
+     * Timestamp the connection was last 'touched' by the pool
+     */
+    private volatile long timestamp;
+    /**
+     * Lock for this connection only
+     */
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
+    /**
+     * Set to true if this connection has been discarded by the pool
+     */
+    private volatile boolean discarded = false;
+    /**
+     * The Timestamp when the last time the connect() method was called successfully
+     */
+    private volatile long lastConnected = -1;
+    /**
+     * timestamp to keep track of validation intervals
+     */
+    private volatile long lastValidated = System.currentTimeMillis();
+    /**
+     * The parent
+     */
+    protected ConnectionPool parent;
+
+    private HashMap<Object, Object> attributes = new HashMap<>();
+
+    private volatile long connectionVersion=0;
+
+    /**
+     * Weak reference to cache the list of interceptors for this connection
+     * so that we don't create a new list of interceptors each time we borrow
+     * the connection
+     */
+    private volatile JdbcInterceptor handler = null;
+
+    private AtomicBoolean released = new AtomicBoolean(false);
+
+    private volatile boolean suspect = false;
+
+    private java.sql.Driver driver = null;
+
+    /**
+     * Constructor
+     * @param prop - pool properties
+     * @param parent - the parent connection pool
+     */
+    public PooledConnection(PoolConfiguration prop, ConnectionPool parent) {
+        poolProperties = prop;
+        this.parent = parent;
+        connectionVersion = parent.getPoolVersion();
+    }
+
+    public long getConnectionVersion() {
+        return connectionVersion;
+    }
+
+    /**
+     * @deprecated use {@link #shouldForceReconnect(String, String)}
+     * method kept since it was public, to avoid changing interface.
+     * @param username The user name
+     * @param password The password
+     * @return <code>true</code>if the pool does not need to reconnect
+     */
+    @Deprecated
+    public boolean checkUser(String username, String password) {
+        return !shouldForceReconnect(username, password);
+    }
+
+    /**
+     * Returns true if we must force reconnect based on credentials passed in.
+     * Returns false if {@link PoolConfiguration#isAlternateUsernameAllowed()} method returns false.
+     * Returns false if the username/password has not changed since this connection was connected
+     * @param username the username you wish to connect with, pass in null to accept the default username from {@link PoolConfiguration#getUsername()}
+     * @param password the password you wish to connect with, pass in null to accept the default username from {@link org.apache.tomcat.jdbc.pool.PoolConfiguration#getPassword()}
+     * @return true is the pool must reconnect
+     */
+    public boolean shouldForceReconnect(String username, String password) {
+
+        if (!getPoolProperties().isAlternateUsernameAllowed()) return false;
+
+        if (username==null) username = poolProperties.getUsername();
+        if (password==null) password = poolProperties.getPassword();
+
+        String storedUsr = (String)getAttributes().get(PROP_USER);
+        String storedPwd = (String)getAttributes().get(PROP_PASSWORD);
+
+        boolean noChangeInCredentials = (username==null && storedUsr==null);
+        noChangeInCredentials = (noChangeInCredentials || (username!=null && username.equals(storedUsr)));
+
+        noChangeInCredentials = noChangeInCredentials && ((password==null && storedPwd==null) || (password!=null && password.equals(storedPwd)));
+
+        if (username==null)  getAttributes().remove(PROP_USER); else getAttributes().put(PROP_USER, username);
+        if (password==null)  getAttributes().remove(PROP_PASSWORD); else getAttributes().put(PROP_PASSWORD, password);
+
+        return !noChangeInCredentials;
+    }
+
+    /**
+     * Connects the underlying connection to the database.
+     * @throws SQLException if the method {@link #release()} has been called.
+     * @throws SQLException if driver instantiation fails
+     * @throws SQLException if a call to {@link java.sql.Driver#connect(String, java.util.Properties)} fails.
+     * @throws SQLException if default properties are configured and a call to
+     * {@link java.sql.Connection#setAutoCommit(boolean)}, {@link java.sql.Connection#setCatalog(String)},
+     * {@link java.sql.Connection#setTransactionIsolation(int)} or {@link java.sql.Connection#setReadOnly(boolean)} fails.
+     */
+    public void connect() throws SQLException {
+        if (released.get()) throw new SQLException("A connection once released, can't be reestablished.");
+        if (connection != null) {
+            try {
+                this.disconnect(false);
+            } catch (Exception x) {
+                log.debug("Unable to disconnect previous connection.", x);
+            } //catch
+        } //end if
+        if (poolProperties.getDataSource()==null && poolProperties.getDataSourceJNDI()!=null) {
+            //TODO lookup JNDI name
+        }
+
+        if (poolProperties.getDataSource()!=null) {
+            connectUsingDataSource();
+        } else {
+            connectUsingDriver();
+        }
+
+        //set up the default state, unless we expect the interceptor to do it
+        if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0 ||
+                poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getSimpleName())<0) {
+            if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
+            if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());
+            if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());
+            if (poolProperties.getDefaultCatalog()!=null) connection.setCatalog(poolProperties.getDefaultCatalog());
+        }
+        this.discarded = false;
+        this.lastConnected = System.currentTimeMillis();
+    }
+
+    protected void connectUsingDataSource() throws SQLException {
+        String usr = null;
+        String pwd = null;
+        if (getAttributes().containsKey(PROP_USER)) {
+            usr = (String) getAttributes().get(PROP_USER);
+        } else {
+            usr = poolProperties.getUsername();
+            getAttributes().put(PROP_USER, usr);
+        }
+        if (getAttributes().containsKey(PROP_PASSWORD)) {
+            pwd = (String) getAttributes().get(PROP_PASSWORD);
+        } else {
+            pwd = poolProperties.getPassword();
+            getAttributes().put(PROP_PASSWORD, pwd);
+        }
+        if (poolProperties.getDataSource() instanceof javax.sql.XADataSource) {
+            javax.sql.XADataSource xds = (javax.sql.XADataSource)poolProperties.getDataSource();
+            if (usr!=null && pwd!=null) {
+                xaConnection = xds.getXAConnection(usr, pwd);
+                connection = xaConnection.getConnection();
+            } else {
+                xaConnection = xds.getXAConnection();
+                connection = xaConnection.getConnection();
+            }
+        } else if (poolProperties.getDataSource() instanceof javax.sql.DataSource){
+            javax.sql.DataSource ds = (javax.sql.DataSource)poolProperties.getDataSource();
+            if (usr!=null && pwd!=null) {
+                connection = ds.getConnection(usr, pwd);
+            } else {
+                connection = ds.getConnection();
+            }
+        } else if (poolProperties.getDataSource() instanceof javax.sql.ConnectionPoolDataSource){
+            javax.sql.ConnectionPoolDataSource ds = (javax.sql.ConnectionPoolDataSource)poolProperties.getDataSource();
+            if (usr!=null && pwd!=null) {
+                connection = ds.getPooledConnection(usr, pwd).getConnection();
+            } else {
+                connection = ds.getPooledConnection().getConnection();
+            }
+        } else {
+            throw new SQLException("DataSource is of unknown class:"+(poolProperties.getDataSource()!=null?poolProperties.getDataSource().getClass():"null"));
+        }
+    }
+    protected void connectUsingDriver() throws SQLException {
+       
+               try {
+                       Class.forName("com.mysql.jdbc.Driver") ;
+                       Driver dr = new com.mysql.jdbc.Driver();
+                       if(dr == null)
+                               log.warn("Driver NOT CREATED");
+               } catch (ClassNotFoundException e) {
+                       log.warn("Driver NOT CREATED", e);
+               }
+
+        try {
+            if (driver==null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Instantiating driver using class: "+poolProperties.getDriverClassName()+" [url="+poolProperties.getUrl()+"]");
+                }
+                if (poolProperties.getDriverClassName()==null) {
+                    //rely on DriverManager
+                    log.warn("Not loading a JDBC driver as driverClassName property is null.");
+                } else {
+                    driver = (java.sql.Driver)
+                        ClassLoaderUtil.loadClass(
+                            poolProperties.getDriverClassName(),
+                            PooledConnection.class.getClassLoader(),
+                            Thread.currentThread().getContextClassLoader()
+                        ).newInstance();
+                }
+            }
+        } catch (java.lang.Exception cn) {
+            if (log.isDebugEnabled()) {
+                log.debug("Unable to instantiate JDBC driver.", cn);
+            }
+            SQLException ex = new SQLException(cn.getMessage());
+            ex.initCause(cn);
+            throw ex;
+        }
+        String driverURL = poolProperties.getUrl();
+        String usr = null;
+        String pwd = null;
+        if (getAttributes().containsKey(PROP_USER)) {
+            usr = (String) getAttributes().get(PROP_USER);
+        } else {
+            usr = poolProperties.getUsername();
+            getAttributes().put(PROP_USER, usr);
+        }
+        if (getAttributes().containsKey(PROP_PASSWORD)) {
+            pwd = (String) getAttributes().get(PROP_PASSWORD);
+        } else {
+            pwd = poolProperties.getPassword();
+            getAttributes().put(PROP_PASSWORD, pwd);
+        }
+        Properties properties = PoolUtilities.clone(poolProperties.getDbProperties());
+        if (usr != null) properties.setProperty(PROP_USER, usr);
+        if (pwd != null) properties.setProperty(PROP_PASSWORD, pwd);
+
+        try {
+            if (driver==null) {
+                connection = DriverManager.getConnection(driverURL, properties);
+            } else {
+                connection = driver.connect(driverURL, properties);
+            }
+        } catch (Exception x) {
+            if (log.isDebugEnabled()) {
+                log.debug("Unable to connect to database.", x);
+            }
+            if (parent.jmxPool!=null) {
+                parent.jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_CONNECT,
+                        ConnectionPool.getStackTrace(x));
+            }
+            if (x instanceof SQLException) {
+                throw (SQLException)x;
+            } else {
+                SQLException ex = new SQLException(x.getMessage());
+                ex.initCause(x);
+                throw ex;
+            }
+        }
+        if (connection==null) {
+            throw new SQLException("Driver:"+driver+" returned null for URL:"+driverURL);
+        }
+    }
+
+    /**
+     *
+     * @return true if connect() was called successfully and disconnect has not yet been called
+     */
+    public boolean isInitialized() {
+        return connection!=null;
+    }
+
+    /**
+     * Returns true if the connection has been connected more than
+     * {@link PoolConfiguration#getMaxAge()} milliseconds. false otherwise.
+     * @return Returns true if the connection has been connected more than
+     * {@link PoolConfiguration#getMaxAge()} milliseconds. false otherwise.
+     */
+    public boolean isMaxAgeExpired() {
+        if (getPoolProperties().getMaxAge()>0 ) {
+            return (System.currentTimeMillis() - getLastConnected()) > getPoolProperties().getMaxAge();
+        } else {
+            return false;
+        }
+    }
+    /**
+     * Issues a call to {@link #disconnect(boolean)} with the argument false followed by a call to
+     * {@link #connect()}
+     * @throws SQLException if the call to {@link #connect()} fails.
+     */
+    public void reconnect() throws SQLException {
+        this.disconnect(false);
+        this.connect();
+    } //reconnect
+
+    /**
+     * Disconnects the connection. All exceptions are logged using debug level.
+     * @param finalize if set to true, a call to {@link ConnectionPool#finalize(PooledConnection)} is called.
+     */
+    private void disconnect(boolean finalize) {
+        if (isDiscarded() && connection == null) {
+            return;
+        }
+        setDiscarded(true);
+        if (connection != null) {
+            try {
+                parent.disconnectEvent(this, finalize);
+                if (xaConnection == null) {
+                    connection.close();
+                } else {
+                    xaConnection.close();
+                }
+            }catch (Exception ignore) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Unable to close underlying SQL connection",ignore);
+                }
+            }
+        }
+        connection = null;
+        xaConnection = null;
+        lastConnected = -1;
+        if (finalize) parent.finalize(this);
+    }
+
+
+//============================================================================
+//
+//============================================================================
+
+    /**
+     * Returns abandon timeout in milliseconds
+     * @return abandon timeout in milliseconds
+     */
+    public long getAbandonTimeout() {
+        if (poolProperties.getRemoveAbandonedTimeout() <= 0) {
+            return Long.MAX_VALUE;
+        } else {
+            return poolProperties.getRemoveAbandonedTimeout() * 1000L;
+        } //end if
+    }
+
+    /**
+     * Returns <code>true</code> if the connection pool is configured
+     * to do validation for a certain action.
+     * @param action The validation action
+     */
+    private boolean doValidate(int action) {
+        if (action == PooledConnection.VALIDATE_BORROW &&
+            poolProperties.isTestOnBorrow())
+            return true;
+        else if (action == PooledConnection.VALIDATE_RETURN &&
+                 poolProperties.isTestOnReturn())
+            return true;
+        else if (action == PooledConnection.VALIDATE_IDLE &&
+                 poolProperties.isTestWhileIdle())
+            return true;
+        else if (action == PooledConnection.VALIDATE_INIT &&
+                 poolProperties.isTestOnConnect())
+            return true;
+        else if (action == PooledConnection.VALIDATE_INIT &&
+                 poolProperties.getInitSQL()!=null)
+           return true;
+        else
+            return false;
+    }
+
+    /**
+     * Returns <code>true</code> if the object is still valid. if not
+     * the pool will call the getExpiredAction() and follow up with one
+     * of the four expired methods
+     * @param validateAction The value
+     * @return <code>true</code> if the connection is valid
+     */
+    public boolean validate(int validateAction) {
+        return validate(validateAction,null);
+    }
+
+    /**
+     * Validates a connection.
+     * @param validateAction the action used. One of {@link #VALIDATE_BORROW}, {@link #VALIDATE_IDLE},
+     * {@link #VALIDATE_INIT} or {@link #VALIDATE_RETURN}
+     * @param sql the SQL to be used during validation. If the {@link PoolConfiguration#setInitSQL(String)} has been called with a non null
+     * value and the action is {@link #VALIDATE_INIT} the init SQL will be used for validation.
+     *
+     * @return true if the connection was validated successfully. It returns true even if validation was not performed, such as when
+     * {@link PoolConfiguration#setValidationInterval(long)} has been called with a positive value.
+     * <p>
+     * false if the validation failed. The caller should close the connection if false is returned since a session could have been left in
+     * an unknown state during initialization.
+     */
+    public boolean validate(int validateAction,String sql) {
+        if (this.isDiscarded()) {
+            return false;
+        }
+
+        if (!doValidate(validateAction)) {
+            //no validation required, no init sql and props not set
+            return true;
+        }
+
+        //Don't bother validating if already have recently enough
+        long now = System.currentTimeMillis();
+        if (validateAction!=VALIDATE_INIT &&
+            poolProperties.getValidationInterval() > 0 &&
+            (now - this.lastValidated) <
+            poolProperties.getValidationInterval()) {
+            return true;
+        }
+
+        if (poolProperties.getValidator() != null) {
+            if (poolProperties.getValidator().validate(connection, validateAction)) {
+                this.lastValidated = now;
+                return true;
+            } else {
+                if (getPoolProperties().getLogValidationErrors()) {
+                    log.error("Custom validation through "+poolProperties.getValidator()+" failed.");
+                }
+                return false;
+            }
+        }
+
+        String query = sql;
+
+        if (validateAction == VALIDATE_INIT && poolProperties.getInitSQL() != null) {
+            query = poolProperties.getInitSQL();
+        }
+
+        if (query == null) {
+            query = poolProperties.getValidationQuery();
+        }
+
+        if (query == null) {
+            int validationQueryTimeout = poolProperties.getValidationQueryTimeout();
+            if (validationQueryTimeout < 0) validationQueryTimeout = 0;
+            try {
+                if (connection.isValid(validationQueryTimeout)) {
+                    this.lastValidated = now;
+                    return true;
+                } else {
+                    if (getPoolProperties().getLogValidationErrors()) {
+                        log.error("isValid() returned false.");
+                    }
+                    return false;
+                }
+            } catch (SQLException e) {
+                if (getPoolProperties().getLogValidationErrors()) {
+                    log.error("isValid() failed.", e);
+                } else if (log.isDebugEnabled()) {
+                    log.debug("isValid() failed.", e);
+                }
+                return false;
+            }
+        }
+
+        Statement stmt = null;
+        try {
+            stmt = connection.createStatement();
+
+            int validationQueryTimeout = poolProperties.getValidationQueryTimeout();
+            if (validationQueryTimeout > 0) {
+                stmt.setQueryTimeout(validationQueryTimeout);
+            }
+
+            stmt.execute(query);
+            stmt.close();
+            this.lastValidated = now;
+            return true;
+        } catch (Exception ex) {
+            if (getPoolProperties().getLogValidationErrors()) {
+                log.warn("SQL Validation error", ex);
+            } else if (log.isDebugEnabled()) {
+                log.debug("Unable to validate object:",ex);
+            }
+            if (stmt!=null)
+                try { stmt.close();} catch (Exception ignore2){/*NOOP*/}
+        }
+        return false;
+    } //validate
+
+    /**
+     * The time limit for how long the object
+     * can remain unused before it is released
+     * @return {@link PoolConfiguration#getMinEvictableIdleTimeMillis()}
+     */
+    public long getReleaseTime() {
+        return this.poolProperties.getMinEvictableIdleTimeMillis();
+    }
+
+    /**
+     * This method is called if (Now - timeCheckedIn &gt; getReleaseTime())
+     * This method disconnects the connection, logs an error in debug mode if it happens
+     * then sets the {@link #released} flag to false. Any attempts to connect this cached object again
+     * will fail per {@link #connect()}
+     * The connection pool uses the atomic return value to decrement the pool size counter.
+     * @return true if this is the first time this method has been called. false if this method has been called before.
+     */
+    public boolean release() {
+        try {
+            disconnect(true);
+        } catch (Exception x) {
+            if (log.isDebugEnabled()) {
+                log.debug("Unable to close SQL connection",x);
+            }
+        }
+        return released.compareAndSet(false, true);
+
+    }
+
+    /**
+     * The pool will set the stack trace when it is check out and
+     * checked in
+     * @param trace the stack trace for this connection
+     */
+
+    public void setStackTrace(String trace) {
+        abandonTrace = trace;
+    }
+
+    /**
+     * Returns the stack trace from when this connection was borrowed. Can return null if no stack trace was set.
+     * @return the stack trace or null of no trace was set
+     */
+    public String getStackTrace() {
+        return abandonTrace;
+    }
+
+    /**
+     * Sets a timestamp on this connection. A timestamp usually means that some operation
+     * performed successfully.
+     * @param timestamp the timestamp as defined by {@link System#currentTimeMillis()}
+     */
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+        setSuspect(false);
+    }
+
+
+    public boolean isSuspect() {
+        return suspect;
+    }
+
+    public void setSuspect(boolean suspect) {
+        this.suspect = suspect;
+    }
+
+    /**
+     * An interceptor can call this method with the value true, and the connection will be closed when it is returned to the pool.
+     * @param discarded - only valid value is true
+     * @throws IllegalStateException if this method is called with the value false and the value true has already been set.
+     */
+    public void setDiscarded(boolean discarded) {
+        if (this.discarded && !discarded) throw new IllegalStateException("Unable to change the state once the connection has been discarded");
+        this.discarded = discarded;
+    }
+
+    /**
+     * Set the timestamp the connection was last validated.
+     * This flag is used to keep track when we are using a {@link PoolConfiguration#setValidationInterval(long) validation-interval}.
+     * @param lastValidated a timestamp as defined by {@link System#currentTimeMillis()}
+     */
+    public void setLastValidated(long lastValidated) {
+        this.lastValidated = lastValidated;
+    }
+
+    /**
+     * Sets the pool configuration for this connection and connection pool.
+     * Object is shared with the {@link ConnectionPool}
+     * @param poolProperties The pool properties
+     */
+    public void setPoolProperties(PoolConfiguration poolProperties) {
+        this.poolProperties = poolProperties;
+    }
+
+    /**
+     * Return the timestamps of last pool action. Timestamps are typically set when connections
+     * are borrowed from the pool. It is used to keep track of {@link PoolConfiguration#setRemoveAbandonedTimeout(int) abandon-timeouts}.
+     * This timestamp can also be reset by the {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer#invoke(Object, java.lang.reflect.Method, Object[])}
+     * @return the timestamp of the last pool action as defined by {@link System#currentTimeMillis()}
+     */
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    /**
+     * Returns the discarded flag.
+     * @return the discarded flag. If the value is true,
+     * either {@link #disconnect(boolean)} has been called or it will be called when the connection is returned to the pool.
+     */
+    public boolean isDiscarded() {
+        return discarded;
+    }
+
+    /**
+     * Returns the timestamp of the last successful validation query execution.
+     * @return the timestamp of the last successful validation query execution as defined by {@link System#currentTimeMillis()}
+     */
+    public long getLastValidated() {
+        return lastValidated;
+    }
+
+    /**
+     * Returns the configuration for this connection and pool
+     * @return the configuration for this connection and pool
+     */
+    public PoolConfiguration getPoolProperties() {
+        return poolProperties;
+    }
+
+    /**
+     * Locks the connection only if either {@link PoolConfiguration#isPoolSweeperEnabled()} or
+     * {@link PoolConfiguration#getUseLock()} return true. The per connection lock ensures thread safety is
+     * multiple threads are performing operations on the connection.
+     * Otherwise this is a noop for performance
+     */
+    public void lock() {
+        if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
+            //optimized, only use a lock when there is concurrency
+            lock.writeLock().lock();
+        }
+    }
+
+    /**
+     * Unlocks the connection only if the sweeper is enabled
+     * Otherwise this is a noop for performance
+     */
+    public void unlock() {
+        if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
+          //optimized, only use a lock when there is concurrency
+            lock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Returns the underlying connection
+     * @return the underlying JDBC connection as it was returned from the JDBC driver
+     * @see javax.sql.PooledConnection#getConnection()
+     */
+    public java.sql.Connection getConnection() {
+        return this.connection;
+    }
+
+    /**
+     * Returns the underlying XA connection
+     * @return the underlying XA connection as it was returned from the Datasource
+     */
+    public javax.sql.XAConnection getXAConnection() {
+        return this.xaConnection;
+    }
+
+
+    /**
+     * Returns the timestamp of when the connection was last connected to the database.
+     * ie, a successful call to {@link java.sql.Driver#connect(String, java.util.Properties)}.
+     * @return the timestamp when this connection was created as defined by {@link System#currentTimeMillis()}
+     */
+    public long getLastConnected() {
+        return lastConnected;
+    }
+
+    /**
+     * Returns the first handler in the interceptor chain
+     * @return the first interceptor for this connection
+     */
+    public JdbcInterceptor getHandler() {
+        return handler;
+    }
+
+    public void setHandler(JdbcInterceptor handler) {
+        if (this.handler!=null && this.handler!=handler) {
+            JdbcInterceptor interceptor = this.handler;
+            while (interceptor!=null) {
+                interceptor.reset(null, null);
+                interceptor = interceptor.getNext();
+            }//while
+        }//end if
+        this.handler = handler;
+    }
+
+    @Override
+    public String toString() {
+        return "PooledConnection["+(connection!=null?connection.toString():"null")+"]";
+    }
+
+    /**
+     * Returns true if this connection has been released and wont be reused.
+     * @return true if the method {@link #release()} has been called
+     */
+    public boolean isReleased() {
+        return released.get();
+    }
+
+    public HashMap<Object,Object> getAttributes() {
+        return attributes;
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java
new file mode 100644 (file)
index 0000000..0a67e8e
--- /dev/null
@@ -0,0 +1,176 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+
+import javax.sql.XAConnection;
+/**
+ * A ProxyConnection object is the bottom most interceptor that wraps an object of type
+ * {@link PooledConnection}. The ProxyConnection intercepts three methods:
+ * <ul>
+ *   <li>{@link java.sql.Connection#close()} - returns the connection to the pool. May be called multiple times.</li>
+ *   <li>{@link java.lang.Object#toString()} - returns a custom string for this object</li>
+ *   <li>{@link javax.sql.PooledConnection#getConnection()} - returns the underlying connection</li>
+ * </ul>
+ * By default method comparisons is done on a String reference level, unless the {@link PoolConfiguration#setUseEquals(boolean)} has been called
+ * with a <code>true</code> argument.
+ */
+public class ProxyConnection extends JdbcInterceptor {
+
+    protected PooledConnection connection = null;
+
+    protected ConnectionPool pool = null;
+
+    public PooledConnection getConnection() {
+        return connection;
+    }
+
+    public void setConnection(PooledConnection connection) {
+        this.connection = connection;
+    }
+
+    public ConnectionPool getPool() {
+        return pool;
+    }
+
+    public void setPool(ConnectionPool pool) {
+        this.pool = pool;
+    }
+
+    protected ProxyConnection(ConnectionPool parent, PooledConnection con,
+            boolean useEquals) {
+        pool = parent;
+        connection = con;
+        setUseEquals(useEquals);
+    }
+
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        this.pool = parent;
+        this.connection = con;
+    }
+
+    public boolean isWrapperFor(Class<?> iface) {
+        if (iface == XAConnection.class && connection.getXAConnection()!=null) {
+            return true;
+        } else {
+            return (iface.isInstance(connection.getConnection()));
+        }
+    }
+
+
+    public Object unwrap(Class<?> iface) throws SQLException {
+        if (iface == PooledConnection.class) {
+            return connection;
+        }else if (iface == XAConnection.class) {
+            return connection.getXAConnection();
+        } else if (isWrapperFor(iface)) {
+            return connection.getConnection();
+        } else {
+            throw new SQLException("Not a wrapper of "+iface.getName());
+        }
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (compare(ISCLOSED_VAL,method)) {
+            return Boolean.valueOf(isClosed());
+        }
+        if (compare(CLOSE_VAL,method)) {
+            if (connection==null) return null; //noop for already closed.
+            PooledConnection poolc = this.connection;
+            this.connection = null;
+            pool.returnConnection(poolc);
+            return null;
+        } else if (compare(TOSTRING_VAL,method)) {
+            return this.toString();
+        } else if (compare(GETCONNECTION_VAL,method) && connection!=null) {
+            return connection.getConnection();
+        } else if (method.getDeclaringClass().equals(XAConnection.class)) {
+            try {
+                return method.invoke(connection.getXAConnection(),args);
+            }catch (Throwable t) {
+                if (t instanceof InvocationTargetException) {
+                    throw t.getCause() != null ? t.getCause() : t;
+                } else {
+                    throw t;
+                }
+            }
+        }
+        if (isClosed()) throw new SQLException("Connection has already been closed.");
+        if (compare(UNWRAP_VAL,method)) {
+            return unwrap((Class<?>)args[0]);
+        } else if (compare(ISWRAPPERFOR_VAL,method)) {
+            return Boolean.valueOf(this.isWrapperFor((Class<?>)args[0]));
+        }
+        try {
+            PooledConnection poolc = connection;
+            if (poolc!=null) {
+                return method.invoke(poolc.getConnection(),args);
+            } else {
+                throw new SQLException("Connection has already been closed.");
+            }
+        }catch (Throwable t) {
+            if (t instanceof InvocationTargetException) {
+                throw t.getCause() != null ? t.getCause() : t;
+            } else {
+                throw t;
+            }
+        }
+    }
+
+    public boolean isClosed() {
+        return connection==null || connection.isDiscarded();
+    }
+
+    public PooledConnection getDelegateConnection() {
+        return connection;
+    }
+
+    public ConnectionPool getParentPool() {
+        return pool;
+    }
+
+    @Override
+    public String toString() {
+        return "ProxyConnection["+(connection!=null?connection.toString():"null")+"]";
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/TrapException.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/TrapException.java
new file mode 100644 (file)
index 0000000..5c597f3
--- /dev/null
@@ -0,0 +1,101 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tomcat.jdbc.pool;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+/**
+ * Interceptor that traps any unhandled exception types and throws an exception that has been declared by the method
+ * called, or throw a SQLException if it is declared.
+ * If the caught exception is not declared, and the method doesn't throw SQLException, then this interceptor will
+ * throw a RuntimeException
+ *
+ */
+public class TrapException extends JdbcInterceptor {
+
+
+    public TrapException() {
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        try {
+            return super.invoke(proxy, method, args);
+        }catch (Exception t) {
+            Throwable exception = t;
+            if (t instanceof InvocationTargetException && t.getCause() != null) {
+                exception = t.getCause();
+                if (exception instanceof Error) {
+                    throw exception;
+                }
+            }
+            Class<?> exceptionClass = exception.getClass();
+            if (!isDeclaredException(method, exceptionClass)) {
+                if (isDeclaredException(method,SQLException.class)) {
+                    SQLException sqlx = new SQLException("Uncaught underlying exception.");
+                    sqlx.initCause(exception);
+                    exception = sqlx;
+                } else {
+                    RuntimeException rx = new RuntimeException("Uncaught underlying exception.");
+                    rx.initCause(exception);
+                    exception = rx;
+                }
+            }
+            throw exception;
+        }
+
+    }
+
+    public boolean isDeclaredException(Method m, Class<?> clazz) {
+        for (Class<?> cl : m.getExceptionTypes()) {
+            if (cl.equals(clazz) || cl.isAssignableFrom(clazz)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * no-op for this interceptor. no state is stored.
+     */
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        // NOOP
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/Validator.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/Validator.java
new file mode 100644 (file)
index 0000000..70cef5a
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.sql.Connection;
+
+/**
+ * Interface to be implemented by custom validator classes.
+ *
+ * @author mpassell
+ */
+public interface Validator {
+    /**
+     * Validate a connection and return a boolean to indicate if it's valid.
+     *
+     * @param connection the Connection object to test
+     * @param validateAction the action used. One of {@link PooledConnection#VALIDATE_BORROW},
+     *   {@link PooledConnection#VALIDATE_IDLE}, {@link PooledConnection#VALIDATE_INIT} or
+     *   {@link PooledConnection#VALIDATE_RETURN}
+     * @return true if the connection is valid
+     */
+    public boolean validate(Connection connection, int validateAction);
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/XADataSource.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/XADataSource.java
new file mode 100644 (file)
index 0000000..4bdb198
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tomcat.jdbc.pool;
+
+public class XADataSource extends DataSource implements javax.sql.XADataSource {
+
+    /**
+     * Constructor for reflection only. A default set of pool properties will be created.
+     */
+    public XADataSource() {
+        super();
+    }
+
+    /**
+     * Constructs a DataSource object wrapping a connection
+     * @param poolProperties The pool configuration
+     */
+    public XADataSource(PoolConfiguration poolProperties) {
+        super(poolProperties);
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java
new file mode 100644 (file)
index 0000000..e2f1414
--- /dev/null
@@ -0,0 +1,158 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.reflect.Method;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * Abstraction interceptor. This component intercepts all calls to create some type of SQL statement.
+ * By extending this class, one can intercept queries and update statements by overriding the {@link #createStatement(Object, Method, Object[], Object, long)}
+ * method.
+ * @version 1.0
+ */
+public abstract class  AbstractCreateStatementInterceptor extends JdbcInterceptor {
+    protected static final String CREATE_STATEMENT      = "createStatement";
+    protected static final int    CREATE_STATEMENT_IDX  = 0;
+    protected static final String PREPARE_STATEMENT     = "prepareStatement";
+    protected static final int    PREPARE_STATEMENT_IDX = 1;
+    protected static final String PREPARE_CALL          = "prepareCall";
+    protected static final int    PREPARE_CALL_IDX      = 2;
+
+    protected static final String[] STATEMENT_TYPES = {CREATE_STATEMENT, PREPARE_STATEMENT, PREPARE_CALL};
+    protected static final int    STATEMENT_TYPE_COUNT = STATEMENT_TYPES.length;
+
+    protected static final String EXECUTE        = "execute";
+    protected static final String EXECUTE_QUERY  = "executeQuery";
+    protected static final String EXECUTE_UPDATE = "executeUpdate";
+    protected static final String EXECUTE_BATCH  = "executeBatch";
+
+    protected static final String[] EXECUTE_TYPES = {EXECUTE, EXECUTE_QUERY, EXECUTE_UPDATE, EXECUTE_BATCH};
+
+    public  AbstractCreateStatementInterceptor() {
+        super();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (compare(CLOSE_VAL,method)) {
+            closeInvoked();
+            return super.invoke(proxy, method, args);
+        } else {
+            boolean process = false;
+            process = isStatement(method, process);
+            if (process) {
+                long start = System.currentTimeMillis();
+                Object statement = super.invoke(proxy,method,args);
+                long delta = System.currentTimeMillis() - start;
+                return createStatement(proxy,method,args,statement, delta);
+            } else {
+                return super.invoke(proxy,method,args);
+            }
+        }
+    }
+
+    /**
+     * This method will be invoked after a successful statement creation. This method can choose to return a wrapper
+     * around the statement or return the statement itself.
+     * If this method returns a wrapper then it should return a wrapper object that implements one of the following interfaces.
+     * {@link java.sql.Statement}, {@link java.sql.PreparedStatement} or {@link java.sql.CallableStatement}
+     * @param proxy the actual proxy object
+     * @param method the method that was called. It will be one of the methods defined in {@link #STATEMENT_TYPES}
+     * @param args the arguments to the method
+     * @param statement the statement that the underlying connection created
+     * @param time Elapsed time
+     * @return a {@link java.sql.Statement} object
+     */
+    public abstract Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time);
+
+    /**
+     * Method invoked when the operation {@link java.sql.Connection#close()} is invoked.
+     */
+    public abstract void closeInvoked();
+
+    /**
+     * Returns true if the method that is being invoked matches one of the statement types.
+     *
+     * @param method the method being invoked on the proxy
+     * @param process boolean result used for recursion
+     * @return returns true if the method name matched
+     */
+    protected boolean isStatement(Method method, boolean process){
+        return process(STATEMENT_TYPES, method, process);
+    }
+
+    /**
+     * Returns true if the method that is being invoked matches one of the execute types.
+     *
+     * @param method the method being invoked on the proxy
+     * @param process boolean result used for recursion
+     * @return returns true if the method name matched
+     */
+    protected boolean isExecute(Method method, boolean process){
+        return process(EXECUTE_TYPES, method, process);
+    }
+
+    /*
+     * Returns true if the method that is being invoked matches one of the method names passed in
+     * @param names list of method names that we want to intercept
+     * @param method the method being invoked on the proxy
+     * @param process boolean result used for recursion
+     * @return returns true if the method name matched
+     */
+    protected boolean process(String[] names, Method method, boolean process) {
+        final String name = method.getName();
+        for (int i=0; (!process) && i<names.length; i++) {
+            process = compare(names[i],name);
+        }
+        return process;
+    }
+
+    /**
+     * no-op for this interceptor. no state is stored.
+     */
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        // NOOP
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java
new file mode 100644 (file)
index 0000000..374969d
--- /dev/null
@@ -0,0 +1,285 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+/**
+ * Abstract class that wraps statements and intercepts query executions.
+ *
+ */
+public abstract class AbstractQueryReport extends AbstractCreateStatementInterceptor {
+    //logger
+    private static final Log log = LogFactory.getLog(AbstractQueryReport.class);
+
+    /**
+     * The threshold in milliseconds. If the query is faster than this, we don't measure it
+     */
+    protected long threshold = 1000; //don't report queries less than this
+
+    /**
+     * the constructors that are used to create statement proxies
+     */
+    protected static final Constructor<?>[] constructors =
+        new Constructor[AbstractCreateStatementInterceptor.STATEMENT_TYPE_COUNT];
+
+
+    public AbstractQueryReport() {
+        super();
+    }
+
+    /**
+     * Invoked when prepareStatement has been called and completed.
+     * @param sql - the string used to prepare the statement with
+     * @param time - the time it took to invoke prepare
+     */
+    protected abstract void prepareStatement(String sql, long time);
+
+    /**
+     * Invoked when prepareCall has been called and completed.
+     * @param query - the string used to prepare the statement with
+     * @param time - the time it took to invoke prepare
+     */
+    protected abstract void prepareCall(String query, long time);
+
+    /**
+     * Invoked when a query execution, a call to execute/executeQuery or executeBatch failed.
+     * @param query the query that was executed and failed
+     * @param args the arguments to the execution
+     * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
+     * @param start the time the query execution started
+     * @param t the exception that happened
+     * @return - the SQL that was executed or the string &quot;batch&quot; if it was a batch execution
+     */
+    protected String reportFailedQuery(String query, Object[] args, final String name, long start, Throwable t) {
+        //extract the query string
+        String sql = (query==null && args!=null &&  args.length>0)?(String)args[0]:query;
+        //if we do batch execution, then we name the query 'batch'
+        if (sql==null && compare(EXECUTE_BATCH,name)) {
+            sql = "batch";
+        }
+        return sql;
+    }
+
+    /**
+     * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was within the timing threshold
+     * @param query the query that was executed and failed
+     * @param args the arguments to the execution
+     * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
+     * @param start the time the query execution started
+     * @param delta the time the execution took
+     * @return - the SQL that was executed or the string &quot;batch&quot; if it was a batch execution
+     */
+    protected String reportQuery(String query, Object[] args, final String name, long start, long delta) {
+        //extract the query string
+        String sql = (query==null && args!=null &&  args.length>0)?(String)args[0]:query;
+        //if we do batch execution, then we name the query 'batch'
+        if (sql==null && compare(EXECUTE_BATCH,name)) {
+            sql = "batch";
+        }
+        return sql;
+    }
+
+    /**
+     * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was exceeded the timing threshold
+     * @param query the query that was executed and failed
+     * @param args the arguments to the execution
+     * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
+     * @param start the time the query execution started
+     * @param delta the time the execution took
+     * @return - the SQL that was executed or the string &quot;batch&quot; if it was a batch execution
+     */
+    protected String reportSlowQuery(String query, Object[] args, final String name, long start, long delta) {
+        //extract the query string
+        String sql = (query==null && args!=null &&  args.length>0)?(String)args[0]:query;
+        //if we do batch execution, then we name the query 'batch'
+        if (sql==null && compare(EXECUTE_BATCH,name)) {
+            sql = "batch";
+        }
+        return sql;
+    }
+
+    /**
+     * returns the query measure threshold.
+     * This value is in milliseconds. If the query is faster than this threshold than it wont be accounted for
+     * @return the threshold in milliseconds
+     */
+    public long getThreshold() {
+        return threshold;
+    }
+
+    /**
+     * Sets the query measurement threshold. The value is in milliseconds.
+     * If the query goes faster than this threshold it will not be recorded.
+     * @param threshold set to -1 to record every query. Value is in milliseconds.
+     */
+    public void setThreshold(long threshold) {
+        this.threshold = threshold;
+    }
+
+    /**
+     * Creates a constructor for a proxy class, if one doesn't already exist
+     * @param idx - the index of the constructor
+     * @param clazz - the interface that the proxy will implement
+     * @return - returns a constructor used to create new instances
+     * @throws NoSuchMethodException Constructor not found
+     */
+    protected Constructor<?> getConstructor(int idx, Class<?> clazz) throws NoSuchMethodException {
+        if (constructors[idx]==null) {
+            Class<?> proxyClass = Proxy.getProxyClass(SlowQueryReport.class.getClassLoader(), new Class[] {clazz});
+            constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+        }
+        return constructors[idx];
+    }
+
+    /**
+     * Creates a statement interceptor to monitor query response times
+     */
+    @Override
+    public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
+        try {
+            Object result = null;
+            String name = method.getName();
+            String sql = null;
+            Constructor<?> constructor = null;
+            if (compare(CREATE_STATEMENT,name)) {
+                //createStatement
+                constructor = getConstructor(CREATE_STATEMENT_IDX,Statement.class);
+            }else if (compare(PREPARE_STATEMENT,name)) {
+                //prepareStatement
+                sql = (String)args[0];
+                constructor = getConstructor(PREPARE_STATEMENT_IDX,PreparedStatement.class);
+                if (sql!=null) {
+                    prepareStatement(sql, time);
+                }
+            }else if (compare(PREPARE_CALL,name)) {
+                //prepareCall
+                sql = (String)args[0];
+                constructor = getConstructor(PREPARE_CALL_IDX,CallableStatement.class);
+                prepareCall(sql,time);
+            }else {
+                //do nothing, might be a future unsupported method
+                //so we better bail out and let the system continue
+                return statement;
+            }
+            result = constructor.newInstance(new Object[] { new StatementProxy(statement,sql) });
+            return result;
+        }catch (Exception x) {
+            log.warn("Unable to create statement proxy for slow query report.",x);
+        }
+        return statement;
+    }
+
+
+    /**
+     * Class to measure query execute time
+     *
+     */
+    protected class StatementProxy implements InvocationHandler {
+        protected boolean closed = false;
+        protected Object delegate;
+        protected final String query;
+        public StatementProxy(Object parent, String query) {
+            this.delegate = parent;
+            this.query = query;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            //get the name of the method for comparison
+            final String name = method.getName();
+            //was close invoked?
+            boolean close = compare(JdbcInterceptor.CLOSE_VAL,name);
+            //allow close to be called multiple times
+            if (close && closed) return null;
+            //are we calling isClosed?
+            if (compare(JdbcInterceptor.ISCLOSED_VAL,name)) return Boolean.valueOf(closed);
+            //if we are calling anything else, bail out
+            if (closed) throw new SQLException("Statement closed.");
+            boolean process = false;
+            //check to see if we are about to execute a query
+            process = isExecute( method, process);
+            //if we are executing, get the current time
+            long start = (process)?System.currentTimeMillis():0;
+            Object result =  null;
+            try {
+                //execute the query
+                result =  method.invoke(delegate,args);
+            }catch (Throwable t) {
+                reportFailedQuery(query,args,name,start,t);
+                if (t instanceof InvocationTargetException
+                        && t.getCause() != null) {
+                    throw t.getCause();
+                } else {
+                    throw t;
+                }
+            }
+            //measure the time
+            long delta = (process)?(System.currentTimeMillis()-start):Long.MIN_VALUE;
+            //see if we meet the requirements to measure
+            if (delta>threshold) {
+                try {
+                    //report the slow query
+                    reportSlowQuery(query, args, name, start, delta);
+                }catch (Exception t) {
+                    if (log.isWarnEnabled()) log.warn("Unable to process slow query",t);
+                }
+            } else if (process) {
+                reportQuery(query, args, name, start, delta);
+            }
+            //perform close cleanup
+            if (close) {
+                closed=true;
+                delegate = null;
+            }
+            return result;
+        }
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java
new file mode 100644 (file)
index 0000000..95049c6
--- /dev/null
@@ -0,0 +1,184 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.DataSourceFactory;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * Interceptor that keep track of connection state to avoid roundtrips to the database.
+ * The {@link org.apache.tomcat.jdbc.pool.ConnectionPool} is optimized to do as little work as possible.
+ * The pool itself doesn't remember settings like {@link java.sql.Connection#setAutoCommit(boolean)},
+ * {@link java.sql.Connection#setReadOnly(boolean)}, {@link java.sql.Connection#setCatalog(String)} or
+ * {@link java.sql.Connection#setTransactionIsolation(int)}. It relies on the application to remember how and when
+ * these settings have been applied.
+ * In the cases where the application code doesn't know or want to keep track of the state, this interceptor helps cache the
+ * state, and it also avoids roundtrips to the database asking for it.
+ *
+ */
+
+public class ConnectionState extends JdbcInterceptor  {
+    private static final Log log = LogFactory.getLog(ConnectionState.class);
+
+    protected final String[] readState = {"getAutoCommit","getTransactionIsolation","isReadOnly","getCatalog"};
+    protected final String[] writeState = {"setAutoCommit","setTransactionIsolation","setReadOnly","setCatalog"};
+
+    protected Boolean autoCommit = null;
+    protected Integer transactionIsolation = null;
+    protected Boolean readOnly = null;
+    protected String catalog = null;
+
+
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        if (parent==null || con==null) {
+            //we are resetting, reset our defaults
+            autoCommit = null;
+            transactionIsolation = null;
+            readOnly = null;
+            catalog = null;
+            return;
+        }
+        PoolConfiguration poolProperties = parent.getPoolProperties();
+        if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) {
+            try {
+                if (transactionIsolation==null || transactionIsolation.intValue()!=poolProperties.getDefaultTransactionIsolation()) {
+                    con.getConnection().setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
+                    transactionIsolation = Integer.valueOf(poolProperties.getDefaultTransactionIsolation());
+                }
+            }catch (SQLException x) {
+                transactionIsolation = null;
+                log.error("Unable to reset transaction isolation state to connection.",x);
+            }
+        }
+        if (poolProperties.getDefaultReadOnly()!=null) {
+            try {
+                if (readOnly==null || readOnly.booleanValue()!=poolProperties.getDefaultReadOnly().booleanValue()) {
+                    con.getConnection().setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());
+                    readOnly = poolProperties.getDefaultReadOnly();
+                }
+            }catch (SQLException x) {
+                readOnly = null;
+                log.error("Unable to reset readonly state to connection.",x);
+            }
+        }
+        if (poolProperties.getDefaultAutoCommit()!=null) {
+            try {
+                if (autoCommit==null || autoCommit.booleanValue()!=poolProperties.getDefaultAutoCommit().booleanValue()) {
+                    con.getConnection().setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());
+                    autoCommit = poolProperties.getDefaultAutoCommit();
+                }
+            }catch (SQLException x) {
+                autoCommit = null;
+                log.error("Unable to reset autocommit state to connection.",x);
+            }
+        }
+        if (poolProperties.getDefaultCatalog()!=null) {
+            try {
+                if (catalog==null || (!catalog.equals(poolProperties.getDefaultCatalog()))) {
+                    con.getConnection().setCatalog(poolProperties.getDefaultCatalog());
+                    catalog = poolProperties.getDefaultCatalog();
+                }
+            }catch (SQLException x) {
+                catalog = null;
+                log.error("Unable to reset default catalog state to connection.",x);
+            }
+        }
+
+    }
+
+
+    @Override
+    public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
+        //we are resetting, reset our defaults
+        autoCommit = null;
+        transactionIsolation = null;
+        readOnly = null;
+        catalog = null;
+        super.disconnected(parent, con, finalizing);
+    }
+
+
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        String name = method.getName();
+        boolean read = false;
+        int index = -1;
+        for (int i=0; (!read) && i<readState.length; i++) {
+            read = compare(name,readState[i]);
+            if (read) index = i;
+        }
+        boolean write = false;
+        for (int i=0; (!write) && (!read) && i<writeState.length; i++) {
+            write = compare(name,writeState[i]);
+            if (write) index = i;
+        }
+        Object result = null;
+        if (read) {
+            switch (index) {
+                case 0:{result = autoCommit; break;}
+                case 1:{result = transactionIsolation; break;}
+                case 2:{result = readOnly; break;}
+                case 3:{result = catalog; break;}
+                default: // NOOP
+            }
+            //return cached result, if we have it
+            if (result!=null) return result;
+        }
+
+        result = super.invoke(proxy, method, args);
+        if (read || write) {
+            switch (index) {
+                case 0:{autoCommit = (Boolean) (read?result:args[0]); break;}
+                case 1:{transactionIsolation = (Integer)(read?result:args[0]); break;}
+                case 2:{readOnly = (Boolean)(read?result:args[0]); break;}
+                case 3:{catalog = (String)(read?result:args[0]); break;}
+            }
+        }
+        return result;
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/QueryTimeoutInterceptor.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/QueryTimeoutInterceptor.java
new file mode 100644 (file)
index 0000000..7aec0b4
--- /dev/null
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Map;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+
+public class QueryTimeoutInterceptor extends AbstractCreateStatementInterceptor {
+    private static Log log = LogFactory.getLog(QueryTimeoutInterceptor.class);
+    int timeout = 1;
+
+    @Override
+    public void setProperties(Map<String,InterceptorProperty> properties) {
+        super.setProperties(properties);
+        InterceptorProperty p = properties.get("queryTimeout");
+        if (p!=null) timeout = p.getValueAsInt(timeout);
+    }
+
+    @Override
+    public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
+        if (statement instanceof Statement && timeout > 0) {
+            Statement s = (Statement)statement;
+            try {
+                s.setQueryTimeout(timeout);
+            }catch (SQLException x) {
+                log.warn("[QueryTimeoutInterceptor] Unable to set query timeout:"+x.getMessage(),x);
+            }
+        }
+        return statement;
+    }
+
+    @Override
+    public void closeInvoked() {
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ResetAbandonedTimer.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ResetAbandonedTimer.java
new file mode 100644 (file)
index 0000000..6c6981e
--- /dev/null
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.reflect.Method;
+
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.pool.ProxyConnection;
+
+/**
+ * Class that resets the abandoned timer on any activity on the
+ * Connection or any successful query executions.
+ * This interceptor is useful for when you have a {@link org.apache.tomcat.jdbc.pool.PoolConfiguration#setRemoveAbandonedTimeout(int)}
+ * that is fairly low, and you want to reset the abandoned time each time any operation on the connection is performed
+ * This is useful for batch processing programs that use connections for extensive amount of times.
+ *
+ */
+public class ResetAbandonedTimer extends AbstractQueryReport {
+
+    public ResetAbandonedTimer() {
+    }
+
+    public boolean resetTimer() {
+        boolean result = false;
+        JdbcInterceptor interceptor = this.getNext();
+        while (interceptor!=null && result==false) {
+            if (interceptor instanceof ProxyConnection) {
+                PooledConnection con = ((ProxyConnection)interceptor).getConnection();
+                if (con!=null) {
+                    con.setTimestamp(System.currentTimeMillis());
+                    result = true;
+                } else {
+                    break;
+                }
+            }
+            interceptor = interceptor.getNext();
+        }
+        return result;
+    }
+
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        Object result = super.invoke(proxy, method, args);
+        resetTimer();
+        return result;
+    }
+
+    @Override
+    protected void prepareCall(String query, long time) {
+        resetTimer();
+    }
+
+    @Override
+    protected void prepareStatement(String sql, long time) {
+        resetTimer();
+
+    }
+
+    @Override
+    public void closeInvoked() {
+        resetTimer();
+    }
+
+    @Override
+    protected String reportQuery(String query, Object[] args, String name,long start, long delta) {
+        resetTimer();
+        return super.reportQuery(query, args, name, start, delta);
+    }
+
+    @Override
+    protected String reportSlowQuery(String query, Object[] args, String name,long start, long delta) {
+        resetTimer();
+        return super.reportSlowQuery(query, args, name, start, delta);
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
new file mode 100644 (file)
index 0000000..23fa3fa
--- /dev/null
@@ -0,0 +1,516 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * Slow query report interceptor. Tracks timing of query executions.
+ * @version 1.0
+ */
+public class SlowQueryReport extends AbstractQueryReport  {
+    //logger
+    private static final Log log = LogFactory.getLog(SlowQueryReport.class);
+
+    /**
+     * we will be keeping track of query stats on a per pool basis
+     */
+    protected static final ConcurrentHashMap<String,ConcurrentHashMap<String,QueryStats>> perPoolStats =
+        new ConcurrentHashMap<>();
+    /**
+     * the queries that are used for this interceptor.
+     */
+    protected volatile ConcurrentHashMap<String,QueryStats> queries = null;
+    /**
+     * Maximum number of queries we will be storing
+     */
+    protected int  maxQueries= 1000; //don't store more than this amount of queries
+
+    /**
+     * Flag to enable disable logging of slow queries
+     */
+    protected boolean logSlow = true;
+
+    /**
+     * Flag to enable disable logging of failed queries
+     */
+    protected boolean logFailed = false;
+
+    /**
+     * Sort QueryStats by last invocation time
+     */
+    protected final Comparator<QueryStats> queryStatsComparator = new QueryStatsComparator();
+
+    /**
+     * Returns the query stats for a given pool
+     * @param poolname - the name of the pool we want to retrieve stats for
+     * @return a hash map containing statistics for 0 to maxQueries
+     */
+    public static ConcurrentHashMap<String,QueryStats> getPoolStats(String poolname) {
+        return perPoolStats.get(poolname);
+    }
+
+    /**
+     * Creates a slow query report interceptor
+     */
+    public SlowQueryReport() {
+        super();
+    }
+
+    public void setMaxQueries(int maxQueries) {
+        this.maxQueries = maxQueries;
+    }
+
+
+    @Override
+    protected String reportFailedQuery(String query, Object[] args, String name, long start, Throwable t) {
+        String sql = super.reportFailedQuery(query, args, name, start, t);
+        if (this.maxQueries > 0 ) {
+            long now = System.currentTimeMillis();
+            long delta = now - start;
+            QueryStats qs = this.getQueryStats(sql);
+            if (qs != null) {
+                qs.failure(delta, now);
+                if (isLogFailed() && log.isWarnEnabled()) {
+                    log.warn("Failed Query Report SQL="+sql+"; time="+delta+" ms;");
+                }
+            }
+        }
+        return sql;
+    }
+
+    @Override
+    protected String reportQuery(String query, Object[] args, final String name, long start, long delta) {
+        String sql = super.reportQuery(query, args, name, start, delta);
+        if (this.maxQueries > 0 ) {
+            QueryStats qs = this.getQueryStats(sql);
+            if (qs != null) qs.add(delta, start);
+        }
+        return sql;
+    }
+
+    @Override
+    protected String reportSlowQuery(String query, Object[] args, String name, long start, long delta) {
+        String sql = super.reportSlowQuery(query, args, name, start, delta);
+        if (this.maxQueries > 0 ) {
+            QueryStats qs = this.getQueryStats(sql);
+            if (qs != null) {
+                qs.add(delta, start);
+                if (isLogSlow() && log.isWarnEnabled()) {
+                    log.warn("Slow Query Report SQL="+sql+"; time="+delta+" ms;");
+                }
+            }
+        }
+        return sql;
+    }
+
+    /**
+     * invoked when the connection receives the close request
+     * Not used for now.
+     */
+    @Override
+    public void closeInvoked() {
+        // NOOP
+    }
+
+    @Override
+    public void prepareStatement(String sql, long time) {
+        if (this.maxQueries > 0 ) {
+            QueryStats qs = getQueryStats(sql);
+            if (qs != null) qs.prepare(time);
+        }
+    }
+
+    @Override
+    public void prepareCall(String sql, long time) {
+        if (this.maxQueries > 0 ) {
+            QueryStats qs = getQueryStats(sql);
+            if (qs != null) qs.prepare(time);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void poolStarted(ConnectionPool pool) {
+        super.poolStarted(pool);
+        //see if we already created a map for this pool
+        queries = SlowQueryReport.perPoolStats.get(pool.getName());
+        if (queries==null) {
+            //create the map to hold our stats
+            //however TODO we need to improve the eviction
+            //selection
+            queries = new ConcurrentHashMap<>();
+            if (perPoolStats.putIfAbsent(pool.getName(), queries)!=null) {
+                //there already was one
+                queries = SlowQueryReport.perPoolStats.get(pool.getName());
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void poolClosed(ConnectionPool pool) {
+        perPoolStats.remove(pool.getName());
+        super.poolClosed(pool);
+    }
+
+    protected QueryStats getQueryStats(String sql) {
+        if (sql==null) sql = "";
+        ConcurrentHashMap<String,QueryStats> queries = SlowQueryReport.this.queries;
+        if (queries==null) {
+            if (log.isWarnEnabled()) log.warn("Connection has already been closed or abandoned");
+            return null;
+        }
+        QueryStats qs = queries.get(sql);
+        if (qs == null) {
+            qs = new QueryStats(sql);
+            if (queries.putIfAbsent(sql,qs)!=null) {
+                qs = queries.get(sql);
+            } else {
+                //we added a new element, see if we need to remove the oldest
+                if (queries.size() > maxQueries) {
+                    removeOldest(queries);
+                }
+            }
+        }
+        return qs;
+    }
+
+    /**
+     * Sort QueryStats by last invocation time
+     * @param queries The queries map
+     */
+    protected void removeOldest(ConcurrentHashMap<String,QueryStats> queries) {
+        ArrayList<QueryStats> list = new ArrayList<>(queries.values());
+        Collections.sort(list, queryStatsComparator);
+        int removeIndex = 0;
+        while (queries.size() > maxQueries) {
+            String sql = list.get(removeIndex).getQuery();
+            queries.remove(sql);
+            if (log.isDebugEnabled()) log.debug("Removing slow query, capacity reached:"+sql);
+            removeIndex++;
+        }
+    }
+
+
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        super.reset(parent, con);
+        if (parent!=null)
+            queries = SlowQueryReport.perPoolStats.get(parent.getName());
+        else
+            queries = null;
+    }
+
+
+    public boolean isLogSlow() {
+        return logSlow;
+    }
+
+    public void setLogSlow(boolean logSlow) {
+        this.logSlow = logSlow;
+    }
+
+    public boolean isLogFailed() {
+        return logFailed;
+    }
+
+    public void setLogFailed(boolean logFailed) {
+        this.logFailed = logFailed;
+    }
+
+    @Override
+    public void setProperties(Map<String, InterceptorProperty> properties) {
+        super.setProperties(properties);
+        final String threshold = "threshold";
+        final String maxqueries= "maxQueries";
+        final String logslow = "logSlow";
+        final String logfailed = "logFailed";
+        InterceptorProperty p1 = properties.get(threshold);
+        InterceptorProperty p2 = properties.get(maxqueries);
+        InterceptorProperty p3 = properties.get(logslow);
+        InterceptorProperty p4 = properties.get(logfailed);
+        if (p1!=null) {
+            setThreshold(Long.parseLong(p1.getValue()));
+        }
+        if (p2!=null) {
+            setMaxQueries(Integer.parseInt(p2.getValue()));
+        }
+        if (p3!=null) {
+            setLogSlow(Boolean.parseBoolean(p3.getValue()));
+        }
+        if (p4!=null) {
+            setLogFailed(Boolean.parseBoolean(p4.getValue()));
+        }
+    }
+
+
+    public static class QueryStats {
+        static final String[] FIELD_NAMES = new String[] {
+            "query",
+            "nrOfInvocations",
+            "maxInvocationTime",
+            "maxInvocationDate",
+            "minInvocationTime",
+            "minInvocationDate",
+            "totalInvocationTime",
+            "failures",
+            "prepareCount",
+            "prepareTime",
+            "lastInvocation"
+        };
+
+        static final  String[] FIELD_DESCRIPTIONS = new String[] {
+            "The SQL query",
+            "The number of query invocations, a call to executeXXX",
+            "The longest time for this query in milliseconds",
+            "The time and date for when the longest query took place",
+            "The shortest time for this query in milliseconds",
+            "The time and date for when the shortest query took place",
+            "The total amount of milliseconds spent executing this query",
+            "The number of failures for this query",
+            "The number of times this query was prepared (prepareStatement/prepareCall)",
+            "The total number of milliseconds spent preparing this query",
+            "The date and time of the last invocation"
+        };
+
+        static final OpenType<?>[] FIELD_TYPES = new OpenType[] {
+            SimpleType.STRING,
+            SimpleType.INTEGER,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.INTEGER,
+            SimpleType.LONG,
+            SimpleType.LONG
+        };
+
+        private final String query;
+        private volatile int nrOfInvocations;
+        private volatile long maxInvocationTime = Long.MIN_VALUE;
+        private volatile long maxInvocationDate;
+        private volatile long minInvocationTime = Long.MAX_VALUE;
+        private volatile long minInvocationDate;
+        private volatile long totalInvocationTime;
+        private volatile long failures;
+        private volatile int prepareCount;
+        private volatile long prepareTime;
+        private volatile long lastInvocation = 0;
+
+        public static String[] getFieldNames() {
+            return FIELD_NAMES;
+        }
+
+        public static String[] getFieldDescriptions() {
+            return FIELD_DESCRIPTIONS;
+        }
+
+        public static OpenType<?>[] getFieldTypes() {
+            return FIELD_TYPES;
+        }
+
+        @Override
+        public String toString() {
+            SimpleDateFormat sdf =
+                    new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US);
+            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
+            StringBuilder buf = new StringBuilder("QueryStats[query:");
+            buf.append(query);
+            buf.append(", nrOfInvocations:");
+            buf.append(nrOfInvocations);
+            buf.append(", maxInvocationTime:");
+            buf.append(maxInvocationTime);
+            buf.append(", maxInvocationDate:");
+            buf.append(sdf.format(new java.util.Date(maxInvocationDate)));
+            buf.append(", minInvocationTime:");
+            buf.append(minInvocationTime);
+            buf.append(", minInvocationDate:");
+            buf.append(sdf.format(new java.util.Date(minInvocationDate)));
+            buf.append(", totalInvocationTime:");
+            buf.append(totalInvocationTime);
+            buf.append(", averageInvocationTime:");
+            buf.append((float)totalInvocationTime / (float)nrOfInvocations);
+            buf.append(", failures:");
+            buf.append(failures);
+            buf.append(", prepareCount:");
+            buf.append(prepareCount);
+            buf.append(", prepareTime:");
+            buf.append(prepareTime);
+            buf.append("]");
+            return buf.toString();
+        }
+
+        public CompositeDataSupport getCompositeData(final CompositeType type) throws OpenDataException{
+            Object[] values = new Object[] {
+                    query,
+                    Integer.valueOf(nrOfInvocations),
+                    Long.valueOf(maxInvocationTime),
+                    Long.valueOf(maxInvocationDate),
+                    Long.valueOf(minInvocationTime),
+                    Long.valueOf(minInvocationDate),
+                    Long.valueOf(totalInvocationTime),
+                    Long.valueOf(failures),
+                    Integer.valueOf(prepareCount),
+                    Long.valueOf(prepareTime),
+                    Long.valueOf(lastInvocation)
+            };
+            return new CompositeDataSupport(type,FIELD_NAMES,values);
+        }
+
+        public QueryStats(String query) {
+            this.query = query;
+        }
+
+        public void prepare(long invocationTime) {
+            prepareCount++;
+            prepareTime+=invocationTime;
+
+        }
+
+        public void add(long invocationTime, long now) {
+            //not thread safe, but don't sacrifice performance for this kind of stuff
+            maxInvocationTime = Math.max(invocationTime, maxInvocationTime);
+            if (maxInvocationTime == invocationTime) {
+                maxInvocationDate = now;
+            }
+            minInvocationTime = Math.min(invocationTime, minInvocationTime);
+            if (minInvocationTime==invocationTime) {
+                minInvocationDate = now;
+            }
+            nrOfInvocations++;
+            totalInvocationTime+=invocationTime;
+            lastInvocation = now;
+        }
+
+        public void failure(long invocationTime, long now) {
+            add(invocationTime,now);
+            failures++;
+
+        }
+
+        public String getQuery() {
+            return query;
+        }
+
+        public int getNrOfInvocations() {
+            return nrOfInvocations;
+        }
+
+        public long getMaxInvocationTime() {
+            return maxInvocationTime;
+        }
+
+        public long getMaxInvocationDate() {
+            return maxInvocationDate;
+        }
+
+        public long getMinInvocationTime() {
+            return minInvocationTime;
+        }
+
+        public long getMinInvocationDate() {
+            return minInvocationDate;
+        }
+
+        public long getTotalInvocationTime() {
+            return totalInvocationTime;
+        }
+
+        @Override
+        public int hashCode() {
+            return query.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof QueryStats) {
+                QueryStats qs = (QueryStats)other;
+                return qs.query.equals(this.query);
+            }
+            return false;
+        }
+
+        public boolean isOlderThan(QueryStats other) {
+            return this.lastInvocation < other.lastInvocation;
+        }
+    }
+
+    /** Compare QueryStats by their lastInvocation value. QueryStats that
+     * have never been updated, have a lastInvocation value of {@code 0}
+     * which should be handled as the newest possible invocation.
+     */
+    private static class QueryStatsComparator implements Comparator<QueryStats> {
+
+        @Override
+        public int compare(QueryStats stats1, QueryStats stats2) {
+            return Long.compare(handleZero(stats1.lastInvocation),
+                    handleZero(stats2.lastInvocation));
+        }
+
+        private static long handleZero(long value) {
+            return value == 0 ? Long.MAX_VALUE : value;
+        }
+
+    }
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java
new file mode 100644 (file)
index 0000000..60b48a0
--- /dev/null
@@ -0,0 +1,338 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.management.ManagementFactory;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+/**
+ * Publishes data to JMX and provides notifications
+ * when failures happen.
+ *
+ */
+public class SlowQueryReportJmx extends SlowQueryReport implements NotificationEmitter, SlowQueryReportJmxMBean{
+    public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
+    public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
+
+    public static final String objectNameAttribute = "objectName";
+
+    protected static volatile CompositeType SLOW_QUERY_TYPE;
+
+    private static final Log log = LogFactory.getLog(SlowQueryReportJmx.class);
+
+
+    protected static final ConcurrentHashMap<String,SlowQueryReportJmxMBean> mbeans =
+        new ConcurrentHashMap<>();
+
+
+    //==============================JMX STUFF========================
+    protected volatile NotificationBroadcasterSupport notifier = new NotificationBroadcasterSupport();
+
+    @Override
+    public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException {
+        notifier.addNotificationListener(listener, filter, handback);
+    }
+
+
+    @Override
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        return notifier.getNotificationInfo();
+    }
+
+    @Override
+    public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
+        notifier.removeNotificationListener(listener);
+
+    }
+
+    @Override
+    public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
+        notifier.removeNotificationListener(listener, filter, handback);
+
+    }
+
+
+    //==============================JMX STUFF========================
+
+    protected String poolName = null;
+
+    protected static final AtomicLong notifySequence = new AtomicLong(0);
+
+    protected boolean notifyPool = true;
+
+    protected ConnectionPool pool = null;
+
+    protected static CompositeType getCompositeType() {
+        if (SLOW_QUERY_TYPE==null) {
+            try {
+                SLOW_QUERY_TYPE = new CompositeType(
+                        SlowQueryReportJmx.class.getName(),
+                        "Composite data type for query statistics",
+                        QueryStats.getFieldNames(),
+                        QueryStats.getFieldDescriptions(),
+                        QueryStats.getFieldTypes());
+            }catch (OpenDataException x) {
+                log.warn("Unable to initialize composite data type for JMX stats and notifications.",x);
+            }
+        }
+        return SLOW_QUERY_TYPE;
+    }
+
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        super.reset(parent, con);
+        if (parent!=null) {
+            poolName = parent.getName();
+            pool = parent;
+            registerJmx();
+        }
+    }
+
+
+    @Override
+    public void poolClosed(ConnectionPool pool) {
+        this.poolName = pool.getName();
+        deregisterJmx();
+        super.poolClosed(pool);
+    }
+
+    @Override
+    public void poolStarted(ConnectionPool pool) {
+        this.pool = pool;
+        super.poolStarted(pool);
+        this.poolName = pool.getName();
+    }
+
+    @Override
+    protected String reportFailedQuery(String query, Object[] args, String name, long start, Throwable t) {
+        query = super.reportFailedQuery(query, args, name, start, t);
+        if (isLogFailed()) notifyJmx(query,FAILED_QUERY_NOTIFICATION);
+        return query;
+    }
+
+    protected void notifyJmx(String query, String type) {
+        try {
+            long sequence = notifySequence.incrementAndGet();
+
+            if (isNotifyPool()) {
+                if (this.pool!=null && this.pool.getJmxPool()!=null) {
+                    this.pool.getJmxPool().notify(type, query);
+                }
+            } else {
+                if (notifier!=null) {
+                    Notification notification =
+                        new Notification(type,
+                                         this,
+                                         sequence,
+                                         System.currentTimeMillis(),
+                                         query);
+
+                    notifier.sendNotification(notification);
+                }
+            }
+        } catch (RuntimeOperationsException e) {
+            if (log.isDebugEnabled()) {
+                log.debug("Unable to send failed query notification.",e);
+            }
+        }
+    }
+
+    @Override
+    protected String reportSlowQuery(String query, Object[] args, String name, long start, long delta) {
+        query = super.reportSlowQuery(query, args, name, start, delta);
+        if (isLogSlow()) notifyJmx(query,SLOW_QUERY_NOTIFICATION);
+        return query;
+    }
+
+    /**
+     * JMX operation - return the names of all the pools
+     * @return - all the names of pools that we have stored data for
+     */
+    public String[] getPoolNames() {
+        Set<String> keys = perPoolStats.keySet();
+        return keys.toArray(new String[0]);
+    }
+
+    /**
+     * JMX operation - return the name of the pool
+     * @return the name of the pool, unique within the JVM
+     */
+    public String getPoolName() {
+        return poolName;
+    }
+
+
+    public boolean isNotifyPool() {
+        return notifyPool;
+    }
+
+    public void setNotifyPool(boolean notifyPool) {
+        this.notifyPool = notifyPool;
+    }
+
+    /**
+     * JMX operation - remove all stats for this connection pool
+     */
+    public void resetStats() {
+        ConcurrentHashMap<String,QueryStats> queries = perPoolStats.get(poolName);
+        if (queries!=null) {
+            Iterator<String> it = queries.keySet().iterator();
+            while (it.hasNext()) it.remove();
+        }
+    }
+
+    /**
+     * JMX operation - returns all the queries we have collected.
+     * @return - the slow query report as composite data.
+     */
+    @Override
+    public CompositeData[] getSlowQueriesCD() throws OpenDataException {
+        CompositeDataSupport[] result = null;
+        ConcurrentHashMap<String,QueryStats> queries = perPoolStats.get(poolName);
+        if (queries!=null) {
+            Set<Map.Entry<String,QueryStats>> stats = queries.entrySet();
+            if (stats!=null) {
+                result = new CompositeDataSupport[stats.size()];
+                Iterator<Map.Entry<String,QueryStats>> it = stats.iterator();
+                int pos = 0;
+                while (it.hasNext()) {
+                    Map.Entry<String,QueryStats> entry = it.next();
+                    QueryStats qs = entry.getValue();
+                    result[pos++] = qs.getCompositeData(getCompositeType());
+                }
+            }
+        }
+        return result;
+    }
+
+    protected void deregisterJmx() {
+        try {
+            if (mbeans.remove(poolName)!=null) {
+                ObjectName oname = getObjectName(getClass(),poolName);
+                ManagementFactory.getPlatformMBeanServer().unregisterMBean(oname);
+            }
+        } catch (MBeanRegistrationException e) {
+            log.debug("Jmx deregistration failed.",e);
+        } catch (InstanceNotFoundException e) {
+            log.debug("Jmx deregistration failed.",e);
+        } catch (MalformedObjectNameException e) {
+            log.warn("Jmx deregistration failed.",e);
+        } catch (RuntimeOperationsException e) {
+            log.warn("Jmx deregistration failed.",e);
+        }
+
+    }
+
+
+    public ObjectName getObjectName(Class<?> clazz, String poolName) throws MalformedObjectNameException {
+        ObjectName oname;
+        Map<String,InterceptorProperty> properties = getProperties();
+        if (properties != null && properties.containsKey(objectNameAttribute)) {
+            oname = new ObjectName(properties.get(objectNameAttribute).getValue());
+        } else {
+            oname = new ObjectName(ConnectionPool.POOL_JMX_TYPE_PREFIX+clazz.getName()+",name=" + poolName);
+        }
+        return oname;
+    }
+
+    protected void registerJmx() {
+        try {
+            //only if we notify the pool itself
+            if (isNotifyPool()) {
+
+            } else if (getCompositeType()!=null) {
+                ObjectName oname = getObjectName(getClass(),poolName);
+                if (mbeans.putIfAbsent(poolName, this)==null) {
+                    ManagementFactory.getPlatformMBeanServer().registerMBean(this, oname);
+                }
+            } else {
+                log.warn(SlowQueryReport.class.getName()+ "- No JMX support, composite type was not found.");
+            }
+        } catch (MalformedObjectNameException e) {
+            log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+        } catch (RuntimeOperationsException e) {
+            log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+        } catch (MBeanException e) {
+            log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+        } catch (InstanceAlreadyExistsException e) {
+            log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+        } catch (NotCompliantMBeanException e) {
+            log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+        }
+    }
+
+    @Override
+    public void setProperties(Map<String, InterceptorProperty> properties) {
+        super.setProperties(properties);
+        final String threshold = "notifyPool";
+        InterceptorProperty p1 = properties.get(threshold);
+        if (p1!=null) {
+            this.setNotifyPool(Boolean.parseBoolean(p1.getValue()));
+        }
+    }
+
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java
new file mode 100644 (file)
index 0000000..202d06e
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.OpenDataException;
+
+public interface SlowQueryReportJmxMBean {
+    public CompositeData[] getSlowQueriesCD() throws OpenDataException;
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java
new file mode 100644 (file)
index 0000000..e98d3b6
--- /dev/null
@@ -0,0 +1,358 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * Interceptor that caches {@code PreparedStatement} and/or
+ * {@code CallableStatement} instances on a connection.
+ */
+public class StatementCache extends StatementDecoratorInterceptor {
+    protected static final String[] ALL_TYPES = new String[] {PREPARE_STATEMENT,PREPARE_CALL};
+    protected static final String[] CALLABLE_TYPE = new String[] {PREPARE_CALL};
+    protected static final String[] PREPARED_TYPE = new String[] {PREPARE_STATEMENT};
+    protected static final String[] NO_TYPE = new String[] {};
+
+    protected static final String STATEMENT_CACHE_ATTR = StatementCache.class.getName() + ".cache";
+
+    /*begin properties for the statement cache*/
+    private boolean cachePrepared = true;
+    private boolean cacheCallable = false;
+    private int maxCacheSize = 50;
+    private PooledConnection pcon;
+    private String[] types;
+
+
+    public boolean isCachePrepared() {
+        return cachePrepared;
+    }
+
+    public boolean isCacheCallable() {
+        return cacheCallable;
+    }
+
+    public int getMaxCacheSize() {
+        return maxCacheSize;
+    }
+
+    public String[] getTypes() {
+        return types;
+    }
+
+    public AtomicInteger getCacheSize() {
+        return cacheSize;
+    }
+
+    @Override
+    public void setProperties(Map<String, InterceptorProperty> properties) {
+        super.setProperties(properties);
+        InterceptorProperty p = properties.get("prepared");
+        if (p!=null) cachePrepared = p.getValueAsBoolean(cachePrepared);
+        p = properties.get("callable");
+        if (p!=null) cacheCallable = p.getValueAsBoolean(cacheCallable);
+        p = properties.get("max");
+        if (p!=null) maxCacheSize = p.getValueAsInt(maxCacheSize);
+        if (cachePrepared && cacheCallable) {
+            this.types = ALL_TYPES;
+        } else if (cachePrepared) {
+            this.types = PREPARED_TYPE;
+        } else if (cacheCallable) {
+            this.types = CALLABLE_TYPE;
+        } else {
+            this.types = NO_TYPE;
+        }
+
+    }
+    /*end properties for the statement cache*/
+
+    /*begin the cache size*/
+    private static ConcurrentHashMap<ConnectionPool,AtomicInteger> cacheSizeMap =
+        new ConcurrentHashMap<>();
+
+    private AtomicInteger cacheSize;
+
+    @Override
+    public void poolStarted(ConnectionPool pool) {
+        cacheSizeMap.putIfAbsent(pool, new AtomicInteger(0));
+        super.poolStarted(pool);
+    }
+
+    @Override
+    public void poolClosed(ConnectionPool pool) {
+        cacheSizeMap.remove(pool);
+        super.poolClosed(pool);
+    }
+    /*end the cache size*/
+
+    /*begin the actual statement cache*/
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        super.reset(parent, con);
+        if (parent==null) {
+            cacheSize = null;
+            this.pcon = null;
+        } else {
+            cacheSize = cacheSizeMap.get(parent);
+            this.pcon = con;
+            if (!pcon.getAttributes().containsKey(STATEMENT_CACHE_ATTR)) {
+                ConcurrentHashMap<CacheKey,CachedStatement> cache =
+                        new ConcurrentHashMap<>();
+                pcon.getAttributes().put(STATEMENT_CACHE_ATTR,cache);
+            }
+        }
+    }
+
+    @Override
+    public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
+        @SuppressWarnings("unchecked")
+        ConcurrentHashMap<CacheKey,CachedStatement> statements =
+            (ConcurrentHashMap<CacheKey,CachedStatement>)con.getAttributes().get(STATEMENT_CACHE_ATTR);
+
+        if (statements!=null) {
+            for (Map.Entry<CacheKey, CachedStatement> p : statements.entrySet()) {
+                closeStatement(p.getValue());
+            }
+            statements.clear();
+        }
+
+        super.disconnected(parent, con, finalizing);
+    }
+
+    public void closeStatement(CachedStatement st) {
+        if (st==null) return;
+        st.forceClose();
+    }
+
+    @Override
+    protected Object createDecorator(Object proxy, Method method, Object[] args,
+                                     Object statement, Constructor<?> constructor, String sql)
+    throws InstantiationException, IllegalAccessException, InvocationTargetException {
+        boolean process = process(this.types, method, false);
+        if (process) {
+            Object result = null;
+            CachedStatement statementProxy = new CachedStatement((Statement)statement,sql);
+            result = constructor.newInstance(new Object[] { statementProxy });
+            statementProxy.setActualProxy(result);
+            statementProxy.setConnection(proxy);
+            statementProxy.setConstructor(constructor);
+            statementProxy.setCacheKey(createCacheKey(method, args));
+            return result;
+        } else {
+            return super.createDecorator(proxy, method, args, statement, constructor, sql);
+        }
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        boolean process = process(this.types, method, false);
+        if (process && args.length>0 && args[0] instanceof String) {
+            CachedStatement statement = isCached(method, args);
+            if (statement!=null) {
+                //remove it from the cache since it is used
+                removeStatement(statement);
+                return statement.getActualProxy();
+            } else {
+                return super.invoke(proxy, method, args);
+            }
+        } else {
+            return super.invoke(proxy,method,args);
+        }
+    }
+
+    public CachedStatement isCached(Method method, Object[] args) {
+        @SuppressWarnings("unchecked")
+        ConcurrentHashMap<CacheKey,CachedStatement> cache =
+            (ConcurrentHashMap<CacheKey,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
+        return cache.get(createCacheKey(method, args));
+    }
+
+    public boolean cacheStatement(CachedStatement proxy) {
+        @SuppressWarnings("unchecked")
+        ConcurrentHashMap<CacheKey,CachedStatement> cache =
+            (ConcurrentHashMap<CacheKey,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
+        if (proxy.getCacheKey()==null) {
+            return false;
+        } else if (cache.containsKey(proxy.getCacheKey())) {
+            return false;
+        } else if (cacheSize.get()>=maxCacheSize) {
+            return false;
+        } else if (cacheSize.incrementAndGet()>maxCacheSize) {
+            cacheSize.decrementAndGet();
+            return false;
+        } else {
+            //cache the statement
+            cache.put(proxy.getCacheKey(), proxy);
+            return true;
+        }
+    }
+
+    public boolean removeStatement(CachedStatement proxy) {
+        @SuppressWarnings("unchecked")
+        ConcurrentHashMap<CacheKey,CachedStatement> cache =
+            (ConcurrentHashMap<CacheKey,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
+        if (cache.remove(proxy.getCacheKey()) != null) {
+            cacheSize.decrementAndGet();
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /*end the actual statement cache*/
+
+
+    protected class CachedStatement extends StatementDecoratorInterceptor.StatementProxy<Statement> {
+        boolean cached = false;
+        CacheKey key;
+        public CachedStatement(Statement parent, String sql) {
+            super(parent, sql);
+        }
+
+        @Override
+        public void closeInvoked() {
+            //should we cache it
+            boolean shouldClose = true;
+            if (cacheSize.get() < maxCacheSize) {
+                //cache a proxy so that we don't reuse the facade
+                CachedStatement proxy = new CachedStatement(getDelegate(),getSql());
+                proxy.setCacheKey(getCacheKey());
+                try {
+                    // clear Resultset
+                    ResultSet result = getDelegate().getResultSet();
+                    if (result != null && !result.isClosed()) {
+                        result.close();
+                    }
+                    //create a new facade
+                    Object actualProxy = getConstructor().newInstance(new Object[] { proxy });
+                    proxy.setActualProxy(actualProxy);
+                    proxy.setConnection(getConnection());
+                    proxy.setConstructor(getConstructor());
+                    if (cacheStatement(proxy)) {
+                        proxy.cached = true;
+                        shouldClose = false;
+                    }
+                } catch (Exception x) {
+                    removeStatement(proxy);
+                }
+            }
+            if (shouldClose) {
+                super.closeInvoked();
+            }
+            closed = true;
+            delegate = null;
+
+        }
+
+        public void forceClose() {
+            removeStatement(this);
+            super.closeInvoked();
+        }
+
+        public CacheKey getCacheKey() {
+            return key;
+        }
+
+        public void setCacheKey(CacheKey cacheKey) {
+            key = cacheKey;
+        }
+
+    }
+
+    protected CacheKey createCacheKey(Method method, Object[] args) {
+        return createCacheKey(method.getName(), args);
+    }
+
+    protected CacheKey createCacheKey(String methodName, Object[] args) {
+        CacheKey key = null;
+        if (compare(PREPARE_STATEMENT, methodName)) {
+            key = new CacheKey(PREPARE_STATEMENT, args);
+        } else if (compare(PREPARE_CALL, methodName)) {
+            key = new CacheKey(PREPARE_CALL, args);
+        }
+        return key;
+    }
+
+
+    private static final class CacheKey {
+        private final String stmtType;
+        private final Object[] args;
+        private CacheKey(String type, Object[] methodArgs) {
+            stmtType = type;
+            args = methodArgs;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + Arrays.hashCode(args);
+            result = prime * result
+                    + ((stmtType == null) ? 0 : stmtType.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            CacheKey other = (CacheKey) obj;
+            if (!Arrays.equals(args, other.args))
+                return false;
+            if (stmtType == null) {
+                if (other.stmtType != null)
+                    return false;
+            } else if (!stmtType.equals(other.stmtType))
+                return false;
+            return true;
+        }
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
new file mode 100644 (file)
index 0000000..e3b160b
--- /dev/null
@@ -0,0 +1,342 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Implementation of <b>JdbcInterceptor</b> that proxies resultSets and statements.
+ * @author Guillermo Fernandes
+ */
+public class StatementDecoratorInterceptor extends AbstractCreateStatementInterceptor {
+
+    private static final Log logger = LogFactory.getLog(StatementDecoratorInterceptor.class);
+
+    protected static final String EXECUTE_QUERY  = "executeQuery";
+    protected static final String GET_GENERATED_KEYS = "getGeneratedKeys";
+    protected static final String GET_RESULTSET  = "getResultSet";
+
+    protected static final String[] RESULTSET_TYPES = {EXECUTE_QUERY, GET_GENERATED_KEYS, GET_RESULTSET};
+
+    /**
+     * the constructors that are used to create statement proxies
+     */
+    protected static final Constructor<?>[] constructors = new Constructor[AbstractCreateStatementInterceptor.STATEMENT_TYPE_COUNT];
+
+    /**
+     * the constructor to create the resultSet proxies
+     */
+    protected static Constructor<?> resultSetConstructor = null;
+
+    @Override
+    public void closeInvoked() {
+        // nothing to do
+    }
+
+    /**
+     * Creates a constructor for a proxy class, if one doesn't already exist
+     *
+     * @param idx
+     *            - the index of the constructor
+     * @param clazz
+     *            - the interface that the proxy will implement
+     * @return - returns a constructor used to create new instances
+     * @throws NoSuchMethodException Constructor not found
+     */
+    protected Constructor<?> getConstructor(int idx, Class<?> clazz) throws NoSuchMethodException {
+        if (constructors[idx] == null) {
+            Class<?> proxyClass = Proxy.getProxyClass(StatementDecoratorInterceptor.class.getClassLoader(),
+                    new Class[] { clazz });
+            constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+        }
+        return constructors[idx];
+    }
+
+    protected Constructor<?> getResultSetConstructor() throws NoSuchMethodException {
+        if (resultSetConstructor == null) {
+            Class<?> proxyClass = Proxy.getProxyClass(StatementDecoratorInterceptor.class.getClassLoader(),
+                    new Class[] { ResultSet.class });
+            resultSetConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+        }
+        return resultSetConstructor;
+    }
+
+    /**
+     * Creates a statement interceptor to monitor query response times
+     */
+    @Override
+    public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
+        try {
+            String name = method.getName();
+            Constructor<?> constructor = null;
+            String sql = null;
+            if (compare(CREATE_STATEMENT, name)) {
+                // createStatement
+                constructor = getConstructor(CREATE_STATEMENT_IDX, Statement.class);
+            } else if (compare(PREPARE_STATEMENT, name)) {
+                // prepareStatement
+                constructor = getConstructor(PREPARE_STATEMENT_IDX, PreparedStatement.class);
+                sql = (String)args[0];
+            } else if (compare(PREPARE_CALL, name)) {
+                // prepareCall
+                constructor = getConstructor(PREPARE_CALL_IDX, CallableStatement.class);
+                sql = (String)args[0];
+            } else {
+                // do nothing, might be a future unsupported method
+                // so we better bail out and let the system continue
+                return statement;
+            }
+            return createDecorator(proxy, method, args, statement, constructor, sql);
+        } catch (Exception x) {
+            if (x instanceof InvocationTargetException) {
+                Throwable cause = x.getCause();
+                if (cause instanceof ThreadDeath) {
+                    throw (ThreadDeath) cause;
+                }
+                if (cause instanceof VirtualMachineError) {
+                    throw (VirtualMachineError) cause;
+                }
+            }
+            logger.warn("Unable to create statement proxy for slow query report.", x);
+        }
+        return statement;
+    }
+
+    /**
+     * Creates a proxy for a Statement.
+     *
+     * @param proxy         The proxy object on which the method that triggered
+     *                          the creation of the statement was called.
+     * @param method        The method that was called on the proxy
+     * @param args          The arguments passed as part of the method call to
+     *                          the proxy
+     * @param statement     The statement object that is to be proxied
+     * @param constructor   The constructor for the desired proxy
+     * @param sql           The sql of of the statement
+     *
+     * @return  A new proxy for the Statement
+     * @throws InstantiationException Couldn't instantiate object
+     * @throws IllegalAccessException Inaccessible constructor
+     * @throws InvocationTargetException Exception thrown from constructor
+     */
+    protected Object createDecorator(Object proxy, Method method, Object[] args,
+                                     Object statement, Constructor<?> constructor, String sql)
+    throws InstantiationException, IllegalAccessException, InvocationTargetException {
+        Object result = null;
+        StatementProxy<Statement> statementProxy =
+                new StatementProxy<>((Statement)statement,sql);
+        result = constructor.newInstance(new Object[] { statementProxy });
+        statementProxy.setActualProxy(result);
+        statementProxy.setConnection(proxy);
+        statementProxy.setConstructor(constructor);
+        return result;
+    }
+
+    protected boolean isExecuteQuery(String methodName) {
+        return EXECUTE_QUERY.equals(methodName);
+    }
+
+    protected boolean isExecuteQuery(Method method) {
+        return isExecuteQuery(method.getName());
+    }
+
+    protected boolean isResultSet(Method method, boolean process) {
+        return process(RESULTSET_TYPES, method, process);
+    }
+
+    /**
+     * Class to measure query execute time.
+     */
+    protected class StatementProxy<T extends java.sql.Statement> implements InvocationHandler {
+
+        protected boolean closed = false;
+        protected T delegate;
+        private Object actualProxy;
+        private Object connection;
+        private String sql;
+        private Constructor<?> constructor;
+
+        public StatementProxy(T delegate, String sql) {
+            this.delegate = delegate;
+            this.sql = sql;
+        }
+        public T getDelegate() {
+            return this.delegate;
+        }
+
+        public String getSql() {
+            return sql;
+        }
+
+        public void setConnection(Object proxy) {
+            this.connection = proxy;
+        }
+        public Object getConnection() {
+            return this.connection;
+        }
+
+        public void setActualProxy(Object proxy){
+            this.actualProxy = proxy;
+        }
+        public Object getActualProxy() {
+            return this.actualProxy;
+        }
+
+
+        public Constructor<?> getConstructor() {
+            return constructor;
+        }
+        public void setConstructor(Constructor<?> constructor) {
+            this.constructor = constructor;
+        }
+        public void closeInvoked() {
+            if (getDelegate()!=null) {
+                try {
+                    getDelegate().close();
+                }catch (SQLException ignore) {
+                }
+            }
+            closed = true;
+            delegate = null;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (compare(TOSTRING_VAL,method)) {
+                return toString();
+            }
+            // was close invoked?
+            boolean close = compare(CLOSE_VAL, method);
+            // allow close to be called multiple times
+            if (close && closed)
+                return null;
+            // are we calling isClosed?
+            if (compare(ISCLOSED_VAL, method))
+                return Boolean.valueOf(closed);
+            // if we are calling anything else, bail out
+            if (closed)
+                throw new SQLException("Statement closed.");
+            if (compare(GETCONNECTION_VAL,method)){
+                return connection;
+            }
+            boolean process = false;
+            process = isResultSet(method, process);
+            // check to see if we are about to execute a query
+            // if we are executing, get the current time
+            Object result = null;
+            try {
+                // perform close cleanup
+                if (close) {
+                    closeInvoked();
+                } else {
+                    // execute the query
+                    result = method.invoke(delegate, args);
+                }
+            } catch (Throwable t) {
+                if (t instanceof InvocationTargetException
+                        && t.getCause() != null) {
+                    throw t.getCause();
+                } else {
+                    throw t;
+                }
+            }
+            if (process && result != null) {
+                Constructor<?> cons = getResultSetConstructor();
+                result = cons.newInstance(new Object[]{new ResultSetProxy(actualProxy, result)});
+            }
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            StringBuffer buf = new StringBuffer(StatementProxy.class.getName());
+            buf.append("[Proxy=");
+            buf.append(System.identityHashCode(this));
+            buf.append("; Sql=");
+            buf.append(getSql());
+            buf.append("; Delegate=");
+            buf.append(getDelegate());
+            buf.append("; Connection=");
+            buf.append(getConnection());
+            buf.append("]");
+            return buf.toString();
+        }
+    }
+
+    protected class ResultSetProxy implements InvocationHandler {
+
+        private Object st;
+        private Object delegate;
+
+        public ResultSetProxy(Object st, Object delegate) {
+            this.st = st;
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (method.getName().equals("getStatement")) {
+                return this.st;
+            } else {
+                try {
+                    return method.invoke(this.delegate, args);
+                } catch (Throwable t) {
+                    if (t instanceof InvocationTargetException
+                            && t.getCause() != null) {
+                        throw t.getCause();
+                    } else {
+                        throw t;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java
new file mode 100644 (file)
index 0000000..6535139
--- /dev/null
@@ -0,0 +1,136 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.interceptor;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.sql.Statement;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * Keeps track of statements associated with a connection and invokes close upon {@link java.sql.Connection#close()}
+ * Useful for applications that dont close the associated statements after being done with a connection.
+ *
+ */
+public class StatementFinalizer extends AbstractCreateStatementInterceptor {
+    private static final Log log = LogFactory.getLog(StatementFinalizer.class);
+
+    protected List<StatementEntry> statements = new LinkedList<>();
+
+    private boolean logCreationStack = false;
+
+    @Override
+    public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
+        try {
+            if (statement instanceof Statement)
+                statements.add(new StatementEntry((Statement)statement));
+        }catch (ClassCastException x) {
+            //ignore this one
+        }
+        return statement;
+    }
+
+    @SuppressWarnings("null") // st is not null when used
+    @Override
+    public void closeInvoked() {
+        while (statements.size()>0) {
+            StatementEntry ws = statements.remove(0);
+            Statement st = ws.getStatement();
+            boolean shallClose = false;
+            try {
+                shallClose = st!=null && (!st.isClosed());
+                if (shallClose) {
+                    st.close();
+                }
+            } catch (Exception ignore) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Unable to closed statement upon connection close.",ignore);
+                }
+            } finally {
+                if (logCreationStack && shallClose) {
+                    log.warn("Statement created, but was not closed at:", ws.getAllocationStack());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setProperties(Map<String, PoolProperties.InterceptorProperty> properties) {
+        super.setProperties(properties);
+
+        PoolProperties.InterceptorProperty logProperty = properties.get("trace");
+        if (null != logProperty) {
+            logCreationStack = logProperty.getValueAsBoolean(logCreationStack);
+        }
+    }
+
+    @Override
+    public void reset(ConnectionPool parent, PooledConnection con) {
+        statements.clear();
+        super.reset(parent, con);
+    }
+
+    protected class StatementEntry {
+        private WeakReference<Statement> statement;
+        private Throwable allocationStack;
+
+        public StatementEntry(Statement statement) {
+            this.statement = new WeakReference<>(statement);
+            if (logCreationStack) {
+                this.allocationStack = new Throwable();
+            }
+        }
+
+        public Statement getStatement() {
+            return statement.get();
+        }
+
+        public Throwable getAllocationStack() {
+            return allocationStack;
+        }
+    }
+
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml
new file mode 100644 (file)
index 0000000..0cca7ad
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  openecomp
+  ================================================================================
+  Copyright (C) 2016 - 2017 AT&T
+  ================================================================================
+  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.
+  ============LICENSE_END=========================================================
+  -->
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<mbeans-descriptors>
+
+  <mbean description="Reports " domain="tomcat.jdbc" group="jdbc-pool" name="SlowQueryReportJmx"
+         type="org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx">
+
+    <attribute description="The name of the connection pool this Jmx bean is representing" name="poolName" type="java.lang.String" writeable="false"/>
+    <attribute description="List of all registered connections pools" name="poolNames" type="[java.lang.String;" writeable="false"/>
+    <attribute description="All the recorded query stats. " name="slowQueriesCD" type="[javax.management.openmbean.CompositeData;" writeable="false"/>
+    <operation description="Clears all the query stats" impact="ACTION" name="resetStats" returnType="void"/>
+
+    <notification description="Notification sent out by the slow query report when a query exceeds the threshold" name="slow-query">
+      <notification-type>Slow query</notification-type>
+    </notification>
+
+    <notification description="Notification sent out by the slow query report when a query fails execution" name="failed-query">
+      <notification-type>Failed query execution</notification-type>
+    </notification>
+  </mbean>
+</mbeans-descriptors>
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
new file mode 100644 (file)
index 0000000..9044bae
--- /dev/null
@@ -0,0 +1,960 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.jmx;
+
+import java.util.Properties;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
+import org.apache.tomcat.jdbc.pool.PoolUtilities;
+import org.apache.tomcat.jdbc.pool.Validator;
+
+public class ConnectionPool extends NotificationBroadcasterSupport implements ConnectionPoolMBean  {
+    /**
+     * logger
+     */
+    private static final Log log = LogFactory.getLog(ConnectionPool.class);
+
+    /**
+     * the connection pool
+     */
+    protected org.apache.tomcat.jdbc.pool.ConnectionPool pool = null;
+    /**
+     * sequence for JMX notifications
+     */
+    protected AtomicInteger sequence = new AtomicInteger(0);
+
+    /**
+     * Listeners that are local and interested in our notifications, no need for JMX
+     */
+    protected ConcurrentLinkedQueue<NotificationListener> listeners =
+            new ConcurrentLinkedQueue<>();
+
+    public ConnectionPool(org.apache.tomcat.jdbc.pool.ConnectionPool pool) {
+        super();
+        this.pool = pool;
+    }
+
+    public org.apache.tomcat.jdbc.pool.ConnectionPool getPool() {
+        return pool;
+    }
+
+    public PoolConfiguration getPoolProperties() {
+        return pool.getPoolProperties();
+    }
+
+    //=================================================================
+    //       NOTIFICATION INFO
+    //=================================================================
+    public static final String NOTIFY_INIT = "INIT FAILED";
+    public static final String NOTIFY_CONNECT = "CONNECTION FAILED";
+    public static final String NOTIFY_ABANDON = "CONNECTION ABANDONED";
+    public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
+    public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
+    public static final String SUSPECT_ABANDONED_NOTIFICATION = "SUSPECT CONNECTION ABANDONED";
+    public static final String POOL_EMPTY = "POOL EMPTY";
+    public static final String SUSPECT_RETURNED_NOTIFICATION = "SUSPECT CONNECTION RETURNED";
+
+    @Override
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        MBeanNotificationInfo[] pres = super.getNotificationInfo();
+        MBeanNotificationInfo[] loc = getDefaultNotificationInfo();
+        MBeanNotificationInfo[] aug = new MBeanNotificationInfo[pres.length + loc.length];
+        if (pres.length>0) System.arraycopy(pres, 0, aug, 0, pres.length);
+        if (loc.length >0) System.arraycopy(loc, 0, aug, pres.length, loc.length);
+        return aug;
+    }
+
+    public static MBeanNotificationInfo[] getDefaultNotificationInfo() {
+        String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON, SLOW_QUERY_NOTIFICATION,
+                FAILED_QUERY_NOTIFICATION, SUSPECT_ABANDONED_NOTIFICATION, POOL_EMPTY, SUSPECT_RETURNED_NOTIFICATION};
+        String name = Notification.class.getName();
+        String description = "A connection pool error condition was met.";
+        MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
+        return new MBeanNotificationInfo[] {info};
+    }
+
+    /**
+     * Return true if the notification was sent successfully, false otherwise.
+     * @param type The notification type
+     * @param message The message
+     * @return true if the notification succeeded
+     */
+    public boolean notify(final String type, String message) {
+        try {
+            Notification n = new Notification(
+                    type,
+                    this,
+                    sequence.incrementAndGet(),
+                    System.currentTimeMillis(),
+                    "["+type+"] "+message);
+            sendNotification(n);
+            for (NotificationListener listener : listeners) {
+                listener.handleNotification(n,this);
+            }
+            return true;
+        }catch (Exception x) {
+            if (log.isDebugEnabled()) {
+                log.debug("Notify failed. Type="+type+"; Message="+message,x);
+            }
+            return false;
+        }
+
+    }
+
+    public void addListener(NotificationListener list) {
+        listeners.add(list);
+    }
+
+    public boolean removeListener(NotificationListener list) {
+        return listeners.remove(list);
+    }
+
+    //=================================================================
+    //       POOL STATS
+    //=================================================================
+
+    @Override
+    public int getSize() {
+        return pool.getSize();
+    }
+
+    @Override
+    public int getIdle() {
+        return pool.getIdle();
+    }
+
+    @Override
+    public int getActive() {
+        return pool.getActive();
+    }
+
+    @Override
+    public int getNumIdle() {
+        return getIdle();
+    }
+
+    @Override
+    public int getNumActive() {
+        return getActive();
+    }
+
+    @Override
+    public int getWaitCount() {
+        return pool.getWaitCount();
+    }
+
+    @Override
+    public long getBorrowedCount() {
+        return pool.getBorrowedCount();
+    }
+
+    @Override
+    public long getReturnedCount() {
+        return pool.getReturnedCount();
+    }
+
+    @Override
+    public long getCreatedCount() {
+        return pool.getCreatedCount();
+    }
+
+    @Override
+    public long getReleasedCount() {
+        return pool.getReleasedCount();
+    }
+
+    @Override
+    public long getReconnectedCount() {
+        return pool.getReconnectedCount();
+    }
+
+    @Override
+    public long getRemoveAbandonedCount() {
+        return pool.getRemoveAbandonedCount();
+    }
+
+    @Override
+    public long getReleasedIdleCount() {
+        return pool.getReleasedIdleCount();
+    }
+
+    //=================================================================
+    //       POOL OPERATIONS
+    //=================================================================
+    @Override
+    public void checkIdle() {
+        pool.checkIdle();
+    }
+
+    @Override
+    public void checkAbandoned() {
+        pool.checkAbandoned();
+    }
+
+    @Override
+    public void testIdle() {
+        pool.testAllIdle();
+    }
+
+    @Override
+    public void resetStats() {
+        pool.resetStats();
+    }
+
+    //=================================================================
+    //       POOL PROPERTIES
+    //=================================================================
+    //=========================================================
+    //  PROPERTIES / CONFIGURATION
+    //=========================================================
+
+
+    @Override
+    public String getConnectionProperties() {
+        return getPoolProperties().getConnectionProperties();
+    }
+
+    @Override
+    public Properties getDbProperties() {
+        return PoolUtilities.cloneWithoutPassword(getPoolProperties().getDbProperties());
+    }
+
+    @Override
+    public String getDefaultCatalog() {
+        return getPoolProperties().getDefaultCatalog();
+    }
+
+    @Override
+    public int getDefaultTransactionIsolation() {
+        return getPoolProperties().getDefaultTransactionIsolation();
+    }
+
+    @Override
+    public String getDriverClassName() {
+        return getPoolProperties().getDriverClassName();
+    }
+
+
+    @Override
+    public int getInitialSize() {
+        return getPoolProperties().getInitialSize();
+    }
+
+    @Override
+    public String getInitSQL() {
+        return getPoolProperties().getInitSQL();
+    }
+
+    @Override
+    public String getJdbcInterceptors() {
+        return getPoolProperties().getJdbcInterceptors();
+    }
+
+    @Override
+    public int getMaxActive() {
+        return getPoolProperties().getMaxActive();
+    }
+
+    @Override
+    public int getMaxIdle() {
+        return getPoolProperties().getMaxIdle();
+    }
+
+    @Override
+    public int getMaxWait() {
+        return getPoolProperties().getMaxWait();
+    }
+
+    @Override
+    public int getMinEvictableIdleTimeMillis() {
+        return getPoolProperties().getMinEvictableIdleTimeMillis();
+    }
+
+    @Override
+    public int getMinIdle() {
+        return getPoolProperties().getMinIdle();
+    }
+
+    @Override
+    public long getMaxAge() {
+        return getPoolProperties().getMaxAge();
+    }
+
+    @Override
+    public String getName() {
+        return this.getPoolName();
+    }
+
+    @Override
+    public int getNumTestsPerEvictionRun() {
+        return getPoolProperties().getNumTestsPerEvictionRun();
+    }
+
+    /**
+     * @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
+     */
+    @Override
+    public String getPassword() {
+        return "Password not available as DataSource/JMX operation.";
+    }
+
+    @Override
+    public int getRemoveAbandonedTimeout() {
+        return getPoolProperties().getRemoveAbandonedTimeout();
+    }
+
+
+    @Override
+    public int getTimeBetweenEvictionRunsMillis() {
+        return getPoolProperties().getTimeBetweenEvictionRunsMillis();
+    }
+
+    @Override
+    public String getUrl() {
+        return getPoolProperties().getUrl();
+    }
+
+    @Override
+    public String getUsername() {
+        return getPoolProperties().getUsername();
+    }
+
+    @Override
+    public long getValidationInterval() {
+        return getPoolProperties().getValidationInterval();
+    }
+
+    @Override
+    public String getValidationQuery() {
+        return getPoolProperties().getValidationQuery();
+    }
+
+    @Override
+    public int getValidationQueryTimeout() {
+        return getPoolProperties().getValidationQueryTimeout();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public String getValidatorClassName() {
+        return getPoolProperties().getValidatorClassName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public Validator getValidator() {
+        return getPoolProperties().getValidator();
+    }
+
+    @Override
+    public boolean isAccessToUnderlyingConnectionAllowed() {
+        return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
+    }
+
+    @Override
+    public Boolean isDefaultAutoCommit() {
+        return getPoolProperties().isDefaultAutoCommit();
+    }
+
+    @Override
+    public Boolean isDefaultReadOnly() {
+        return getPoolProperties().isDefaultReadOnly();
+    }
+
+    @Override
+    public boolean isLogAbandoned() {
+        return getPoolProperties().isLogAbandoned();
+    }
+
+    @Override
+    public boolean isPoolSweeperEnabled() {
+        return getPoolProperties().isPoolSweeperEnabled();
+    }
+
+    @Override
+    public boolean isRemoveAbandoned() {
+        return getPoolProperties().isRemoveAbandoned();
+    }
+
+    @Override
+    public int getAbandonWhenPercentageFull() {
+        return getPoolProperties().getAbandonWhenPercentageFull();
+    }
+
+    @Override
+    public boolean isTestOnBorrow() {
+        return getPoolProperties().isTestOnBorrow();
+    }
+
+    @Override
+    public boolean isTestOnConnect() {
+        return getPoolProperties().isTestOnConnect();
+    }
+
+    @Override
+    public boolean isTestOnReturn() {
+        return getPoolProperties().isTestOnReturn();
+    }
+
+    @Override
+    public boolean isTestWhileIdle() {
+        return getPoolProperties().isTestWhileIdle();
+    }
+
+
+    @Override
+    public Boolean getDefaultAutoCommit() {
+        return getPoolProperties().getDefaultAutoCommit();
+    }
+
+    @Override
+    public Boolean getDefaultReadOnly() {
+        return getPoolProperties().getDefaultReadOnly();
+    }
+
+    @Override
+    public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
+        return getPoolProperties().getJdbcInterceptorsAsArray();
+    }
+
+    @Override
+    public boolean getUseLock() {
+        return getPoolProperties().getUseLock();
+    }
+
+    @Override
+    public boolean isFairQueue() {
+        return getPoolProperties().isFairQueue();
+    }
+
+    @Override
+    public boolean isJmxEnabled() {
+        return getPoolProperties().isJmxEnabled();
+    }
+
+    @Override
+    public boolean isUseEquals() {
+        return getPoolProperties().isUseEquals();
+    }
+
+    @Override
+    public void setAbandonWhenPercentageFull(int percentage) {
+        getPoolProperties().setAbandonWhenPercentageFull(percentage);
+    }
+
+    @Override
+    public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
+        getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
+    }
+
+    @Override
+    public void setDbProperties(Properties dbProperties) {
+        getPoolProperties().setDbProperties(dbProperties);
+    }
+
+    @Override
+    public void setDefaultReadOnly(Boolean defaultReadOnly) {
+        getPoolProperties().setDefaultReadOnly(defaultReadOnly);
+    }
+
+    @Override
+    public void setMaxAge(long maxAge) {
+        getPoolProperties().setMaxAge(maxAge);
+    }
+
+    @Override
+    public void setName(String name) {
+        getPoolProperties().setName(name);
+    }
+
+    @Override
+    public String getPoolName() {
+        return getPoolProperties().getName();
+    }
+
+
+    @Override
+    public void setConnectionProperties(String connectionProperties) {
+        getPoolProperties().setConnectionProperties(connectionProperties);
+
+    }
+
+    @Override
+    public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
+        getPoolProperties().setDefaultAutoCommit(defaultAutoCommit);
+    }
+
+    @Override
+    public void setDefaultCatalog(String defaultCatalog) {
+        getPoolProperties().setDefaultCatalog(defaultCatalog);
+    }
+
+    @Override
+    public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
+        getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
+    }
+
+    @Override
+    public void setDriverClassName(String driverClassName) {
+        getPoolProperties().setDriverClassName(driverClassName);
+    }
+
+
+    @Override
+    public void setFairQueue(boolean fairQueue) {
+        // noop - this pool is already running
+        throw new UnsupportedOperationException();
+    }
+
+
+    @Override
+    public void setInitialSize(int initialSize) {
+        // noop - this pool is already running
+        throw new UnsupportedOperationException();
+
+    }
+
+
+    @Override
+    public void setInitSQL(String initSQL) {
+        getPoolProperties().setInitSQL(initSQL);
+
+    }
+
+
+    @Override
+    public void setJdbcInterceptors(String jdbcInterceptors) {
+        // noop - this pool is already running
+        throw new UnsupportedOperationException();
+    }
+
+
+    @Override
+    public void setJmxEnabled(boolean jmxEnabled) {
+        // noop - this pool is already running and obviously jmx enabled
+        throw new UnsupportedOperationException();
+    }
+
+
+    @Override
+    public void setLogAbandoned(boolean logAbandoned) {
+        getPoolProperties().setLogAbandoned(logAbandoned);
+    }
+
+
+    @Override
+    public void setMaxActive(int maxActive) {
+        getPoolProperties().setMaxActive(maxActive);
+        //make sure the pool is properly configured
+        pool.checkPoolConfiguration(getPoolProperties());
+    }
+
+
+    @Override
+    public void setMaxIdle(int maxIdle) {
+        getPoolProperties().setMaxIdle(maxIdle);
+        //make sure the pool is properly configured
+        pool.checkPoolConfiguration(getPoolProperties());
+
+    }
+
+
+    @Override
+    public void setMaxWait(int maxWait) {
+        getPoolProperties().setMaxWait(maxWait);
+    }
+
+
+    @Override
+    public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+        boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
+        getPoolProperties().setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+        boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
+        //make sure pool cleaner starts/stops when it should
+        if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
+        else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
+    }
+
+
+    @Override
+    public void setMinIdle(int minIdle) {
+        getPoolProperties().setMinIdle(minIdle);
+        //make sure the pool is properly configured
+        pool.checkPoolConfiguration(getPoolProperties());
+    }
+
+
+    @Override
+    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+        getPoolProperties().setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+    }
+
+
+    @Override
+    public void setPassword(String password) {
+        getPoolProperties().setPassword(password);
+    }
+
+
+    @Override
+    public void setRemoveAbandoned(boolean removeAbandoned) {
+        boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
+        getPoolProperties().setRemoveAbandoned(removeAbandoned);
+        boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
+        //make sure pool cleaner starts/stops when it should
+        if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
+        else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
+    }
+
+
+    @Override
+    public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
+        boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
+        getPoolProperties().setRemoveAbandonedTimeout(removeAbandonedTimeout);
+        boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
+        //make sure pool cleaner starts/stops when it should
+        if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
+        else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
+    }
+
+
+    @Override
+    public void setTestOnBorrow(boolean testOnBorrow) {
+        getPoolProperties().setTestOnBorrow(testOnBorrow);
+    }
+
+
+    @Override
+    public void setTestOnConnect(boolean testOnConnect) {
+        getPoolProperties().setTestOnConnect(testOnConnect);
+    }
+
+
+    @Override
+    public void setTestOnReturn(boolean testOnReturn) {
+        getPoolProperties().setTestOnReturn(testOnReturn);
+    }
+
+
+    @Override
+    public void setTestWhileIdle(boolean testWhileIdle) {
+        boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
+        getPoolProperties().setTestWhileIdle(testWhileIdle);
+        boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
+        //make sure pool cleaner starts/stops when it should
+        if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
+        else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
+    }
+
+
+    @Override
+    public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
+        boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
+        getPoolProperties().setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+        boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
+        //make sure pool cleaner starts/stops when it should
+        if (!wasEnabled && shouldBeEnabled) {
+            pool.initializePoolCleaner(getPoolProperties());
+        } else if (wasEnabled) {
+            pool.terminatePoolCleaner();
+            if (shouldBeEnabled) {
+                pool.initializePoolCleaner(getPoolProperties());
+            }
+        }
+    }
+
+
+    @Override
+    public void setUrl(String url) {
+        getPoolProperties().setUrl(url);
+    }
+
+
+    @Override
+    public void setUseEquals(boolean useEquals) {
+        getPoolProperties().setUseEquals(useEquals);
+    }
+
+
+    @Override
+    public void setUseLock(boolean useLock) {
+        getPoolProperties().setUseLock(useLock);
+    }
+
+
+    @Override
+    public void setUsername(String username) {
+        getPoolProperties().setUsername(username);
+    }
+
+
+    @Override
+    public void setValidationInterval(long validationInterval) {
+        getPoolProperties().setValidationInterval(validationInterval);
+    }
+
+
+    @Override
+    public void setValidationQuery(String validationQuery) {
+        getPoolProperties().setValidationQuery(validationQuery);
+    }
+
+    @Override
+    public void setValidationQueryTimeout(int validationQueryTimeout) {
+        getPoolProperties().setValidationQueryTimeout(validationQueryTimeout);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setValidatorClassName(String className) {
+        getPoolProperties().setValidatorClassName(className);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public int getSuspectTimeout() {
+        return getPoolProperties().getSuspectTimeout();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+
+    @Override
+    public void setSuspectTimeout(int seconds) {
+        getPoolProperties().setSuspectTimeout(seconds);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDataSource(Object ds) {
+        getPoolProperties().setDataSource(ds);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object getDataSource() {
+        return getPoolProperties().getDataSource();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDataSourceJNDI(String jndiDS) {
+        getPoolProperties().setDataSourceJNDI(jndiDS);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getDataSourceJNDI() {
+        return getPoolProperties().getDataSourceJNDI();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAlternateUsernameAllowed() {
+        return getPoolProperties().isAlternateUsernameAllowed();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
+        getPoolProperties().setAlternateUsernameAllowed(alternateUsernameAllowed);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValidator(Validator validator) {
+        getPoolProperties().setValidator(validator);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setCommitOnReturn(boolean commitOnReturn) {
+        getPoolProperties().setCommitOnReturn(commitOnReturn);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getCommitOnReturn() {
+        return getPoolProperties().getCommitOnReturn();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setRollbackOnReturn(boolean rollbackOnReturn) {
+        getPoolProperties().setRollbackOnReturn(rollbackOnReturn);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getRollbackOnReturn() {
+        return getPoolProperties().getRollbackOnReturn();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUseDisposableConnectionFacade(boolean useDisposableConnectionFacade) {
+        getPoolProperties().setUseDisposableConnectionFacade(useDisposableConnectionFacade);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getUseDisposableConnectionFacade() {
+        return getPoolProperties().getUseDisposableConnectionFacade();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setLogValidationErrors(boolean logValidationErrors) {
+        getPoolProperties().setLogValidationErrors(logValidationErrors);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getLogValidationErrors() {
+        return getPoolProperties().getLogValidationErrors();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getPropagateInterruptState() {
+        return getPoolProperties().getPropagateInterruptState();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setPropagateInterruptState(boolean propagateInterruptState) {
+        getPoolProperties().setPropagateInterruptState(propagateInterruptState);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isIgnoreExceptionOnPreLoad() {
+        return getPoolProperties().isIgnoreExceptionOnPreLoad();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setIgnoreExceptionOnPreLoad(boolean ignoreExceptionOnPreLoad) {
+        // noop - this pool is already running
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void purge() {
+        pool.purge();
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void purgeOnReturn() {
+        pool.purgeOnReturn();
+
+    }
+
+
+
+
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java
new file mode 100644 (file)
index 0000000..bc3bbca
--- /dev/null
@@ -0,0 +1,107 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool.jmx;
+
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+
+public interface ConnectionPoolMBean extends PoolConfiguration  {
+
+    //=================================================================
+    //       POOL STATS
+    //=================================================================
+
+    public int getSize();
+
+    public int getIdle();
+
+    public int getActive();
+
+    public int getNumIdle();
+
+    public int getNumActive();
+
+    public int getWaitCount();
+
+    public long getBorrowedCount();
+
+    public long getReturnedCount();
+
+    public long getCreatedCount();
+
+    public long getReleasedCount();
+
+    public long getReconnectedCount();
+
+    public long getRemoveAbandonedCount();
+
+    public long getReleasedIdleCount();
+
+    //=================================================================
+    //       POOL OPERATIONS
+    //=================================================================
+    public void checkIdle();
+
+    public void checkAbandoned();
+
+    public void testIdle();
+
+    /**
+     * Purges all connections in the pool.
+     * For connections currently in use, these connections will be
+     * purged when returned on the pool. This call also
+     * purges connections that are idle and in the pool
+     * To only purge used/active connections see {@link #purgeOnReturn()}
+     */
+    public void purge();
+
+    /**
+     * Purges connections when they are returned from the pool.
+     * This call does not purge idle connections until they are used.
+     * To purge idle connections see {@link #purge()}
+     */
+    public void purgeOnReturn();
+
+    /**
+     * reset the statistics of this pool.
+     */
+    public void resetStats();
+
+    //=================================================================
+    //       POOL NOTIFICATIONS
+    //=================================================================
+
+
+}
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml
new file mode 100644 (file)
index 0000000..591c1d1
--- /dev/null
@@ -0,0 +1,420 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  openecomp
+  ================================================================================
+  Copyright (C) 2016 - 2017 AT&T
+  ================================================================================
+  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.
+  ============LICENSE_END=========================================================
+  -->
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<mbeans-descriptors>
+
+    <mbean        name="TomcatJDBCPool"
+           description="Provides per diagnostic metrics and notifications for JDBC operations"
+                domain="tomcat"
+                 group="jdbc"
+                  type="org.apache.tomcat.jdbc.pool.DataSource">
+
+    <attribute    name="className"
+           description="Fully qualified class name of the managed object"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="size"
+           description="The number of established connections in the pool, idle and in use"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="idle"
+           description="The number of established connections in the pool that are idle"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="numIdle"
+           description="Same as the idle attribute"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="active"
+           description="The number of established connections in the pool that are in use"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="numActive"
+           description="Same as the active attribute"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="poolSweeperEnabled"
+           description="Returns true if the pool has a background thread running"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="url"
+           description="The JDBC url for this connection pool"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="driverClassName"
+           description="The JDBC driver class for this connection pool"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="defaultAutoCommit"
+           description="The JDBC auto commit setting for new connections"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="defaultReadOnly"
+           description="The JDBC read only setting for new connections"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="defaultTransactionIsolation"
+           description="The JDBC transaction isolation setting for new connections"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="connectionProperties"
+           description="The connection properties that will be set for new connections. Format of the string will be [propertyName=property;]*"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="defaultCatalog"
+           description="The JDBC transaction isolation setting for new connections"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="initialSize"
+           description="The number of connections opened at pool startup"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="maxActive"
+           description="The maximum number of open connections"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="maxIdle"
+           description="The max number of idle connections"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="minIdle"
+           description="The minimum number of open connections"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="maxWait"
+           description="The time to wait in milliseconds before a SQLException is thrown when a connection is requested"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="validationQuery"
+           description="The query to run during validation"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="validationQueryTimeout"
+           description="The timeout in seconds before a connection validation queries fail"
+                  type="java.lang.Integer"
+             writeable="false" />
+
+    <attribute    name="testOnBorrow"
+           description="True if validation happens when a connection is requested"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="testOnReturn"
+           description="True if validation happens when a connection is returned"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="testWhileIdle"
+           description="True if validation happens when a connection is not in use (idle)"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="timeBetweenEvictionRunsMillis"
+           description="Sleep time for background thread in between pool checks"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="numTestsPerEvictionRun"
+           description="Not in use"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="minEvictableIdleTimeMillis"
+           description="Minimum amount of time a connection stays idle before it is evicted"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="accessToUnderlyingConnectionAllowed"
+           description="Returns true if one can retrieve the actual JDBC connection"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="removeAbandoned"
+           description="Returns true if connection in use can be timed out"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="removeAbandonedTimeout"
+           description="Timeout in seconds for connections in use"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="logAbandoned"
+           description="If true, stack trace will be recorded and printed out for timed out connection"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="loginTimeout"
+           description="Not in use"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+
+    <attribute    name="name"
+           description="The name of the connection pool, will be used in the ObjectName of the actual pool"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="password"
+           description="For security purposes,this doesn't return anything"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="username"
+           description="The username used to open connections"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="validationInterval"
+           description="If larger than zero than validation will only occur after the interval milliseconds has passed"
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="initSQL"
+           description="A SQL executed once per connection, when it is established"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="testOnConnect"
+           description="Validate connection after connection has been established"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="jdbcInterceptors"
+           description="The interceptors configured for this pool"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="jmxEnabled"
+           description="Register the pool with JMX or not"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="fairQueue"
+           description="a fair queue is being used by the connection pool"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="abandonWhenPercentageFull"
+           description="Connections that have been abandoned isn't closed unless connections in use are above this percentage"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="maxAge"
+           description="Time in milliseconds to keep this connection alive even when used"
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="useEquals"
+           description="Set to true if you wish the ProxyConnection class to use String.equals and set to false when you wish to use == when comparing method names"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="useLock"
+           description="If true, use a lock when operations are performed on the connection object"
+                  type="java.lang.Boolean"
+                    is="false"
+             writeable="false"/>
+
+    <attribute    name="suspectTimeout"
+           description="Timeout in seconds for connection that suspected to have been abandoned"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="rollbackOnReturn"
+           description="If autoCommit==false then the pool can terminate the transaction by calling rollback on the connection as it is returned to the pool"
+                  type="java.lang.Boolean"
+                    is="false"
+             writeable="false"/>
+
+    <attribute    name="commitOnReturn"
+           description="If autoCommit==false then the pool can complete the transaction by calling commit on the connection as it is returned to the pool"
+                  type="java.lang.Boolean"
+                    is="false"
+             writeable="false"/>
+
+    <attribute    name="alternateUsernameAllowed"
+           description="If true, getConnection(username,password) is allowed"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="dataSource"
+           description="Data source that is injected into the pool"
+                  type="javax.sql.DataSource"
+             writeable="false"/>
+
+    <attribute    name="dataSourceJNDI"
+           description="The JNDI name for a data source to be looked up"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="useDisposableConnectionFacade"
+           description="If true, connection pool is configured to use a connection facade to prevent re-use of connection after close() has been invoked"
+                  type="java.lang.Boolean"
+                    is="false"
+             writeable="false"/>
+
+    <attribute    name="logValidationErrors"
+           description="Log errors during the validation phase to the log file"
+                  type="java.lang.Boolean"
+                    is="false"
+             writeable="false"/>
+
+    <attribute    name="validatorClassName"
+           description="The name of validator class which implements org.apache.tomcat.jdbc.pool.Validator interface"
+                  type="java.lang.String"
+             writeable="false"/>
+
+    <attribute    name="waitCount"
+           description="The number of threads waiting for a connection"
+                  type="java.lang.Integer"
+             writeable="false"/>
+
+    <attribute    name="propagateInterruptState"
+           description="If true, propagate the interrupt state for a thread that has been interrupted"
+                  type="java.lang.Boolean"
+                    is="false"
+             writeable="false"/>
+
+    <attribute    name="ignoreExceptionOnPreLoad"
+           description="If true, ignore error of connection creation while initializing the pool"
+                  type="java.lang.Boolean"
+                    is="true"
+             writeable="false"/>
+
+    <attribute    name="borrowedCount"
+           description="The total number of connections borrowed from this pool"
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="createdCount"
+           description="The total number of connections created by this pool"
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="returnedCount"
+           description="The total number of connections returned to this pool"
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="releasedCount"
+           description="The total number of connections released from this pool"
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="reconnectedCount"
+           description="The total number of connections reconnected by this pool."
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="removeAbandonedCount"
+           description="The total number of connections released by remove abandoned."
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <attribute    name="releasedIdleCount"
+           description="The total number of connections released by eviction."
+                  type="java.lang.Long"
+             writeable="false"/>
+
+    <operation    name="checkIdle"
+                  description="forces a check of idle connections"
+                  impact="ACTION"
+                  returnType="void" />
+
+    <operation    name="checkAbandoned"
+                  description="forces a check of abandoned connections"
+                  impact="ACTION"
+                  returnType="void" />
+
+    <operation    name="testIdle"
+                  description="forces a validation of abandoned connections"
+                  impact="ACTION"
+                  returnType="void" />
+
+    <operation    name="purge"
+                  description="Purges all connections in the pool"
+                  impact="ACTION"
+                  returnType="void" />
+
+    <operation    name="purgeOnReturn"
+                  description="Purges connections when they are returned from the pool"
+                  impact="ACTION"
+                  returnType="void" />
+
+    <operation    name="resetStats"
+                  description="reset the statistics of this pool."
+                  impact="ACTION"
+                  returnType="void" />
+
+  </mbean>
+
+</mbeans-descriptors>
diff --git a/dblib/common/src/main/java/org/openecomp/sdnc/sli/resource/common/CommonActivator.java b/dblib/common/src/main/java/org/openecomp/sdnc/sli/resource/common/CommonActivator.java
new file mode 100644 (file)
index 0000000..6a0ed06
--- /dev/null
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.resource.common;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class CommonActivator implements BundleActivator {
+
+       @Override
+       public void start(BundleContext context) throws Exception {
+               // TODO Auto-generated method stub
+
+       }
+
+       @Override
+       public void stop(BundleContext context) throws Exception {
+               // TODO Auto-generated method stub
+
+       }
+
+}
index cc080aa..d7f0030 100755 (executable)
@@ -10,6 +10,7 @@
     <feature name='sdnc-dblib' description="sdnc-dblib" version='${project.version}'>
         <!-- Most applications will have a dependency on the ODL MD-SAL Broker -->
         <feature version="${odl.mdsal.version}">odl-mdsal-broker</feature>
+        <bundle>mvn:org.openecomp.sdnc.core/dblib-common/${project.version}</bundle>
         <bundle>mvn:org.openecomp.sdnc.core/dblib-provider/${project.version}</bundle>
         <bundle>mvn:mysql/mysql-connector-java/${mysql.connector.version}</bundle>
     </feature>
index 0534e07..5adb663 100755 (executable)
         <name>AT&amp;T</name>
     </organization>
   <modules>
+    <module>common</module>
     <module>provider</module>
     <module>features</module>
     <module>installer</module>
index 71de996..913adf3 100755 (executable)
                        <artifactId>mysql-connector-java</artifactId>
                        <version>${mysql.connector.version}</version>
                </dependency>
+               <dependency>
+                       <groupId>org.openecomp.sdnc.core</groupId>
+                       <artifactId>dblib-common</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
        </dependencies>
 
        <build>
                                                <Bundle-SymbolicName>org.openecomp.sdnc.sli.resource.dblib</Bundle-SymbolicName>
                                                <Bundle-Activator>org.openecomp.sdnc.sli.resource.dblib.DBLIBResourceActivator</Bundle-Activator>
                                                <Export-Package>org.openecomp.sdnc.sli.resource.dblib;version=${project.version}</Export-Package>
-                                               <Import-Package>org.openecomp.sdnc.sli.*,org.osgi.framework.*,org.slf4j.*,com.mysql.jdbc.*,javax.sql.*</Import-Package>
+                                               <!--
+                                               <Import-Package>org.openecomp.sdnc.sli.*,org.osgi.framework.*,org.slf4j.*,com.mysql.jdbc.*,javax.sql.*,org.apache.tomcat.*</Import-Package>
+                                               -->
+                                               <Import-Package>*</Import-Package>
                                                <Embed-Transitive>true</Embed-Transitive>
                                        </instructions>
                                </configuration>
index f774748..3e51ed9 100644 (file)
@@ -23,9 +23,8 @@ package org.openecomp.sdnc.sli.resource.dblib;
 
 import org.openecomp.sdnc.sli.resource.dblib.config.BaseDBConfiguration;
 import org.openecomp.sdnc.sli.resource.dblib.config.JDBCConfiguration;
-import org.openecomp.sdnc.sli.resource.dblib.config.JndiConfiguration;
+import org.openecomp.sdnc.sli.resource.dblib.jdbc.JdbcDBCachedDataSource;
 import org.openecomp.sdnc.sli.resource.dblib.jdbc.MySQLCachedDataSource;
-import org.openecomp.sdnc.sli.resource.dblib.jndi.JndiCachedDataSource;
 
 /**
  * @version $Revision: 1.1 $
@@ -38,9 +37,8 @@ public class CachedDataSourceFactory {
 
        public static CachedDataSource createDataSource(BaseDBConfiguration config) {
                if(config instanceof JDBCConfiguration)
-                       return MySQLCachedDataSource.createInstance(config);
-               if(config instanceof JndiConfiguration)
-                       return JndiCachedDataSource.createInstance(config);
+                       return JdbcDBCachedDataSource.createInstance(config);
+
                return (CachedDataSource)null;
        }
 
index 7f85c42..401c013 100644 (file)
@@ -53,7 +53,6 @@ import org.openecomp.sdnc.sli.resource.dblib.pm.SQLExecutionMonitor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.sun.rowset.providers.RIOptimisticProvider;
 
 /**
  * @version $Revision: 1.15 $
@@ -87,7 +86,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
                        }
                        return 0;
                }
-               
+
        });
        protected final Set<CachedDataSource> broken = Collections.synchronizedSet(new HashSet<CachedDataSource>());
        protected final Object monitor = new Object();
@@ -131,17 +130,6 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
                worker.setName("DBResourcemanagerWatchThread");
                worker.setDaemon(true);
                worker.start();
-               
-               try {
-                       RIOptimisticProvider rio  = new RIOptimisticProvider();
-                       LOGGER.info("Class " + rio.getClass().getName() + " found.");
-                       Class clas = this.getClass().getClassLoader().loadClass("com.sun.rowset.providers.RIOptimisticProvider");
-                       if(clas != null) {
-                               LOGGER.info("Class " + rio.getClass().getName() + " found by classloader.");
-                       }
-               } catch(Exception exc) {
-                       LOGGER.info("Failed resolving RIOptimisticProvider class", exc);
-               }
        }
 
        private void config(Properties ctx) throws Exception {
@@ -320,7 +308,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
                        Collections.reverse(sources);
                }
 
-               
+
                // loop through available data sources to retrieve data.
                while(!sources.isEmpty())
                {
@@ -428,7 +416,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
        public boolean writeData(String statement, ArrayList<String> arguments, String preferredDS) throws SQLException {
                return writeDataNoRecovery(statement, arguments, preferredDS);
        }
-       
+
        CachedDataSource findMaster() {
                CachedDataSource master = null;
                CachedDataSource[] dss = this.dsQueue.toArray(new CachedDataSource[0]);
@@ -468,7 +456,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
                                                active = master;
                                        }
                                }
-                               
+
                                return active.writeData(statement, arguments);
                        } catch(Throwable exc){
                                String message = exc.getMessage();
index 90ea6bc..117f932 100644 (file)
@@ -46,10 +46,6 @@ public class DbConfigPool {
                return type;
        }
 
-       public JndiConfiguration[] getJndiDbSourceArray() {
-               return configurations.toArray(new JndiConfiguration[configurations.size()]);
-       }
-
        public JDBCConfiguration[] getJDBCbSourceArray() {
                return configurations.toArray(new JDBCConfiguration[configurations.size()]);
        }
index e6b1a35..f4291a7 100644 (file)
@@ -21,7 +21,6 @@
 package org.openecomp.sdnc.sli.resource.dblib.factory;
 
 import org.openecomp.sdnc.sli.resource.dblib.jdbc.JdbcDbResourceManagerFactory;
-import org.openecomp.sdnc.sli.resource.dblib.jndi.JNDIDbResourceManagerFactory;
 
 /**
  * @version $Revision: 1.1 $
@@ -33,13 +32,7 @@ import org.openecomp.sdnc.sli.resource.dblib.jndi.JNDIDbResourceManagerFactory;
 public class AbstractDBResourceManagerFactory {
 
        public static AbstractResourceManagerFactory getFactory(String type) throws FactoryNotDefinedException {
-               
-               if("JNDI".equals(type)){
-                       try {
-                               return JNDIDbResourceManagerFactory.createIntstance();
-                       } catch (Exception e) {
-                       }
-               }
+
                // JDBC
                return JdbcDbResourceManagerFactory.createIntstance();
        }
index 148ddac..29ec061 100644 (file)
@@ -32,7 +32,6 @@ import org.openecomp.sdnc.sli.resource.dblib.DBResourceManager;
 import org.openecomp.sdnc.sli.resource.dblib.config.BaseDBConfiguration;
 import org.openecomp.sdnc.sli.resource.dblib.config.DbConfigPool;
 import org.openecomp.sdnc.sli.resource.dblib.config.JDBCConfiguration;
-import org.openecomp.sdnc.sli.resource.dblib.config.JndiConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,20 +48,15 @@ public abstract class AbstractResourceManagerFactory {
        public abstract CachedDataSource[] initDBResourceManager(DbConfigPool dbConfig, DBResourceManager manager) throws Exception;
        public abstract CachedDataSource[] initDBResourceManager(DbConfigPool dbConfig, DBResourceManager dbResourceManager, String sourceName) throws SQLException ;
 
-       
+
        public static AbstractResourceManagerFactory createIntstance() throws FactoryNotDefinedException {
                throw new FactoryNotDefinedException("Factory method 'createIntstance' needs to be overriden in DBResourceManagerFactory");
        }
 
-       public class DBInitTask implements Callable<CachedDataSource> 
+       public class DBInitTask implements Callable<CachedDataSource>
        {
                private BaseDBConfiguration config = null;
                private Set<DBInitTask> activeTasks;
-               
-               public DBInitTask(JndiConfiguration jndiConfig, Set<DBInitTask> tasks){
-                       this.config = jndiConfig;
-                       this.activeTasks = tasks;
-               }
 
                public DBInitTask(JDBCConfiguration jdbcconfig, Set<DBInitTask> tasks) {
                        this.config = jdbcconfig;
@@ -97,6 +91,7 @@ public abstract class AbstractResourceManagerFactory {
                                                worker.start();
                                        } else {
                                                if(LOGGER.isDebugEnabled())
+                                                       if(ds != null)
                                                        LOGGER.debug("Completed CachedDataSource.Call from "+ds.getDbConnectionName());
                                        }
                                }
index 7044082..3530459 100644 (file)
@@ -25,10 +25,11 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Properties;
 
+import org.slf4j.LoggerFactory;
+
 import org.openecomp.sdnc.sli.resource.dblib.config.BaseDBConfiguration;
 import org.openecomp.sdnc.sli.resource.dblib.config.DbConfigPool;
 import org.openecomp.sdnc.sli.resource.dblib.config.JDBCConfiguration;
-import org.openecomp.sdnc.sli.resource.dblib.config.JndiConfiguration;
 
 /**
  * @version $Revision: 1.1 $
@@ -44,7 +45,7 @@ public class DBConfigFactory {
        }
 
        static DbConfigPool getConfigparams(Properties properties){
-               org.slf4j.LoggerFactory.getLogger(DBConfigFactory.class).info(properties.toString());
+               LoggerFactory.getLogger(DBConfigFactory.class).info(properties.toString());
                DbConfigPool xmlConfig = new DbConfigPool(properties);
                ArrayList<Properties> propertySets = new ArrayList<Properties>();
 
@@ -78,7 +79,7 @@ public class DBConfigFactory {
                        }
 
                } catch (Exception e) {
-                       org.slf4j.LoggerFactory.getLogger(DBConfigFactory.class).warn("",e);
+                       LoggerFactory.getLogger(DBConfigFactory.class).warn("",e);
                }
 
                return xmlConfig;
@@ -89,15 +90,12 @@ public class DBConfigFactory {
                String type = props.getProperty(BaseDBConfiguration.DATABASE_TYPE);
 
                BaseDBConfiguration config = null;
-               
-               if("JNDI".equalsIgnoreCase(type)) {
-                       config = new JndiConfiguration(props);
-               }
+
                if("JDBC".equalsIgnoreCase(type)) {
                        config = new JDBCConfiguration(props);
                }
 
                return config;
-               
+
        }
 }
diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/JdbcDBCachedDataSource.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/JdbcDBCachedDataSource.java
new file mode 100644 (file)
index 0000000..ee3d4ff
--- /dev/null
@@ -0,0 +1,252 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.resource.dblib.jdbc;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLFeatureNotSupportedException;
+
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.openecomp.sdnc.sli.resource.dblib.CachedDataSource;
+import org.openecomp.sdnc.sli.resource.dblib.DBConfigException;
+import org.openecomp.sdnc.sli.resource.dblib.config.BaseDBConfiguration;
+import org.openecomp.sdnc.sli.resource.dblib.config.JDBCConfiguration;
+import com.mysql.jdbc.Driver;
+
+
+/**
+ * @version $Revision: 1.7 $
+ * Change Log
+ * Author         Date     Comments
+ * ============== ======== ====================================================
+ * Rich Tabedzki
+ */
+
+public class JdbcDBCachedDataSource extends CachedDataSource
+{
+       private String dbUserId;
+       private String dbPasswd;
+       private String dbUrl;
+
+       private int minLimit;
+       private int maxLimit;
+       private int initialLimit;
+
+       private static final String AS_CONF_ERROR = "AS_CONF_ERROR: ";
+
+       private static Logger LOGGER = LoggerFactory.getLogger(JdbcDBCachedDataSource.class);
+
+       /**
+        * @param jdbcElem
+        * @param alarmLog
+        * @param occManager
+        * @throws Exception
+        */
+       public JdbcDBCachedDataSource(BaseDBConfiguration jdbcElem)
+       {
+                       super(jdbcElem);
+       }
+
+       @Override
+       protected void configure(BaseDBConfiguration xmlElem) throws DBConfigException
+       {
+               BaseDBConfiguration jdbcConfig = (BaseDBConfiguration)xmlElem;
+               if(jdbcConfig.getConnTimeout() > 0){
+                       this.CONN_REQ_TIMEOUT = jdbcConfig.getConnTimeout();
+               }
+               if(jdbcConfig.getRequestTimeout() > 0){
+                               this.DATA_REQ_TIMEOUT = jdbcConfig.getRequestTimeout();
+               }
+
+       // set connection pool name
+               String dbConnectionName = jdbcConfig.getDbConnectionName();
+       super.setDbConnectionName(dbConnectionName);
+       // Configure the JDBC connection
+       dbUserId = jdbcConfig.getDbUserId();
+        if (dbUserId == null)
+        {
+               String errorMsg =  "Invalid XML contents: JDBCConnection missing dbUserId attribute";
+               LOGGER.error(AS_CONF_ERROR + errorMsg);
+            throw new DBConfigException(errorMsg);
+        }
+
+        dbPasswd = jdbcConfig.getDbPasswd();
+        if (dbPasswd == null)
+        {
+               String errorMsg =  "Invalid XML contents: JDBCConnection missing dbPasswd attribute";
+               LOGGER.error(AS_CONF_ERROR + errorMsg);
+            throw new DBConfigException(errorMsg);
+        }
+        /*
+        dbDriver = jdbcConfig.getDbDriver();
+        if (dbDriver == null)
+        {
+               String errorMsg =  "Invalid XML contents: JDBCConnection missing dbDriver attribute";
+               LOGGER.error(AS_CONF_ERROR + errorMsg);
+               throw new ScpTblUpdateError(errorMsg);
+        }
+        */
+
+        minLimit = jdbcConfig.getDbMinLimit();
+//        if (minLimit == null)
+//        {
+//             String errorMsg =  "Invalid XML contents: JDBC Connection missing minLimit attribute";
+//             LOGGER.error(AS_CONF_ERROR + errorMsg);
+//             throw new DBConfigException(errorMsg);
+//        }
+        maxLimit =  jdbcConfig.getDbMaxLimit();
+//        if (maxLimit == null)
+//        {
+//             String errorMsg =  "Invalid XML contents: JDBC Connection missing maxLimit attribute";
+//             LOGGER.error(AS_CONF_ERROR + errorMsg);
+//             throw new DBConfigException(errorMsg);
+//        }
+        initialLimit =  jdbcConfig.getDbInitialLimit();
+//        if (initialLimit == null)
+//        {
+//             String errorMsg =  "Invalid XML contents: JDBC Connection missing initialLimit attribute";
+//             LOGGER.error(AS_CONF_ERROR + errorMsg);
+//             throw new DBConfigException(errorMsg);
+//        }
+
+        dbUrl = jdbcConfig.getDbUrl();
+        if(dbUrl == null){
+               String errorMsg =  "Invalid XML contents: JDBCConnection missing dbUrl attribute";
+               LOGGER.error(AS_CONF_ERROR + errorMsg);
+            throw new DBConfigException(errorMsg);
+        }
+
+               try {
+                       Driver dr = new com.mysql.jdbc.Driver();
+                       Class clazz = Class.forName("com.mysql.jdbc.Driver") ;
+
+                       PoolProperties p = new PoolProperties();
+                       p.setDriverClassName("com.mysql.jdbc.Driver");
+                       p.setUrl(dbUrl);
+                       p.setUsername(dbUserId);
+                       p.setPassword(dbPasswd);
+                       p.setJmxEnabled(true);
+                       p.setTestWhileIdle(false);
+                       p.setTestOnBorrow(true);
+                       p.setValidationQuery("SELECT 1");
+                       p.setTestOnReturn(false);
+                       p.setValidationInterval(30000);
+                       p.setTimeBetweenEvictionRunsMillis(30000);
+                       p.setInitialSize(initialLimit);
+                       p.setMaxActive(maxLimit);
+                       p.setMaxIdle(maxLimit);
+                       p.setMaxWait(10000);
+                       p.setRemoveAbandonedTimeout(60);
+                       p.setMinEvictableIdleTimeMillis(30000);
+                       p.setMinIdle(minLimit);
+                       p.setLogAbandoned(true);
+                       p.setRemoveAbandoned(true);
+                       p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
+                                       + "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
+
+                       DataSource dataSource = new DataSource(p);
+
+                       synchronized(this)
+                       {
+                               this.ds = dataSource;
+                               Connection con = null;
+                               PreparedStatement st = null;
+                               ResultSet rs = null;
+
+                               try {
+                                       con = dataSource.getConnection();
+                                       st = con.prepareStatement("Select 1 FROM DUAL");
+                                       rs = st.executeQuery();
+                               } catch(Exception exc) {
+                                       LOGGER.error(exc.getMessage());
+                               } finally {
+                                       if(rs != null) rs.close();
+                                       if(st != null) st.close();
+                                       if(con != null) con.close();
+                               }
+
+                               initialized = true;
+                               LOGGER.info("MySQLDataSource <"+dbConnectionName+"> configured successfully. Using URL: "+dbUrl);
+                       }
+
+//             } catch (SQLException exc) {
+//                     initialized = false;
+//                     StringBuffer sb = new StringBuffer();
+//                     sb.append("Failed to initialize MySQLDataSource<");
+//                     sb.append(dbConnectionName).append(">. Reason: ");
+//                     sb.append(exc.getMessage());
+//                     LOGGER.error("AS_CONF_ERROR: " + sb.toString());
+////                   throw new DBConfigException(e.getMessage());
+               } catch (Exception exc) {
+               initialized = false;
+                       StringBuffer sb = new StringBuffer();
+                       sb.append("Failed to initialize MySQLCachedDataSource <");
+                       sb.append(dbConnectionName).append(">. Reason: ");
+                       sb.append(exc.getMessage());
+                       LOGGER.error("AS_CONF_ERROR: " + sb.toString());
+//             throw new DBConfigException(e.getMessage());
+       }
+    }
+
+       public final String getDbUrl()
+       {
+               return dbUrl;
+       }
+
+       public final String getDbUserId()
+       {
+               return dbUserId;
+       }
+
+       public final String getDbPasswd()
+       {
+               return dbPasswd;
+       }
+
+       public static JdbcDBCachedDataSource createInstance(BaseDBConfiguration config) /*throws Exception*/ {
+               return new JdbcDBCachedDataSource(config);
+       }
+
+       public String toString(){
+               return getDbConnectionName();
+       }
+
+       public java.util.logging.Logger getParentLogger()
+                       throws SQLFeatureNotSupportedException {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public void cleanUp(){
+               DataSource dataSource = (DataSource)ds;
+               dataSource.getPool().purge();
+               int active = dataSource.getActive();
+               int size = dataSource.getSize();
+               dataSource.close(true);
+               super.cleanUp();
+       }
+
+}
diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jndi/JNDIDbResourceManagerFactory.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jndi/JNDIDbResourceManagerFactory.java
deleted file mode 100644 (file)
index 2888bc5..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * openecomp
- * ================================================================================
- * Copyright (C) 2016 - 2017 AT&T
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.openecomp.sdnc.sli.resource.dblib.jndi;
-
-import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
-
-import org.openecomp.sdnc.sli.resource.dblib.CachedDataSource;
-import org.openecomp.sdnc.sli.resource.dblib.CachedDataSourceFactory;
-import org.openecomp.sdnc.sli.resource.dblib.DBResourceManager;
-import org.openecomp.sdnc.sli.resource.dblib.config.DbConfigPool;
-import org.openecomp.sdnc.sli.resource.dblib.config.JndiConfiguration;
-import org.openecomp.sdnc.sli.resource.dblib.factory.AbstractResourceManagerFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @version $Revision: 1.6 $
- * Change Log
- * Author         Date     Comments
- * ============== ======== ====================================================
- * Rich Tabedzki
- */
-public class JNDIDbResourceManagerFactory extends AbstractResourceManagerFactory {
-
-       private static Logger LOGGER = LoggerFactory.getLogger(JNDIDbResourceManagerFactory.class);
-
-       class MyFutureTask extends FutureTask<DBInitTask>
-       {
-
-               public MyFutureTask(Callable<CachedDataSource> result) {
-                       super((Callable)result);
-               }
-               
-       }
-
-       public CachedDataSource[] initDBResourceManager(DbConfigPool dbConfig, DBResourceManager manager, String sourceName) throws SQLException 
-       {       
-               // here create the data sources objects
-               JndiConfiguration[] list = dbConfig.getJndiDbSourceArray();
-               CachedDataSource[] cachedDS = new CachedDataSource[1];
-
-               for(int i=0, max=list.length; i<max; i++){
-                       if(!sourceName.equals(list[i].getJndiConnectionName()))
-                               continue;
-
-                       JndiConfiguration config = list[i];
-                       CachedDataSource dataSource = CachedDataSourceFactory.createDataSource(config);
-                       cachedDS[0] = dataSource;
-               }
-               return cachedDS;
-       }
-       
-       public CachedDataSource[] initDBResourceManager(DbConfigPool dbConfig, DBResourceManager manager) /* throws Exception */ {
-//             WSConfigManagement ws = WSConfigManagement.getInstance();
-               
-               ExecutorService threadExecutor = Executors.newFixedThreadPool(2);
-               // here create the data sources objects
-               JndiConfiguration[] list = dbConfig.getJndiDbSourceArray();
-               FutureTask<DBInitTask>[] futures = new MyFutureTask[list.length];
-               final Set<DBInitTask> tasks = new HashSet<DBInitTask>();
-               if(LOGGER.isDebugEnabled())
-                       LOGGER.debug("Creating datasources.");
-               for(int i=0, max=list.length; i<max; i++){
-                       JndiConfiguration config = list[i];
-//                     if(manager.getJndiContextFactoryStr()!=null && manager.getJndiContextFactoryStr().trim().length()>0){
-//                             config.setJndiContextFactory(manager.getJndiContextFactoryStr());
-//                     }
-//                     if(manager.getJndiURLStr()!=null && manager.getJndiURLStr().trim().length()>0){
-//                             config.setJndiURL(manager.getJndiURLStr());
-//                     }
-                       DBInitTask task = new DBInitTask(config, tasks);
-                       tasks.add(task);
-                       futures[i] = new MyFutureTask(task);
-               }
-
-               try {
-                       synchronized(tasks){
-                               for(int i=0, max=list.length; i<max; i++){
-                                       threadExecutor.execute(futures[i]);
-                               }
-                               // the timeout param is set is seconds. 
-                               long timeout = ((dbConfig.getTimeout() <= 0) ? 60L : dbConfig.getTimeout());
-                               timeout *= 1000;
-                               // the timeout param is set is seconds, hence it needs to be multiplied by 1000. 
-                               tasks.wait(timeout);
-                               if(LOGGER.isDebugEnabled())
-                                       LOGGER.debug("initDBResourceManager wait completed.");
-                       }
-               } catch(Exception exc) {
-                       LOGGER.error("Failed to initialize JndiCachedDataSource. Reason: ", exc);
-               }
-               
-               if(threadExecutor != null){
-                       try {
-                               threadExecutor.shutdown();
-                       } catch(Exception exc){}
-               }
-
-               CachedDataSource[] cachedDS = new CachedDataSource[futures.length];
-               
-               boolean initialized = false;
-               for(int i=0; i<futures.length; i++){
-                       Object obj = null;
-                       if(futures[i].isDone()){
-                               try {
-                                       obj = futures[i].get();
-                                       if(obj instanceof CachedDataSource){
-                                               cachedDS[i] = (CachedDataSource)obj;
-                                               initialized = true;
-                                               LOGGER.info("DataSource "+list[i].getJndiConnectionName()+" initialized successfully");
-                                       }
-                               } catch (InterruptedException exc) {
-                                       LOGGER.error("DataSource "+list[i].getJndiConnectionName()+" initialization failed", exc);
-                               } catch (ExecutionException exc) {
-                                       LOGGER.error("DataSource "+list[i].getJndiConnectionName()+" initialization failed", exc);
-                               } catch (Exception exc) {
-                                       LOGGER.error("DataSource "+list[i].getJndiConnectionName()+" initialization failed", exc);
-                               }
-                       } else {
-                               try {
-                                       obj = futures[i].get();
-                                       if(obj instanceof CachedDataSource){
-
-                                               LOGGER.error("DataSource "+((CachedDataSource)obj).getDbConnectionName()+" failed");
-                                       }
-                               } catch (Exception exc) {
-                                       LOGGER.error("DataSource "+list[i].getJndiConnectionName()+" initialization failed", exc);
-                               }
-                       }
-               }
-
-               if(!initialized){
-                       new Error("Failed to initialize DB Library.");
-               }
-               return cachedDS;
-       }
-       
-       public static AbstractResourceManagerFactory createIntstance() {
-               return new JNDIDbResourceManagerFactory();
-       }
-
-}
diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jndi/JndiCachedDataSource.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jndi/JndiCachedDataSource.java
deleted file mode 100644 (file)
index 19fa8e9..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * openecomp
- * ================================================================================
- * Copyright (C) 2016 - 2017 AT&T
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.openecomp.sdnc.sli.resource.dblib.jndi;
-
-import java.sql.SQLFeatureNotSupportedException;
-import java.util.Properties;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-
-import org.openecomp.sdnc.sli.resource.dblib.CachedDataSource;
-import org.openecomp.sdnc.sli.resource.dblib.DBConfigException;
-import org.openecomp.sdnc.sli.resource.dblib.config.BaseDBConfiguration;
-import org.openecomp.sdnc.sli.resource.dblib.config.JndiConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xml.sax.SAXException;
-
-/**
- * @version $Revision: 1.2 $
- * Change Log
- * Author         Date     Comments
- * ============== ======== ====================================================
- * Rich Tabedzki
- */
-public class JndiCachedDataSource extends CachedDataSource
-{
-       private static Logger LOGGER = LoggerFactory.getLogger(JndiCachedDataSource.class);
-       /**
-        * @param alarmLog 
-        * @param jdbcElem
-        * @throws SAXException 
-        * @throws ScpTblUpdateError 
-        */
-       public JndiCachedDataSource(BaseDBConfiguration xmlElem) throws DBConfigException
-       {
-               super(xmlElem);
-       }
-
-       protected void configure(BaseDBConfiguration xmlElem) throws DBConfigException {
-               JndiConfiguration jdbcConfig = (JndiConfiguration)xmlElem;
-       String jndiContextFactoryStr = jdbcConfig.getJndiContextFactory(); 
-       String jndiURLStr = jdbcConfig.getJndiURL();
-       String jndiSourceStr = jdbcConfig.getJndiSource();
-       
-       if(jdbcConfig.getConnTimeout() > 0){
-               this.CONN_REQ_TIMEOUT = jdbcConfig.getConnTimeout();
-       }
-               if(jdbcConfig.getRequestTimeout() > 0){
-                       this.DATA_REQ_TIMEOUT = jdbcConfig.getRequestTimeout();
-               }
-       
-       super.setDbConnectionName(jdbcConfig.getJndiConnectionName());
-       
-       if(jndiContextFactoryStr == null || jndiContextFactoryStr.length() == 0)
-       {
-//             throw new DBConfigException("The jndi configuration is incomplete: jndiContextFactory");
-       }
-       if(jndiURLStr == null || jndiContextFactoryStr.length() == 0)
-       {
-//             throw new ScpTblUpdateError("The jndi configuration is incomplete: jndiURL");
-       }
-       if(jndiSourceStr == null || jndiSourceStr.length() == 0)
-       {
-               throw new DBConfigException("The jndi configuration is incomplete: jndiSource");
-       }
-
-       Properties env = new Properties();
-       Context ctx; 
-               try
-               {
-                       if(jndiContextFactoryStr != null && jndiContextFactoryStr.length() != 0){
-                               env.put(Context.INITIAL_CONTEXT_FACTORY, jndiContextFactoryStr);
-                               ctx = new InitialContext(env);
-                       } else {
-                               ctx = new InitialContext();
-                       }
-                       ds = (javax.sql.DataSource) ctx.lookup (jndiSourceStr);
-                       if(ds == null)
-                       {
-                               this.initialized = false;
-                               LOGGER.error("AS_CONF_ERROR: Failed to initialize DataSource <"+getDbConnectionName()+"> using JNDI <"+jndiSourceStr+">");
-                               return;
-                       } else {
-                               this.initialized = true;
-                               LOGGER.info("JndiCachedDataSource <"+getDbConnectionName()+"> configured successfully.");
-                               return;
-                       }
-               } catch (NamingException exc) {
-                       this.initialized = false;
-                       LOGGER.error("AS_CONF_ERROR" + exc.getMessage());
-
-               } catch(Throwable exc) {
-                       this.initialized = false;
-                       LOGGER.error("AS_CONF_ERROR: " + exc.getMessage());
-               }
-    }
-
-       public static JndiCachedDataSource createInstance(BaseDBConfiguration config) {
-               return new JndiCachedDataSource(config);
-       }
-       
-       public String toString(){
-               return getDbConnectionName();
-       }
-
-       public java.util.logging.Logger getParentLogger()
-                       throws SQLFeatureNotSupportedException {
-               // TODO Auto-generated method stub
-               return null;
-       }
-}
index 3872288..0f28f1f 100755 (executable)
@@ -3,7 +3,7 @@ org.openecomp.sdnc.sli.jdbc.hosts=sdnctldb01,sdnctldb02
 org.openecomp.sdnc.sli.jdbc.url=jdbc:mysql://DBHOST:3306/sdnctl
 org.openecomp.sdnc.sli.jdbc.database=sdnctl
 org.openecomp.sdnc.sli.jdbc.user=sdnctl
-org.openecomp.sdnc.sli.jdbc.password=gamma
+org.openecomp.sdnc.sli.jdbc.password={password for sdnctl}
 org.openecomp.sdnc.sli.jdbc.connection.name=sdnctldb01
 
 org.openecomp.sdnc.sli.jdbc.connection.timeout=50
index cf31a0c..6afa2d2 100755 (executable)
                         <artifactId>commons-codec</artifactId>
                         <version>${commons.codec.version}</version>
                 </dependency>
-
+                <dependency>
+                       <groupId>org.openecomp.sdnc.core</groupId>
+                       <artifactId>sli-common</artifactId>
+                       <version>${sdnctl.sli.version}</version>
+                </dependency>
 <!--
                <dependency>
                        <groupId>mysql</groupId>
index 40100c3..809cfb2 100644 (file)
@@ -47,7 +47,7 @@ import java.util.TimeZone;
 
 
 /**
- * Logs IN request according ECOMP Logging Guidelines
+ * Logs IN request according ECOMP Logging Guidelines at https://tspace.web.att.com/viewer/app/lcfiles/ae5f7751-39da-4c6b-8a83-5836c8c815e1/content
  */
 public class LogFilter implements Filter {
 
diff --git a/filters/provider/src/main/java/org/openecomp/sdnc/filters/RequestResponseDbLoggingFilter.java b/filters/provider/src/main/java/org/openecomp/sdnc/filters/RequestResponseDbLoggingFilter.java
new file mode 100644 (file)
index 0000000..183301b
--- /dev/null
@@ -0,0 +1,297 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.filters;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.zip.GZIPInputStream;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.openecomp.sdnc.sli.MessageWriter;
+
+public class RequestResponseDbLoggingFilter implements Filter {
+
+       private static Logger log = LoggerFactory.getLogger(RequestResponseDbLoggingFilter.class);
+
+       public static final String REQUEST_ID = "X-ECOMP-RequestID";
+
+       private static class ByteArrayServletStream extends ServletOutputStream {
+
+               ByteArrayOutputStream baos;
+
+               ByteArrayServletStream(ByteArrayOutputStream baos) {
+                       this.baos = baos;
+               }
+
+               @Override
+               public void write(int param) throws IOException {
+                       baos.write(param);
+               }
+       }
+
+       private static class ByteArrayPrintWriter {
+
+               private ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+               private PrintWriter pw = new PrintWriter(baos);
+
+               private ServletOutputStream sos = new ByteArrayServletStream(baos);
+
+               public PrintWriter getWriter() {
+                       return pw;
+               }
+
+               public ServletOutputStream getStream() {
+                       return sos;
+               }
+
+               byte[] toByteArray() {
+                       return baos.toByteArray();
+               }
+       }
+
+       private class BufferedServletInputStream extends ServletInputStream {
+
+               ByteArrayInputStream bais;
+
+               public BufferedServletInputStream(ByteArrayInputStream bais) {
+                       this.bais = bais;
+               }
+
+               @Override
+               public int available() {
+                       return bais.available();
+               }
+
+               @Override
+               public int read() {
+                       return bais.read();
+               }
+
+               @Override
+               public int read(byte[] buf, int off, int len) {
+                       return bais.read(buf, off, len);
+               }
+
+       }
+
+       private class BufferedRequestWrapper extends HttpServletRequestWrapper {
+
+               ByteArrayInputStream bais;
+
+               ByteArrayOutputStream baos;
+
+               BufferedServletInputStream bsis;
+
+               byte[] buffer;
+
+               public BufferedRequestWrapper(HttpServletRequest req) throws IOException {
+                       super(req);
+
+                       InputStream is = req.getInputStream();
+                       baos = new ByteArrayOutputStream();
+                       byte buf[] = new byte[1024];
+                       int letti;
+                       while ((letti = is.read(buf)) > 0) {
+                               baos.write(buf, 0, letti);
+                       }
+                       buffer = baos.toByteArray();
+
+               }
+
+               @Override
+               public ServletInputStream getInputStream() {
+                       try {
+                               bais = new ByteArrayInputStream(buffer);
+                               bsis = new BufferedServletInputStream(bais);
+                       } catch (Exception ex) {
+                               ex.printStackTrace();
+                       }
+
+                       return bsis;
+               }
+
+               public byte[] getBuffer() {
+                       return buffer;
+               }
+
+       }
+
+       @Override
+       public void init(FilterConfig filterConfig) throws ServletException {
+       }
+
+       @Override
+       public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain)
+               throws IOException, ServletException {
+
+               if (request == null || !(request instanceof HttpServletRequest)) {
+                       filterChain.doFilter(request, response);
+                       return;
+               }
+
+               long t1 = System.currentTimeMillis();
+
+               final HttpServletRequest httpRequest = (HttpServletRequest) request;
+               BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(httpRequest);
+
+               String requestId = httpRequest.getHeader(REQUEST_ID);
+               if (requestId == null || requestId.trim().length() == 0) {
+                       log.warn("Could not write request in DB: " + REQUEST_ID + " is missing in the HTTP headers.");
+                       return;
+               }
+
+               String requestHost = request.getRemoteHost();
+               if (requestHost == null)
+                       requestHost = request.getRemoteAddr();
+
+               String requestStr = new String(bufferedRequest.getBuffer());
+
+               MessageWriter.saveIncomingRequest(requestId, null, requestHost, requestStr);
+
+               long t2 = System.currentTimeMillis();
+
+               log.info("Request saved in DB for request-id: " + requestId + ". TIme: " + (t2 - t1));
+
+               final HttpServletResponse httpResponse = (HttpServletResponse) response;
+
+               final ByteArrayPrintWriter pw = new ByteArrayPrintWriter();
+               HttpServletResponse wrappedResp = new HttpServletResponseWrapper(httpResponse) {
+
+                       @Override
+                       public PrintWriter getWriter() {
+                               return pw.getWriter();
+                       }
+
+                       @Override
+                       public ServletOutputStream getOutputStream() {
+                               return pw.getStream();
+                       }
+               };
+
+               try {
+
+                       filterChain.doFilter(bufferedRequest, wrappedResp);
+
+               } finally {
+
+                       if (request != null && request instanceof HttpServletRequest) {
+
+                               t1 = System.currentTimeMillis();
+
+                               byte[] bytes = pw.toByteArray();
+                               response.getOutputStream().write(bytes);
+                               response.getOutputStream().flush();
+
+                               String responseStr = null;
+                               if ("gzip".equals(httpResponse.getHeader("Content-Encoding"))) {
+                                       responseStr = decompressGZIPByteArray(bytes);
+                               } else {
+                                       responseStr = new String(bytes);
+                               }
+
+                               MessageWriter.saveIncomingResponse(requestId, httpResponse.getStatus(), responseStr);
+
+                               t2 = System.currentTimeMillis();
+
+                               log.info("Response saved in DB for request-id: " + requestId + ". TIme: " + (t2 - t1));
+                       }
+               }
+
+       }
+
+       @Override
+       public void destroy() {
+       }
+
+       private String decompressGZIPByteArray(byte[] bytes) {
+
+               BufferedReader in = null;
+               InputStreamReader inR = null;
+               ByteArrayInputStream byteS = null;
+               GZIPInputStream gzS = null;
+               StringBuilder str = new StringBuilder();
+               try {
+                       byteS = new ByteArrayInputStream(bytes);
+                       gzS = new GZIPInputStream(byteS);
+                       inR = new InputStreamReader(gzS);
+                       in = new BufferedReader(inR);
+
+                       if (in != null) {
+
+                               String content;
+
+                               while ((content = in.readLine()) != null) {
+                                       str.append(content);
+                               }
+                       }
+
+               } catch (Exception e) {
+                       log.error("Failed get read GZIPInputStream", e);
+               } finally {
+
+                       if (byteS != null)
+                               try {
+                                       byteS.close();
+                               } catch (IOException e1) {
+                                       log.error("Failed to close ByteStream", e1);
+                               }
+                       if (gzS != null)
+                               try {
+                                       gzS.close();
+                               } catch (IOException e2) {
+                                       log.error("Failed to close GZStream", e2);
+                               }
+                       if (inR != null)
+                               try {
+                                       inR.close();
+                               } catch (IOException e3) {
+                                       log.error("Failed to close InputReader", e3);
+                               }
+                       if (in != null)
+                               try {
+                                       in.close();
+                               } catch (IOException e) {
+                                       log.error("Failed to close BufferedReader", e);
+                               }
+               }
+               return str.toString();
+       }
+}
index 48f0689..b15932f 100644 (file)
@@ -30,7 +30,6 @@ import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.Enumeration;
 import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -57,6 +56,7 @@ public class RequestResponseLoggingFilter implements Filter {
                        this.baos = baos;
                }
 
+               @Override
                public void write(int param) throws IOException {
                        baos.write(param);
                }
@@ -91,14 +91,17 @@ public class RequestResponseLoggingFilter implements Filter {
                        this.bais = bais;
                }
 
+               @Override
                public int available() {
                        return bais.available();
                }
 
+               @Override
                public int read() {
                        return bais.read();
                }
 
+               @Override
                public int read(byte[] buf, int off, int len) {
                        return bais.read(buf, off, len);
                }
@@ -129,6 +132,7 @@ public class RequestResponseLoggingFilter implements Filter {
 
                }
 
+               @Override
                public ServletInputStream getInputStream() {
                        try {
                                bais = new ByteArrayInputStream(buffer);
@@ -146,9 +150,11 @@ public class RequestResponseLoggingFilter implements Filter {
 
        }
 
+       @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
 
+       @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                        throws IOException, ServletException {
 
@@ -177,10 +183,12 @@ public class RequestResponseLoggingFilter implements Filter {
 
                final ByteArrayPrintWriter pw = new ByteArrayPrintWriter();
                HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {
+                       @Override
                        public PrintWriter getWriter() {
                                return pw.getWriter();
                        }
 
+                       @Override
                        public ServletOutputStream getOutputStream() {
                                return pw.getStream();
                        }
@@ -188,15 +196,16 @@ public class RequestResponseLoggingFilter implements Filter {
                };
 
                try {
-                       
+
                filterChain.doFilter(bufferedRequest, wrappedResp);
-               
+
                }catch (Exception e){
                        log.error("Chain Exception",e);
                        throw e;
                } finally {
                byte[] bytes = pw.toByteArray();
                response.getOutputStream().write(bytes);
+               response.getOutputStream().flush();
 
                StringBuilder responseHeaders = new StringBuilder("RESPONSE HEADERS|");
 
@@ -220,6 +229,7 @@ public class RequestResponseLoggingFilter implements Filter {
                }
        }
 
+       @Override
        public void destroy() {
        }
 
diff --git a/pom.xml b/pom.xml
index 4469f9a..a305621 100755 (executable)
--- a/pom.xml
+++ b/pom.xml
@@ -7,8 +7,9 @@
        <groupId>org.openecomp.sdnc.core</groupId>
        <artifactId>sdnc-core</artifactId>
 
+
        <name>SDN-C Core Components</name>
-       <url>https://wiki.onap.org</url>
+       <url>https://wiki.openecomp.org</url>
        <description>The SDN-C core components contains the SLI, dblib and root pom</description>
 
        <parent>
@@ -21,7 +22,7 @@
 
        <issueManagement>
                <system>JIRA</system>
-               <url>http://jira.onap.org/</url>
+               <url>http://jira.openecomp.org/</url>
        </issueManagement>
 
 
@@ -34,7 +35,7 @@
 
        <ciManagement>
                <system>Jenkins</system>
-               <url>https://jenkins.onap.org/</url>
+               <url>https://jenkins.openecomp.org/</url>
        </ciManagement>
 
 
@@ -55,7 +56,6 @@
                                </property>
                        </activation>
                        <build>
-                               <pluginManagement>
                                        <plugins>
                                                <plugin>
                                                        <groupId>com.blackducksoftware.integration</groupId>
@@ -78,7 +78,7 @@
                                                </plugin>
                                        </plugins>
 
-                               </pluginManagement>
+
 
                        </build>
 
 
        </build>
        <modules>
-               <module>rootpom</module>
                <module>dblib</module>
                <module>filters</module>
                <module>sli</module>
index 7a59501..4938811 100755 (executable)
@@ -5,7 +5,7 @@
        <parent>
                <groupId>org.opendaylight.odlparent</groupId>
                <artifactId>odlparent</artifactId>
-               <version>1.6.2-Beryllium-SR2</version>
+               <version>1.7.1-Boron-SR1</version>
                <relativePath>../../../../../opendaylight/odlparent</relativePath>
        </parent>
 
                <opendaylight.nexus.public-url>https://nexus.opendaylight.org/content/repositories/public/</opendaylight.nexus.public-url>
                <opendaylight.nexus.snapshot-url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</opendaylight.nexus.snapshot-url>
 
-               <release-tag>R17.01</release-tag>
+               <release-tag>R17.07</release-tag>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+               <java.version.source>1.8</java.version.source>
+               <java.version.target>1.8</java.version.target>
                <bundle.plugin.version>2.5.0</bundle.plugin.version>
-               <java.version.source>1.7</java.version.source>
-               <java.version.target>1.7</java.version.target>
                <maven.compile.plugin.version>2.5.1</maven.compile.plugin.version>
-               <equinox.osgi.version>3.8.1.v20120830-144521</equinox.osgi.version>
-               <jackson-annotations-version>${jackson.version}</jackson-annotations-version>
-               <jettison.version>1.3.7</jettison.version>
-               <jvnet.jaxb2.version>0.6.4</jvnet.jaxb2.version>
-               <apache.httpcomponents.version>4.4</apache.httpcomponents.version>
-               <antlr.version>4.5.1</antlr.version>
-               <mysql.connector.version>5.1.39</mysql.connector.version>
-               <odl.version>1.6.2-Beryllium-SR2</odl.version>
-               <odl.dlux.version>0.3.2-Beryllium-SR2</odl.dlux.version>
-               <odl.yangtools.version>0.8.2-Beryllium-SR2</odl.yangtools.version>
-               <odl.mdsal.version>1.3.2-Beryllium-SR2</odl.mdsal.version>
-               <odl.mdsal.features.version>2.0.2-Beryllium-SR2</odl.mdsal.features.version>
-               <odl.mdsal.model.version>0.8.2-Beryllium-SR2</odl.mdsal.model.version>
-               <odl.restconf.version>1.3.2-Beryllium-SR2</odl.restconf.version>
-               <odl.yangtools.version>0.8.2-Beryllium-SR2</odl.yangtools.version>
-               <odl.controller.model.version>${odl.mdsal.model.version}</odl.controller.model.version>
-               <odl.controller.config.api.version>0.4.2-Beryllium-SR2</odl.controller.config.api.version>
-               <odl.karaf.empty.distro.version>${odl.version}</odl.karaf.empty.distro.version>
-               <odl.commons.opendaylight.version>${odl.version}</odl.commons.opendaylight.version>
-               <odl.ietf-inet-types.version>2010.09.24.8.2-Beryllium-SR2</odl.ietf-inet-types.version>
-               <odl.ietf-yang-types.version>2010.09.24.8.2-Beryllium-SR2</odl.ietf-yang-types.version>
-               <odl.yang.jmx.generator.version>0.4.2-Beryllium-SR2</odl.yang.jmx.generator.version>
-               <odl.yangtools.yang.maven.plugin.version>${odl.yangtools.version}</odl.yangtools.yang.maven.plugin.version>
                <features.file>features.xml</features.file>
-               <h2database.version>1.4.186</h2database.version>
                <jmxGeneratorPath>src/main/yang-gen-config</jmxGeneratorPath>
                <salGeneratorPath>src/main/yang-gen-sal</salGeneratorPath>
                <checkstyle.skip>true</checkstyle.skip>
                <sonar.jacoco.reportMissing.force.zero>true</sonar.jacoco.reportMissing.force.zero>
                <sonar.projectVersion>${project.version}</sonar.projectVersion>
 
+               <!-- OpenDaylight component versions -->
+               <odl.version>1.7.1-Boron-SR1</odl.version>
+               <odl.dlux.version>0.4.1-Boron-SR1</odl.dlux.version>
+               <odl.yangtools.version>1.0.1-Boron-SR1</odl.yangtools.version>
+               <odl.mdsal.version>1.4.1-Boron-SR1</odl.mdsal.version>
+               <odl.mdsal.features.version>2.1.1-Boron-SR1</odl.mdsal.features.version>
+               <odl.mdsal.model.version>0.9.1-Boron-SR1</odl.mdsal.model.version>
+               <odl.mdsal.yang.binding.version>0.9.1-Boron-SR1</odl.mdsal.yang.binding.version>
+               <odl.restconf.version>1.4.1-Boron-SR1</odl.restconf.version>
+               <odl.controller.model.version>${odl.mdsal.model.version}</odl.controller.model.version>
+               <odl.controller.config.api.version>0.5.1-Boron-SR1</odl.controller.config.api.version>
+               <odl.karaf.empty.distro.version>${odl.version}</odl.karaf.empty.distro.version>
+               <odl.commons.opendaylight.version>${odl.version}</odl.commons.opendaylight.version>
+               <odl.ietf-inet-types.version>2010.09.24.9.1-Boron-SR1</odl.ietf-inet-types.version>
+               <odl.ietf-yang-types.version>2010.09.24.9.1-Boron-SR1</odl.ietf-yang-types.version>
+               <odl.yang.jmx.generator.version>0.5.1-Boron-SR1</odl.yang.jmx.generator.version>
+               <odl.yangtools.yang.maven.plugin.version>${odl.yangtools.version}</odl.yangtools.yang.maven.plugin.version>
+               <odl.sal.api.gen.plugin.version>0.9.1-Boron-SR1</odl.sal.api.gen.plugin.version>
+
+
+
+               <!--  SDN-C component versions  -->
                <sdnc.core.version>1.1.0-SNAPSHOT</sdnc.core.version>
                <sdnc.adaptors.version>1.1.0-SNAPSHOT</sdnc.adaptors.version>
+               <sdnc.northbound.version>1.1.0-SNAPSHOT</sdnc.northbound.version>
+               <sdnc.oam.version>1.1.0-SNAPSHOT</sdnc.oam.version>
+               <sdnc.plugins.version>1.1.0-SNAPSHOT</sdnc.plugins.version>
                <sdnctl.sli.version>${sdnc.core.version}</sdnctl.sli.version>
                <sdnctl.aai.service.version>${sdnc.adaptors.version}</sdnctl.aai.service.version>
                <sdnctl.dblib.version>${sdnc.core.version}</sdnctl.dblib.version>
                <sdnctl.mdsal.resource.version>${sdnc.adaptors.version}</sdnctl.mdsal.resource.version>
                <sdnctl.slipluginutils.version>${sdnc.core.version}</sdnctl.slipluginutils.version>
+
+               <!-- Support libraries used by OpenDaylight -->
+               <!-- Used by aaa, vtn -->
+               <commons.codec.version>1.10</commons.codec.version>
+               <!-- Used by netconf, ovsdb -->
+               <commons.lang3.version>3.4</commons.lang3.version>
+               <!-- Used by sfc, snmp4sdn; see also affinity, toolkit -->
+               <commons.lang.version>2.6</commons.lang.version>
+               <!-- Used by neutron; see also controller, vtn -->
+               <commons.net.version>3.5</commons.net.version>
+               <!-- Used by neutron -->
+               <eclipse.persistence.version>2.6.2</eclipse.persistence.version>
+               <!-- Used by aaa -->
+               <felix.dependencymanager.version>4.3.0</felix.dependencymanager.version>
+               <!-- Used by lacp, netconf, ovsdb, sfc, toolkit; see also vtn -->
+               <gson.version>2.3.1</gson.version>
+               <!-- Used by aaa, dlux, persistence, snmp4sdn, sxp -->
+               <guava.version>18.0</guava.version>
+               <!-- Used by lispflowmapping, sxp, vtn/manager -->
+               <hamcrest.version>1.3</hamcrest.version>
+               <!-- Used by aaa, alto, netconf, ovsdb, sfc; see also affinity, defense4all,
+                       integration/distribution, snmp4sdn, toolkit, ttp -->
+               <jackson.version>2.3.2</jackson.version>
+               <!-- Used by snmp4sdn, yangtools -->
+               <javassist.version>3.20.0-GA</javassist.version>
+
+               <!-- FIXME remove all dependencies for jersey 1.17 after migration all
+                       projects -->
+               <!-- Used by aaa, alto, netconf, neutron, sfc; see also affinity, defense4all,
+                       snmp4sdn, toolkit -->
+               <jersey.version>1.17</jersey.version>
+               <!-- Used by sfc -->
+               <jersey.client.version>1.17</jersey.client.version>
+
+               <!-- New packages for jersey migration 1.17 to 2.8 -->
+               <!-- appache.geronimo.bundle for DocGen -->
+               <!-- Used by aaa, iotdm, netconf, ovsdb, sfc -->
+               <org.json.version>20131018</org.json.version>
+
+               <!-- Used by sfc -->
+               <jettison.version>1.3.7</jettison.version>
+               <!-- Used by persistence -->
+               <jsr305.api.version>3.0.0</jsr305.api.version>
+               <!-- Need to stick to JUnit 4.11 until https://github.com/jayway/powermock/issues/560
+                       is fixed (either in PowerMock or with a new JUnit release) -->
+               <!-- Used everywhere -->
+               <junit.version>4.11</junit.version>
+               <!-- Used by coretutorials, sfc, snmp4sdn, sxp; see also affinity, toolkit -->
+               <logback.version>1.1.7</logback.version>
+               <!-- Used by nic, sfc, sxp, tsdr -->
+               <mockito.version>1.10.19</mockito.version>
+               <!-- Used by bgpcep, netconf, ovsdb, sxp; see also opendove, toolkit -->
+               <netty.version>4.0.37.Final</netty.version>
+               <!-- Used by openflowjava, persistence, sfc, snmp4sdn, sxp; see also affinity,
+                       toolkit -->
+               <slf4j.version>1.7.21</slf4j.version>
+               <!-- Used in integration/distribution; see also affinity, snmp4sdn, toolkit,
+                       tsdr, ttp -->
+               <spring.version>3.2.14.RELEASE</spring.version>
+
+
+
+               <!-- Extra support libraries used by SDN-C -->
+               <equinox.osgi.version>3.8.1.v20120830-144521</equinox.osgi.version>
+               <jackson-annotations-version>${jackson.version}</jackson-annotations-version>
+               <jettison.version>1.3.7</jettison.version>
+               <jvnet.jaxb2.version>0.6.4</jvnet.jaxb2.version>
+               <apache.httpcomponents.version>4.4</apache.httpcomponents.version>
+               <antlr.version>4.5.1</antlr.version>
+               <mysql.connector.version>5.1.39</mysql.connector.version>
+               <h2database.version>1.4.186</h2database.version>
+
        </properties>
 
        <modelVersion>4.0.0</modelVersion>
                                                <additionalDependency>
                                                        <groupId>org.opendaylight.odlparent</groupId>
                                                        <artifactId>odlparent</artifactId>
-                                                       <version>1.6.2-Beryllium-SR2</version>
+                                                       <version>1.7.1-Boron-SR1</version>
                                                </additionalDependency>
                                                <additionalDependency>
                                                        <groupId>org.slf4j</groupId>
                                                <additionalDependency>
                                                        <groupId>org.opendaylight.mdsal</groupId>
                                                        <artifactId>yang-binding</artifactId>
-                                                       <version>${odl.yangtools.version}</version>
+                                                       <version>${odl.mdsal.yang.binding.version}</version>
                                                </additionalDependency>
                                                <additionalDependency>
                                                        <groupId>org.opendaylight.yangtools</groupId>
                                                        <additionalDependency>
                                                                <groupId>org.opendaylight.mdsal</groupId>
                                                                <artifactId>yang-binding</artifactId>
-                                                               <version>${odl.yangtools.version}</version>
+                                                               <version>${odl.mdsal.yang.binding.version}</version>
                                                        </additionalDependency>
                                                        <additionalDependency>
                                                                <groupId>org.opendaylight.yangtools</groupId>
index 7a08c34..eb06e6b 100755 (executable)
@@ -44,7 +44,7 @@
                <dependency>
                        <groupId>org.opendaylight.mdsal</groupId>
                        <artifactId>yang-binding</artifactId>
-                       <version>${odl.yangtools.version}</version>
+                       <version>${odl.mdsal.yang.binding.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.opendaylight.yangtools</groupId>
diff --git a/sli/common/src/main/java/org/openecomp/sdnc/sli/BreakNodeException.java b/sli/common/src/main/java/org/openecomp/sdnc/sli/BreakNodeException.java
new file mode 100644 (file)
index 0000000..3e355ba
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli;
+
+public class BreakNodeException extends SvcLogicException {
+       
+       /**
+        * 
+        */
+       private static final long serialVersionUID = 1L;
+
+       public BreakNodeException()
+       {
+               super();
+       }
+       
+       public BreakNodeException(String message)
+       {
+               super(message);
+       }
+       
+       public BreakNodeException(String message, Throwable t)
+       {
+               super(message, t);
+       }
+
+}
diff --git a/sli/common/src/main/java/org/openecomp/sdnc/sli/MessageWriter.java b/sli/common/src/main/java/org/openecomp/sdnc/sli/MessageWriter.java
new file mode 100644 (file)
index 0000000..5e5b621
--- /dev/null
@@ -0,0 +1,302 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Properties;
+
+import javax.sql.rowset.CachedRowSet;
+
+import org.openecomp.sdnc.sli.resource.dblib.DbLibService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class MessageWriter {
+
+       private static final Logger LOG = LoggerFactory.getLogger(MessageWriter.class);
+
+       private static final String DBLIB_SERVICE = "org.openecomp.sdnc.sli.resource.dblib.DBResourceManager";
+       private static final String SVCLOGIC_PROP_VAR = "SDNC_SLI_PROPERTIES";
+       private static final String SDNC_CONFIG_DIR = "SDNC_CONFIG_DIR";
+
+       private static final String INCOMING_PROPERTY_NAME = "org.openecomp.sdnc.sli.MessageWriter.writeIncomingRequests";
+       private static final String OUTGOING_PROPERTY_NAME = "org.openecomp.sdnc.sli.MessageWriter.writeOutgoingRequests";
+
+       private static final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+       private static DbLibService dbLibService = null;
+
+       private static boolean incomingEnabled = false;
+       private static boolean outgoingEnabled = false;
+
+       private static boolean initialized = false;
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       private static void init() {
+               if (initialized)
+                       return;
+
+               initialized = true;
+
+               // Read properties
+               Properties props = new Properties();
+               String propPath = System.getenv(SVCLOGIC_PROP_VAR);
+
+               if (propPath == null) {
+                       String propDir = System.getenv(SDNC_CONFIG_DIR);
+                       if (propDir == null) {
+                               propDir = "/opt/sdnc/data/properties";
+                       }
+                       propPath = propDir + "/svclogic.properties";
+                       LOG.warn("Environment variable " + SVCLOGIC_PROP_VAR + " unset - defaulting to " + propPath);
+               }
+
+               File propFile = new File(propPath);
+
+               if (!propFile.exists()) {
+                       LOG.warn("Property file does not exist: " + propPath);
+               }
+
+               try {
+                       props.load(new FileInputStream(propFile));
+               } catch (Exception e) {
+                       LOG.warn("Error loading property file: " + propPath, e);
+               }
+
+               incomingEnabled = Boolean.valueOf(props.getProperty(INCOMING_PROPERTY_NAME, "false"));
+               outgoingEnabled = Boolean.valueOf(props.getProperty(OUTGOING_PROPERTY_NAME, "false"));
+
+               LOG.info(INCOMING_PROPERTY_NAME + ": " + incomingEnabled);
+               LOG.info(OUTGOING_PROPERTY_NAME + ": " + outgoingEnabled);
+
+               if (dbLibService != null)
+                       return;
+
+               BundleContext bctx = FrameworkUtil.getBundle(MessageWriter.class).getBundleContext();
+
+               ServiceReference sref = bctx.getServiceReference(DBLIB_SERVICE);
+
+               if (sref == null) {
+                       LOG.warn("Could not find service reference for DBLIB service (" + DBLIB_SERVICE + ")");
+               } else {
+                       dbLibService = (DbLibService) bctx.getService(sref);
+                       if (dbLibService == null) {
+                               LOG.warn("Could not find service reference for DBLIB service (" + DBLIB_SERVICE + ")");
+                       }
+               }
+       }
+
+       public static void saveOutgoingRequest(
+               String requestId,
+               String serviceInstanceId,
+               String targetUrl,
+               String request) {
+               try {
+                       init();
+
+                       if (!outgoingEnabled)
+                               return;
+
+                       if (serviceInstanceId == null || serviceInstanceId.trim().length() == 0)
+                               serviceInstanceId = "NA";
+
+                       int seqnum = getLastSequenceNumber("OUTGOING_MESSAGE", requestId) + 1;
+                       String now = df.format(new Date());
+
+                       String sql = "INSERT INTO OUTGOING_MESSAGE (\n" +
+                               "       request_id, sequence_number, service_instance_id, target_url, request, start_time)\n" +
+                               "VALUES (?, ?, ?, ?, ?, ?)";
+
+                       ArrayList<String> data = new ArrayList<>();
+                       data.add(requestId);
+                       data.add(String.valueOf(seqnum));
+                       data.add(serviceInstanceId);
+                       data.add(targetUrl);
+                       data.add(request);
+                       data.add(now);
+
+                       dbLibService.writeData(sql, data, null);
+
+               } catch (Exception e) {
+                       LOG.warn("Failed to save outgoing request for request-id: " + requestId, e);
+               }
+       }
+
+       public static void saveOutgoingResponse(String requestId, int httpResponseCode, String response) {
+               try {
+                       init();
+
+                       if (!outgoingEnabled)
+                               return;
+
+                       int seqnum = getLastSequenceNumber("OUTGOING_MESSAGE", requestId);
+                       if (seqnum == 0) {
+                               LOG.warn("Failed to save outgoing response for request-id: " + requestId +
+                                       ": Request record not found in OUTGOING_MESSAGE");
+                               return;
+                       }
+
+                       String now = df.format(new Date());
+
+                       String sql = "UPDATE OUTGOING_MESSAGE SET http_response_code = ?, response = ?,\n" +
+                               "       duration = timestampdiff(MICROSECOND, start_time, ?) / 1000\n" +
+                               "WHERE request_id = ? AND sequence_number = ?";
+
+                       ArrayList<String> data = new ArrayList<>();
+                       data.add(String.valueOf(httpResponseCode));
+                       data.add(response);
+                       data.add(now);
+                       data.add(requestId);
+                       data.add(String.valueOf(seqnum));
+
+                       dbLibService.writeData(sql, data, null);
+
+               } catch (Exception e) {
+                       LOG.warn("Failed to save outgoing response for request-id: " + requestId, e);
+               }
+       }
+
+       public static void saveIncomingRequest(
+               String requestId,
+               String serviceInstanceId,
+               String requestHost,
+               String request) {
+               try {
+                       init();
+
+                       if (!incomingEnabled)
+                               return;
+
+                       if (serviceInstanceId == null || serviceInstanceId.trim().length() == 0)
+                               serviceInstanceId = "NA";
+
+                       int seqnum = getLastSequenceNumber("INCOMING_MESSAGE", requestId) + 1;
+                       String now = df.format(new Date());
+
+                       String sql = "INSERT INTO INCOMING_MESSAGE (\n" +
+                               "       request_id, sequence_number, service_instance_id, request_host, request, start_time)\n" +
+                               "VALUES (?, ?, ?, ?, ?, ?)";
+
+                       ArrayList<String> data = new ArrayList<>();
+                       data.add(requestId);
+                       data.add(String.valueOf(seqnum));
+                       data.add(serviceInstanceId);
+                       data.add(requestHost);
+                       data.add(request);
+                       data.add(now);
+
+                       dbLibService.writeData(sql, data, null);
+
+               } catch (Exception e) {
+                       LOG.warn("Failed to save incoming request for request-id: " + requestId, e);
+               }
+       }
+
+       public static void saveIncomingResponse(String requestId, int httpResponseCode, String response) {
+               try {
+                       init();
+
+                       if (!incomingEnabled)
+                               return;
+
+                       int seqnum = getLastSequenceNumber("INCOMING_MESSAGE", requestId);
+                       if (seqnum == 0) {
+                               LOG.warn("Failed to save response for request-id: " + requestId +
+                                       ": Request record not found in INCOMING_MESSAGE");
+                               return;
+                       }
+
+                       String now = df.format(new Date());
+
+                       String sql = "UPDATE INCOMING_MESSAGE SET http_response_code = ?, response = ?,\n" +
+                               "       duration = timestampdiff(MICROSECOND, start_time, ?) / 1000\n" +
+                               "WHERE request_id = ? AND sequence_number = ?";
+
+                       ArrayList<String> data = new ArrayList<>();
+                       data.add(String.valueOf(httpResponseCode));
+                       data.add(response);
+                       data.add(now);
+                       data.add(requestId);
+                       data.add(String.valueOf(seqnum));
+
+                       dbLibService.writeData(sql, data, null);
+
+               } catch (Exception e) {
+                       LOG.warn("Failed to save response for request-id: " + requestId, e);
+               }
+       }
+
+       public static String getServiceInstanceId(String requestId) throws SQLException {
+               init();
+
+               String sql = "SELECT service_instance_id FROM OUTGOING_MESSAGE WHERE request_id = '" + requestId +
+                       "' ORDER BY sequence_number DESC";
+
+               CachedRowSet rs = null;
+               try {
+                       rs = dbLibService.getData(sql, null, null);
+                       if (rs.next()) {
+                               return rs.getString("service_instance_id");
+                       }
+               } finally {
+                       if (rs != null) {
+                               try {
+                                       rs.close();
+                               } catch (Exception e) {
+                                       LOG.warn("Failed to close CachedRowSet", e);
+                               }
+                       }
+               }
+               return null;
+       }
+
+       private static int getLastSequenceNumber(String tableName, String requestId) throws SQLException {
+               String sql = "SELECT sequence_number FROM " + tableName + " WHERE request_id = '" + requestId +
+                       "' ORDER BY sequence_number DESC";
+
+               CachedRowSet rs = null;
+               try {
+                       rs = dbLibService.getData(sql, null, null);
+                       if (rs.next()) {
+                               return rs.getInt("sequence_number");
+                       }
+               } finally {
+                       if (rs != null) {
+                               try {
+                                       rs.close();
+                               } catch (Exception e) {
+                                       LOG.warn("Failed to close CachedRowSet", e);
+                               }
+                       }
+               }
+               return 0;
+       }
+}
index d8d3384..4fef12f 100644 (file)
@@ -77,7 +77,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
        
        private void pushExpr(SvcLogicExpression expr)
        {
-               LOG.debug("Pushing expression ["+expr.getClass().getName()+"]");
+               LOG.trace("Pushing expression ["+expr.getClass().getName()+"]");
                if (curExpr != null)
                {
                        exprStack.push(curExpr);
@@ -89,7 +89,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
        {
                if (exprStack.isEmpty())
                {
-                       LOG.debug("Popping last expression");
+                       LOG.trace("Popping last expression");
                        topExpr = curExpr;
                }
                else
@@ -97,7 +97,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
                        SvcLogicExpression lastExpr = curExpr;
                        curExpr = exprStack.pop();
                        curExpr.addOperand(lastExpr);
-                       LOG.debug("New curExpr is ["+curExpr.getClass().getName()+"]");
+                       LOG.trace("New curExpr is ["+curExpr.getClass().getName()+"]");
                }
                
        }
@@ -107,7 +107,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
                
                String atomText = ctx.getText();
                
-               LOG.debug("enterAtom: text = "+atomText);
+               LOG.trace("enterAtom: text = "+atomText);
 
                
                SvcLogicAtom newAtom = new SvcLogicAtom(atomText);
@@ -118,7 +118,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
 
        @Override
        public void enterMultExpr(MultExprContext ctx) {
-               LOG.debug("enterMultExpr: text = "+ctx.getText());
+               LOG.trace("enterMultExpr: text = "+ctx.getText());
                
                SvcLogicBinaryExpression curBinExpr = new SvcLogicBinaryExpression();
                pushExpr(curBinExpr);
@@ -127,7 +127,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
                
                for (TerminalNode nd : opList)
                {
-                       LOG.debug("enterMultExpr: operator - "+nd.getText());
+                       LOG.trace("enterMultExpr: operator - "+nd.getText());
                        curBinExpr.addOperator(nd.getText());
                }
 
@@ -136,7 +136,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
        @Override
        public void exitMultExpr(MultExprContext ctx) {
 
-               LOG.debug("exitMultExpr: text = "+ctx.getText());
+               LOG.trace("exitMultExpr: text = "+ctx.getText());
 
                popExpr();
                
@@ -144,13 +144,13 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
 
        @Override
        public void exitAtom(AtomContext ctx) {
-               LOG.debug("exitAtom: text = "+ctx.getText());
+               LOG.trace("exitAtom: text = "+ctx.getText());
                popExpr();
        }
 
        @Override
        public void enterAddExpr(AddExprContext ctx) {
-               LOG.debug("enterAddExpr: text = "+ctx.getText());
+               LOG.trace("enterAddExpr: text = "+ctx.getText());
                List<TerminalNode> opList = ctx.ADDOP();
                
 
@@ -160,7 +160,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
                
                for (TerminalNode nd : opList)
                {
-                       LOG.debug("enterAddExpr: operator - "+nd.getText());
+                       LOG.trace("enterAddExpr: operator - "+nd.getText());
                        curBinExpr.addOperator(nd.getText());
                }
                
@@ -168,19 +168,19 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
 
        @Override
        public void exitAddExpr(AddExprContext ctx) {
-               LOG.debug("exitAddExpr: text = "+ctx.getText());
+               LOG.trace("exitAddExpr: text = "+ctx.getText());
                
                popExpr();
        }
 
        @Override
        public void enterFuncExpr(FuncExprContext ctx) {
-               LOG.debug("enterFuncExpr: text = "+ctx.getText());
-               LOG.debug("enterFuncExpr - IDENTIFIER : "+ctx.IDENTIFIER().getText());
+               LOG.trace("enterFuncExpr: text = "+ctx.getText());
+               LOG.trace("enterFuncExpr - IDENTIFIER : "+ctx.IDENTIFIER().getText());
                
                for (ExprContext expr: ctx.expr())
                {
-                       LOG.debug("enterFuncExpr - expr = "+expr.getText());
+                       LOG.trace("enterFuncExpr - expr = "+expr.getText());
                }
                
 
@@ -189,25 +189,25 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
 
        @Override
        public void exitFuncExpr(FuncExprContext ctx) {
-               LOG.debug("exitFuncExpr: text = "+ctx.getText());
+               LOG.trace("exitFuncExpr: text = "+ctx.getText());
                
                popExpr();
        }
 
        @Override
        public void enterParenExpr(ParenExprContext ctx) {
-               LOG.debug("enterParenExpr: text = "+ctx.getText());
-               LOG.debug("enterParenExpr: expr = "+ctx.expr().getText());
+               LOG.trace("enterParenExpr: text = "+ctx.getText());
+               LOG.trace("enterParenExpr: expr = "+ctx.expr().getText());
        }
 
        @Override
        public void exitParenExpr(ParenExprContext ctx) {
-               LOG.debug("exitParenExpr: text = "+ctx.getText());
+               LOG.trace("exitParenExpr: text = "+ctx.getText());
        }
 
        @Override
        public void enterRelExpr(RelExprContext ctx) {
-               LOG.debug("enterRelExpr: text = "+ctx.getText());
+               LOG.trace("enterRelExpr: text = "+ctx.getText());
                
                List<TerminalNode> opList = ctx.RELOP();
                
@@ -218,7 +218,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
                
                for (TerminalNode nd : opList)
                {
-                       LOG.debug("enterRelExpr: operator - "+nd.getText());
+                       LOG.trace("enterRelExpr: operator - "+nd.getText());
                        curBinExpr.addOperator(nd.getText());
                }
                
@@ -226,28 +226,28 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
 
        @Override
        public void exitRelExpr(RelExprContext ctx) {
-               LOG.debug("exitRelExpr: text = "+ctx.getText());
+               LOG.trace("exitRelExpr: text = "+ctx.getText());
                
                popExpr();
        }
 
        @Override
        public void enterCompareExpr(CompareExprContext ctx) {
-               LOG.debug("enterCompareExpr: text = "+ctx.getText());
+               LOG.trace("enterCompareExpr: text = "+ctx.getText());
                
                TerminalNode nd = ctx.COMPAREOP();
 
                SvcLogicBinaryExpression curBinExpr = new SvcLogicBinaryExpression();
                pushExpr(curBinExpr);
 
-               LOG.debug("enterCompareExpr: operator - "+nd.getText());
+               LOG.trace("enterCompareExpr: operator - "+nd.getText());
                curBinExpr.addOperator(nd.getText());
 
        }
 
        @Override
        public void exitCompareExpr(CompareExprContext ctx) {
-               LOG.debug("exitCompareExpr : text = "+ctx.getText());
+               LOG.trace("exitCompareExpr : text = "+ctx.getText());
                
                popExpr();
        }
@@ -256,18 +256,18 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
        
        @Override 
        public void enterConstant(ConstantContext ctx) {
-               LOG.debug("enterConstant: text = "+ctx.getText());
+               LOG.trace("enterConstant: text = "+ctx.getText());
        }
 
        @Override
        public void exitConstant(ConstantContext ctx) {
-               LOG.debug("exitConstant: text = "+ctx.getText());
+               LOG.trace("exitConstant: text = "+ctx.getText());
        }
 
 
        @Override
        public void enterVariable(VariableContext ctx) {
-               LOG.debug("enterVariable: text = "+ctx.getText());
+               LOG.trace("enterVariable: text = "+ctx.getText());
                
                
        }
@@ -290,12 +290,12 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
        @Override
        public void exitVariableLead(VariableLeadContext ctx) {
 
-               LOG.debug("exitVariableLead: text ="+ctx.getText());
+               LOG.trace("exitVariableLead: text ="+ctx.getText());
        }
 
        @Override
        public void enterVariableTerm(VariableTermContext ctx) {
-               LOG.debug("enterVariableTerm: text ="+ctx.getText());
+               LOG.trace("enterVariableTerm: text ="+ctx.getText());
                
                String name = ctx.getText();
                
@@ -310,7 +310,7 @@ public class SvcLogicExprListener extends ExprGrammarBaseListener
 
        @Override
        public void exitVariableTerm(VariableTermContext ctx) {
-               LOG.debug("exitVariableTerm: text="+ctx.getText());
+               LOG.trace("exitVariableTerm: text="+ctx.getText());
                popExpr();
        }
 }
index 751564b..cce8e04 100644 (file)
@@ -42,7 +42,7 @@ public class SvcLogicExpressionFactory {
        
        public static SvcLogicExpression parse(String exprStr) throws IOException
        {
-               LOG.debug("parse("+exprStr+")");
+               LOG.trace("parse("+exprStr+")");
                InputStream exprStream = new ByteArrayInputStream(exprStr.getBytes());
                CharStream input = new ANTLRInputStream(exprStream);
                ExprGrammarLexer lexer = new ExprGrammarLexer(input);
diff --git a/sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/BreakNodeExecutor.java b/sli/provider/src/main/java/org/openecomp/sdnc/sli/provider/BreakNodeExecutor.java
new file mode 100644 (file)
index 0000000..0f8719c
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import org.openecomp.sdnc.sli.BreakNodeException;
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.openecomp.sdnc.sli.SvcLogicNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BreakNodeExecutor extends SvcLogicNodeExecutor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BreakNodeExecutor.class);
+
+    @Override
+    public SvcLogicNode execute(SvcLogicServiceImpl svc, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException {
+        String message = "BreakNodeExecutor encountered break with nodeId " + node.getNodeId();
+        LOG.debug(message);
+        throw new BreakNodeException(message);
+    }
+
+}
index 2ce4f0a..da0bc56 100644 (file)
@@ -114,24 +114,21 @@ public class CallNodeExecutor extends SvcLogicNodeExecutor {
                        version  = SvcLogicExpressionResolver.evaluate(moduleExpr, node, ctx);
                }
 
+               String parentGraph = ctx.getAttribute("currentGraph");
+        ctx.setAttribute("parentGraph", parentGraph);
                
                SvcLogicStore store = SvcLogicActivator.getStore();
                
-               LOG.debug("Calling ["+module+","+rpc+","+version+","+mode+"]");
-               
-               if (store != null)
-               {
+        if (store != null) {
                        SvcLogicGraph calledGraph = store.fetch(module, rpc, version, mode);
-                       
-                       if (calledGraph != null)
-                       {
+            LOG.debug("Parent " + parentGraph + " is calling child " + calledGraph.toString());
+            ctx.setAttribute("currentGraph", calledGraph.toString());
+            if (calledGraph != null) {
                                svc.execute(calledGraph, ctx);
                                
                                outValue = ctx.getStatus();
-                       }
-                       else
-                       {
-                               LOG.debug("Could not find service logic for ["+module+","+rpc+","+version+","+mode+"]");
+            } else {
+                LOG.error("Could not find service logic for [" + module + "," + rpc + "," + version + "," + mode + "]");
                        }
                }
                else
@@ -144,6 +141,7 @@ public class CallNodeExecutor extends SvcLogicNodeExecutor {
                        if (LOG.isDebugEnabled()) {
                                LOG.debug("about to execute " + outValue + " branch");
                        }
+            ctx.setAttribute("currentGraph", parentGraph);
                        return (nextNode);
                }
 
@@ -157,6 +155,9 @@ public class CallNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.debug("no " + outValue + " or Other branch found");
                        }
                }
+        ctx.setAttribute("currentGraph", parentGraph);
+        ctx.setAttribute("parentGraph", null);
+
                return (nextNode);
 
        }
index 97da2a6..375c631 100644 (file)
@@ -53,15 +53,8 @@ public class DeleteNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
-
-               ServiceReference sref = bctx.getServiceReference(plugin);
-
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
 
+               SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
                        if (resourcePlugin != null) {
 
                                try {
@@ -85,10 +78,7 @@ public class DeleteNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
+
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -110,6 +100,22 @@ public class DeleteNodeExecutor extends SvcLogicNodeExecutor {
                }
                return (nextNode);
        }
+       
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
 
 
 }
index 158c843..85aede7 100644 (file)
@@ -21,6 +21,7 @@
 
 package org.openecomp.sdnc.sli.provider;
 
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -44,6 +45,7 @@ public class ExecuteNodeExecutor extends SvcLogicNodeExecutor {
        private static final Logger LOG = LoggerFactory
                        .getLogger(ExecuteNodeExecutor.class);
 
+       private static final String pluginErrorMessage = "Could not execute plugin. SvcLogic status will be set to failure.";
        public SvcLogicNode execute(SvcLogicServiceImpl svc, SvcLogicNode node,
                        SvcLogicContext ctx) throws SvcLogicException {
 
@@ -55,35 +57,30 @@ public class ExecuteNodeExecutor extends SvcLogicNodeExecutor {
                        LOG.debug("execute node encountered - looking for plugin "
                                        + pluginName);
                }
-               
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
 
-               ServiceReference sref = bctx.getServiceReference(pluginName);
+        SvcLogicJavaPlugin plugin  = getSvcLogicJavaPlugin(pluginName);
 
-               if (sref == null) {
+               if (plugin == null) {
                        outValue = "not-found";
                } else {
-                       SvcLogicJavaPlugin plugin  = (SvcLogicJavaPlugin) bctx
-                                       .getService(sref);
-                       
-                       String methodName = SvcLogicExpressionResolver.evaluate(node.getAttribute("method"),  node, ctx);
-                       
+
+                       String methodName = evaluate(node.getAttribute("method"),  node, ctx);
+
                        Class pluginClass = plugin.getClass();
-                       
+
                        Method pluginMethod = null;
-                       
+
                        try {
                                pluginMethod = pluginClass.getMethod(methodName, Map.class, SvcLogicContext.class);
-                       } catch (Exception e) {
-                               LOG.error("Caught exception looking for method "+pluginName+"."+methodName+"(Map, SvcLogicContext)");
+                       } catch (NoSuchMethodException e) {
+                               LOG.error(pluginErrorMessage, e);
                        }
-                       
+
                        if (pluginMethod == null) {
                                outValue = "unsupported-method";
                        } else {
                                try {
-                                       
+
                                        Map<String, String> parmMap = new HashMap<String, String>();
 
                                        Set<Map.Entry<String, SvcLogicExpression>> parmSet = node
@@ -95,21 +92,34 @@ public class ExecuteNodeExecutor extends SvcLogicNodeExecutor {
                                                String curName = curEnt.getKey();
                                                SvcLogicExpression curExpr = curEnt.getValue();
                                                String curExprValue = SvcLogicExpressionResolver.evaluate(curExpr, node, ctx);
-                                               
+
                                                LOG.debug("Parameter "+curName+" = "+curExpr.asParsedExpr()+" resolves to "+curExprValue);
 
                                                parmMap.put(curName,curExprValue);
                                        }
-                                       
-                                       pluginMethod.invoke(plugin, parmMap, ctx);
-                                       
-                                       outValue = "success";
-                               } catch (Exception e) {
-                                       LOG.error("Caught exception executing "+pluginName+"."+methodName, e);
-                                       
+
+                                       Object o = pluginMethod.invoke(plugin, parmMap, ctx);
+                               String emitsOutcome = SvcLogicExpressionResolver.evaluate(node.getAttribute("emitsOutcome"),  node, ctx);
+
+                                       outValue = mapOutcome(o, emitsOutcome);
+
+                               } catch (InvocationTargetException e) {
+                                   if(e.getCause() != null){
+                           LOG.error(pluginErrorMessage, e.getCause());
+                                   }else{
+                                       LOG.error(pluginErrorMessage, e);
+                                   }
                                        outValue = "failure";
                                        ctx.setStatus("failure");
-                               }
+                               } catch (IllegalAccessException e) {
+                    LOG.error(pluginErrorMessage, e);
+                    outValue = "failure";
+                    ctx.setStatus("failure");
+                } catch (IllegalArgumentException e) {
+                    LOG.error(pluginErrorMessage, e);
+                    outValue = "failure";
+                    ctx.setStatus("failure");
+                }
                        }
 
                }
@@ -135,4 +145,37 @@ public class ExecuteNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+       protected SvcLogicJavaPlugin getSvcLogicJavaPlugin(String pluginName){
+              BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                       .getBundleContext();
+
+               ServiceReference sref = bctx.getServiceReference(pluginName);
+
+               if (sref == null) {
+                   LOG.warn("Could not find service reference object for plugin " + pluginName);
+                   return null;
+               } else {
+                   SvcLogicJavaPlugin plugin  = (SvcLogicJavaPlugin) bctx
+                           .getService(sref);
+                   return plugin;
+               }
+       }
+       protected String evaluate(SvcLogicExpression expr, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException {
+        return SvcLogicExpressionResolver.evaluate(node.getAttribute("method"), node, ctx);
+    }
+
+    public String mapOutcome(Object o, String emitsOutcome) {
+        if (emitsOutcome != null) {
+            Boolean nodeEmitsOutcome = Boolean.valueOf(emitsOutcome);
+            if (nodeEmitsOutcome) {
+                return (String) o;
+            } else {
+                return "success";
+            }
+
+        } else {
+            return "success";
+        }
+    }
+
 }
index 48b511e..464c676 100644 (file)
@@ -55,14 +55,9 @@ public class ExistsNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
 
-               ServiceReference sref = bctx.getServiceReference(plugin);
 
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
+                       SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
 
                        if (resourcePlugin != null) {
 
@@ -87,10 +82,6 @@ public class ExistsNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -114,5 +105,21 @@ public class ExistsNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
+
 
 }
index a669712..e9fdc55 100644 (file)
@@ -21,6 +21,7 @@
 
 package org.openecomp.sdnc.sli.provider;
 
+import org.openecomp.sdnc.sli.BreakNodeException;
 import org.openecomp.sdnc.sli.SvcLogicContext;
 import org.openecomp.sdnc.sli.SvcLogicException;
 import org.openecomp.sdnc.sli.SvcLogicExpression;
@@ -40,7 +41,7 @@ public class ForNodeExecutor extends SvcLogicNodeExecutor {
                SvcLogicExpression atomicExpr = node.getAttribute("atomic");
                String atomicStr = SvcLogicExpressionResolver.evaluate(atomicExpr, node, ctx);
                boolean isAtomic = !("false".equalsIgnoreCase(atomicStr));
-               
+
                int numOutcomes = node.getNumOutcomes();
                String idxVar = SvcLogicExpressionResolver.evaluate(
                                node.getAttribute("index"), node, ctx);
@@ -59,21 +60,30 @@ public class ForNodeExecutor extends SvcLogicNodeExecutor {
                        startIdx = Integer.parseInt(startVal);
                        endIdx = Integer.parseInt(endVal);
                } catch (NumberFormatException e) {
-                       throw new SvcLogicException("Invalid index values [" + startVal
-                                       + "," + endVal + "]");
+                       SvcLogicExpression silentFailureExpr = node.getAttribute("silentFailure");
+                       String silentFailure = SvcLogicExpressionResolver.evaluate(silentFailureExpr, node, ctx);
+                       boolean isSilentFailure = Boolean.parseBoolean(silentFailure);
+                       String message = "Invalid index values [" + startVal + "," + endVal + "]";
+                       if(!isSilentFailure){
+                       throw new SvcLogicException(message);
+                       }else{
+                           LOG.debug(message + ". Not exiting because silentFailure was set to true.");
+                           return(null);
+                       }
                }
 
+        try {
                for (int ctr = startIdx; ctr < endIdx; ctr++) {
 
                        ctx.setAttribute(idxVar, "" + ctr);
 
                        for (int i = 0; i < numOutcomes; i++) {
-                               
+
                                if ("failure".equals(ctx.getStatus()) && isAtomic) {
                                        LOG.info("For - stopped executing nodes due to failure status");
                                        return(null);
                                }
-                               
+
                                SvcLogicNode nextNode = node.getOutcomeValue("" + (i + 1));
                                if (nextNode != null) {
                                        if (LOG.isDebugEnabled()) {
@@ -83,7 +93,6 @@ public class ForNodeExecutor extends SvcLogicNodeExecutor {
                                        while (innerNextNode != null) {
                                                innerNextNode = svc.executeNode(innerNextNode, ctx);
                                        }
-
                                } else {
                                        if (LOG.isDebugEnabled()) {
                                                LOG.debug("For - done: no outcome " + (i + 1));
@@ -91,6 +100,9 @@ public class ForNodeExecutor extends SvcLogicNodeExecutor {
                                }
                        }
                }
+        } catch (BreakNodeException br) {
+            LOG.debug("ForNodeExecutor caught break");
+        }
                return (null);
        }
 
index ce0fe68..c260db2 100644 (file)
@@ -84,14 +84,8 @@ public class GetResourceNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
 
-               ServiceReference sref = bctx.getServiceReference(plugin);
-
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
+                       SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
 
                        if (resourcePlugin != null) {
 
@@ -116,9 +110,7 @@ public class GetResourceNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Cound not find service reference for plugin " + plugin);
-               }
+
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -141,6 +133,22 @@ public class GetResourceNodeExecutor extends SvcLogicNodeExecutor {
                }
                return (nextNode);
        }
+       
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
 
 
 }
index 47eebe4..00c7e66 100644 (file)
@@ -56,14 +56,8 @@ public class IsAvailableNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
+            SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
 
-               ServiceReference sref = bctx.getServiceReference(plugin);
-
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
 
                        if (resourcePlugin != null) {
                                try {
@@ -86,10 +80,6 @@ public class IsAvailableNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -113,5 +103,20 @@ public class IsAvailableNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
 
 }
index 9847416..4c5ee06 100644 (file)
@@ -47,1359 +47,1140 @@ import org.slf4j.LoggerFactory;
 
 public class MdsalHelper {
 
-       private static final Logger LOG = LoggerFactory.getLogger(MdsalHelper.class);
-       public static final String PROPERTIES_FILE="/opt/bvc/controller/configuration/l3sdn.properties";
-       private static Properties properties = new Properties();
-       
-       
-       public static void setProperties(Properties properties) {
-               
-               for (Object propNameObj: properties.keySet()) {
-                       String propName = (String) propNameObj;
-                       MdsalHelper.properties.setProperty(propName, properties.getProperty(propName));
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalHelper.class);
+    private static Properties yangMappingProperties = new Properties();
+
+    @Deprecated
+    public static void setProperties(Properties input) {
+        setYangMappingProperties(input);
+    }
+    
+    public static void setYangMappingProperties(Properties properties) {
+        for (Object propNameObj : properties.keySet()) {
+            String propName = (String) propNameObj;
+            MdsalHelper.yangMappingProperties.setProperty(propName, properties.getProperty(propName));
+        }
+    }
+
+    public static void loadProperties(String propertiesFile) {
+       File file = new File(propertiesFile);
+       Properties properties = new Properties();
+       InputStream input = null;
+       if (file.isFile() && file.canRead()) {
+           try {
+               input = new FileInputStream(file);
+               properties.load(input);
+               MdsalHelper.setYangMappingProperties(properties);
+               LOG.info("Loaded properties from " + propertiesFile);
+           } catch (Exception e) {
+               LOG.error("Failed to load properties " + propertiesFile + "\n", e);
+           } finally {
+               if (input != null) {
+                   try {
+                       input.close();
+                   } catch (IOException e) {
+                       LOG.error("Failed to close properties file " + propertiesFile + "\n", e);
+                   }
                }
+           }
+       }else{
+           LOG.error("Failed to load the properties file " + propertiesFile + "\n");
+           LOG.error("Either isFile or canRead returned false for " + propertiesFile + "\n");
        }
+    }
 
-       public static void loadProperties() {
-
-               File file = new File(PROPERTIES_FILE); 
-               Properties properties = new Properties();
-               InputStream input = null;
-               if (file.isFile() && file.canRead()) {
-                       try     {
-                               input = new FileInputStream(file);
-                               properties.load(input);
-                               MdsalHelper.setProperties(properties);
-                               LOG.info("Loaded properties from " + PROPERTIES_FILE );
-                       } catch (Exception e) {
-                               LOG.error("Failed to load properties " + PROPERTIES_FILE +"\n",e);
-                       } finally {
-                               if (input != null) {
-                                       try {
-                                               input.close();
-                                       } catch (IOException e) {
-                                               LOG.error("Failed to close properties file " + PROPERTIES_FILE +"\n",e);
-                                       }
-                               }
-                       }
-               }
+    public static Properties toProperties(Properties props, Object fromObj) {
+       Class fromClass = null;
+
+       if (fromObj != null) {
+           fromClass = fromObj.getClass();
        }
-       
-       public static Properties toProperties(Properties props, Object fromObj) {
-               Class fromClass = null;
-               
-               if (fromObj != null)
-               {
-                       fromClass = fromObj.getClass();
-               }
-               return (toProperties(props, "", fromObj, fromClass));
+       return (toProperties(props, "", fromObj, fromClass));
+    }
+
+    public static Properties toProperties(Properties props, String pfx, Object fromObj) {
+       Class fromClass = null;
+
+       if (fromObj != null) {
+           fromClass = fromObj.getClass();
        }
-       
-       public static Properties toProperties(Properties props, String pfx, Object fromObj)
-       {
-               Class fromClass = null;
-               
-               if (fromObj != null)
-               {
-                       fromClass = fromObj.getClass();
-               }
-               
-               return(toProperties(props, pfx, fromObj, fromClass));
+
+       return (toProperties(props, pfx, fromObj, fromClass));
+    }
+
+    public static Properties toProperties(Properties props, String pfx, Object fromObj, Class fromClass) {
+
+       if (fromObj == null) {
+           return (props);
        }
 
-       public static Properties toProperties(Properties props, String pfx,
-                       Object fromObj, Class fromClass) {
+       String simpleName = fromClass.getSimpleName();
+
+       LOG.trace("Extracting properties from " + fromClass.getName() + " class");
+       if (fromObj instanceof List) {
+
+           // Class is a List. List should contain yang-generated classes.
+           LOG.trace(fromClass.getName() + " is a List");
+
+           List fromList = (List) fromObj;
+
+           for (int i = 0; i < fromList.size(); i++) {
+               toProperties(props, pfx + "[" + i + "]", fromList.get(i), fromClass);
+           }
+           props.setProperty(pfx + "_length", "" + fromList.size());
 
-               if (fromObj == null) {
-                       return (props);
+       } else if (isYangGenerated(fromClass)) {
+           // Class is yang generated.
+           LOG.trace(fromClass.getName() + " is a Yang-generated class");
+
+           String propNamePfx = null;
+
+           // If called from a list (so prefix ends in ']'), don't
+           // add class name again
+           if (pfx.endsWith("]")) {
+               propNamePfx = pfx;
+           } else {
+               if ((pfx != null) && (pfx.length() > 0)) {
+                   propNamePfx = pfx;
+               } else {
+                   propNamePfx = toLowerHyphen(fromClass.getSimpleName());
                }
-       
-               
-               String simpleName = fromClass.getSimpleName();
 
-               LOG.trace("Extracting properties from " + fromClass.getName()
-                               + " class");
-               if (fromObj instanceof List) {
+               if (propNamePfx.endsWith("-builder")) {
+                   propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-builder".length());
+               }
 
-                       // Class is a List. List should contain yang-generated classes.
-                       LOG.trace(fromClass.getName() + " is a List");
+               if (propNamePfx.endsWith("-impl")) {
+                   propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-impl".length());
+               }
+           }
 
-                       List fromList = (List) fromObj;
+           // Iterate through getter methods to figure out values we need to
+           // save from
 
-                       for (int i = 0; i < fromList.size(); i++) {
-                               toProperties(props, pfx + "[" + i + "]", fromList.get(i), fromClass);
-                       }
-                       props.setProperty(pfx + "_length", "" + fromList.size());
+           int numGetters = 0;
+           String lastGetterName = null;
+           String propVal = null;
 
-               } else if (isYangGenerated(fromClass)) {
-                       // Class is yang generated.
-                       LOG.trace(fromClass.getName() + " is a Yang-generated class");
+           for (Method m : fromClass.getMethods()) {
+               if (isGetter(m)) {
 
-                       String propNamePfx = null;
+                   numGetters++;
+                   lastGetterName = m.getName();
 
-                       // If called from a list (so prefix ends in ']'), don't
-                       // add class name again
-                       if (pfx.endsWith("]")) {
-                               propNamePfx = pfx;
-                       } else {
-                               if ((pfx != null) && (pfx.length() > 0)) {
-                                       propNamePfx = pfx ;
-                               } else {
-                                       propNamePfx = toLowerHyphen(fromClass.getSimpleName());
-                               }
+                   Class returnType = m.getReturnType();
+                   String fieldName;
+                   if (m.getName().startsWith("get")) {
+                       fieldName = toLowerHyphen(m.getName().substring(3));
+                   } else {
 
-                               if (propNamePfx.endsWith("-builder")) {
-                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
-                                                       - "-builder".length());
+                       fieldName = toLowerHyphen(m.getName().substring(2));
+                   }
+
+                   fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
+
+                   // Is the return type a yang generated class?
+                   if (isYangGenerated(returnType)) {
+                       // Is it an enum?
+                       if (returnType.isEnum()) {
+                           // Return type is a typedef. Save its value.
+                           try {
+                               boolean isAccessible = m.isAccessible();
+                               if (!isAccessible) {
+                                   m.setAccessible(true);
                                }
 
-                               if (propNamePfx.endsWith("-impl")) {
-                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
-                                                       - "-impl".length());
+                               Object retValue = m.invoke(fromObj);
+
+                               if (!isAccessible) {
+                                   m.setAccessible(isAccessible);
+                               }
+                               if (retValue != null) {
+                                   String propName = propNamePfx + "." + fieldName;
+                                   propVal = retValue.toString();
+                                   props.setProperty(propName, mapEnumeratedValue(fieldName, propVal));
+                               }
+                           } catch (Exception e) {
+                               LOG.error("Caught exception trying to convert Yang-generated enum returned by " + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                           }
+                       } else if (isIpv4Address(returnType)) {
+                           // Save its value
+                           try {
+                               String propName = propNamePfx + "." + fieldName;
+                               boolean isAccessible = m.isAccessible();
+                               if (!isAccessible) {
+                                   m.setAccessible(true);
+                               }
+                               Ipv4Address retValue = (Ipv4Address) m.invoke(fromObj);
+                               if (!isAccessible) {
+                                   m.setAccessible(isAccessible);
                                }
-                       }
-                       
-                       // Iterate through getter methods to figure out values we need to
-                       // save from
-
-                       int numGetters = 0;
-                       String lastGetterName = null;
-                       String propVal = null;
-                       
-                       for (Method m : fromClass.getMethods()) {
-                               if (isGetter(m)) {
-                                       
-                                       numGetters++;
-                                       lastGetterName = m.getName();
-                                       
-                                       Class returnType = m.getReturnType();
-                                       String fieldName;
-                                       if (m.getName().startsWith("get")) {
-                                               fieldName = toLowerHyphen(m.getName().substring(3));
-                                       } else {
 
-                                               fieldName = toLowerHyphen(m.getName().substring(2));
-                                       }
-                                       
-                                       fieldName = fieldName.substring(0, 1).toLowerCase()
-                                                       + fieldName.substring(1);
-
-                                       // Is the return type a yang generated class?
-                                       if (isYangGenerated(returnType)) {
-                                               // Is it an enum?
-                                               if (returnType.isEnum()) {
-                                                       // Return type is a typedef. Save its value.
-                                                       try {
-                                                               boolean isAccessible = m.isAccessible();
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(true);
-                                                               }
-
-                                                               Object retValue = m.invoke(fromObj);
-
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(isAccessible);
-                                                               }
-                                                               if (retValue != null) {
-                                                                       String propName = propNamePfx + "."
-                                                                                       + fieldName;
-                                                                       propVal = retValue.toString();
-                                                                       String yangProp = "yang." + fieldName + "." + propVal;
-                                                                       if ( properties.containsKey(yangProp)) {
-                                                                               propVal = properties.getProperty(yangProp);
-                                                                               LOG.trace("Adjusting property " + yangProp + " " + propVal);
-                                                                       }
-                                                                       LOG.debug("Setting property " + propName
-                                                                                       + " to " + propVal);
-                                                                       props.setProperty(propName, propVal);
-                                                               }
-                                                       } catch (Exception e) {
-                                                               LOG.error(
-                                                                               "Caught exception trying to convert Yang-generated enum returned by "
-                                                                                               + fromClass.getName() + "."
-                                                                                               + m.getName()
-                                                                                               + "() to Properties entry", e);
-                                                       }
-                                               } else if (isIpv4Address(returnType)) {
-                                                       // Save its value
-                                                       try {
-                                                               String propName = propNamePfx + "." + fieldName;
-                                                               boolean isAccessible = m.isAccessible();
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(true);
-                                                               }
-                                                               Ipv4Address retValue = (Ipv4Address) m.invoke(fromObj);
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(isAccessible);
-                                                               }
-
-                                                               if (retValue != null) {
-                                                                       propVal = retValue.getValue().toString();
-                                                                       LOG.debug("Setting property " + propName
-                                                                                       + " to " + propVal);
-                                                                       props.setProperty(propName, propVal);
-
-                                                               }
-                                                       } catch (Exception e) {
-                                                               LOG.error(
-                                                                               "Caught exception trying to convert value returned by "
-                                                                                               + fromClass.getName() + "."
-                                                                                               + m.getName()
-                                                                                               + "() to Properties entry", e);
-                                                       }
-                                               } else if (isIpv6Address(returnType)) {
-                                                       // Save its value
-                                                       try {
-                                                               String propName = propNamePfx + "." + fieldName;
-                                                               boolean isAccessible = m.isAccessible();
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(true);
-                                                               }
-                                                               Ipv6Address retValue = (Ipv6Address) m.invoke(fromObj);
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(isAccessible);
-                                                               }
-
-                                                               if (retValue != null) {
-                                                                       propVal = retValue.getValue().toString();
-                                                                       LOG.debug("Setting property " + propName
-                                                                                       + " to " + propVal);
-                                                                       props.setProperty(propName, propVal);
-
-                                                               }
-                                                       } catch (Exception e) {
-                                                               LOG.error(
-                                                                               "Caught exception trying to convert value returned by "
-                                                                                               + fromClass.getName() + "."
-                                                                                               + m.getName()
-                                                                                               + "() to Properties entry", e);
-                                                       }
-                                               } else if (isIpAddress(returnType)) {
-                                                       // Save its value
-                                                       try {
-                                                               String propName = propNamePfx + "." + fieldName;
-                                                               boolean isAccessible = m.isAccessible();
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(true);
-                                                               }
-                                                               IpAddress retValue = (IpAddress) m.invoke(fromObj);
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(isAccessible);
-                                                               }
-
-                                                               if (retValue != null) {
-                                                                       propVal = new String(retValue.getValue());
-                                                                       LOG.debug("Setting property " + propName
-                                                                                       + " to " + propVal);
-                                                                       props.setProperty(propName, propVal);
-
-                                                               }
-                                                       } catch (Exception e) {
-                                                               LOG.error(
-                                                                               "Caught exception trying to convert value returned by "
-                                                                                               + fromClass.getName() + "."
-                                                                                               + m.getName()
-                                                                                               + "() to Properties entry", e);
-                                                       }
-                                               } else if (isIpPrefix(returnType)) {
-                                                       // Save its value
-                                                       try {
-                                                               String propName = propNamePfx + "." + fieldName;
-                                                               boolean isAccessible = m.isAccessible();
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(true);
-                                                               }
-                                                               IpPrefix retValue = (IpPrefix) m.invoke(fromObj);
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(isAccessible);
-                                                               }
-
-                                                               if (retValue != null) {
-                                                                       propVal = new String(retValue.getValue());
-                                                                       LOG.debug("Setting property " + propName
-                                                                                       + " to " + propVal);
-                                                                       props.setProperty(propName, propVal);
-
-                                                               }
-                                                       } catch (Exception e) {
-                                                               LOG.error(
-                                                                               "Caught exception trying to convert value returned by "
-                                                                                               + fromClass.getName() + "."
-                                                                                               + m.getName()
-                                                                                               + "() to Properties entry", e);
-                                                       }
-                                               } else {
-                                                       try {
-                                                               boolean isAccessible = m.isAccessible();
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(true);
-                                                               }
-                                                               Object retValue = m.invoke(fromObj);
-                                                               
-                                                               if (retValue instanceof byte[]) {
-                                                                       LOG.trace(m.getName()+" returns a byte[]");
-                                                                       retValue = new String((byte[]) retValue, "UTF-8");
-                                                                       LOG.trace("Converted byte array "+propNamePfx+"."+fieldName+"to string "+ retValue );
-                                                               }
-                                                               if (!isAccessible) {
-                                                                       m.setAccessible(isAccessible);
-                                                               }
-                                                               if (retValue != null) {
-                                                                       toProperties(props, propNamePfx + "." + fieldName, retValue, returnType);
-                                                               }
-                                                       } catch (Exception e) {
-                                                               
-                                                               if (m.getName().equals("getKey")) {
-                                                                       LOG.trace("Caught "+e.getClass().getName()+" exception trying to convert results from getKey() - ignoring");
-                                                               } else {
-                                                                       LOG.error(
-                                                                                       "Caught exception trying to convert Yang-generated class returned by"
-                                                                                                       + fromClass.getName() + "."
-                                                                                                       + m.getName()
-                                                                                                       + "() to Properties entry", e);
-                                                               }
-                                                       }
-                                               }
-                                       } else if (returnType.equals(Class.class)) {
+                               if (retValue != null) {
+                                   propVal = retValue.getValue().toString();
+                                   LOG.debug("Setting property " + propName + " to " + propVal);
+                                   props.setProperty(propName, propVal);
 
-                                               LOG.trace(m.getName()
-                                                               + " returns a Class object - not interested");
+                               }
+                           } catch (Exception e) {
+                               LOG.error("Caught exception trying to convert value returned by " + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                           }
+                       } else if (isIpv6Address(returnType)) {
+                           // Save its value
+                           try {
+                               String propName = propNamePfx + "." + fieldName;
+                               boolean isAccessible = m.isAccessible();
+                               if (!isAccessible) {
+                                   m.setAccessible(true);
+                               }
+                               Ipv6Address retValue = (Ipv6Address) m.invoke(fromObj);
+                               if (!isAccessible) {
+                                   m.setAccessible(isAccessible);
+                               }
 
-                                       } else if (List.class.isAssignableFrom(returnType)) {
+                               if (retValue != null) {
+                                   propVal = retValue.getValue().toString();
+                                   LOG.debug("Setting property " + propName + " to " + propVal);
+                                   props.setProperty(propName, propVal);
 
-                                               // This getter method returns a list.
-                                               try {
-                                                       boolean isAccessible = m.isAccessible();
-                                                       if (!isAccessible) {
-                                                               m.setAccessible(true);
-                                                       }
-                                                       Object retList = m.invoke(fromObj);
-                                                       if (!isAccessible) {
-                                                               m.setAccessible(isAccessible);
-                                                       }
-                                                       // Figure out what type of elements are stored in this array.
-                                                       Type paramType = m.getGenericReturnType();
-                                                       Type elementType = ((ParameterizedType) paramType)
-                                                                       .getActualTypeArguments()[0];
-                                                       toProperties(props, propNamePfx + "." + fieldName,
-                                                                       retList, (Class)elementType);
-                                               } catch (Exception e) {
-                                                       LOG.error(
-                                                                       "Caught exception trying to convert List returned by "
-                                                                                       + fromClass.getName() + "."
-                                                                                       + m.getName()
-                                                                                       + "() to Properties entry", e);
-                                               }
+                               }
+                           } catch (Exception e) {
+                               LOG.error("Caught exception trying to convert value returned by " + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                           }
+                       } else if (isIpAddress(returnType)) {
+                           // Save its value
+                           try {
+                               String propName = propNamePfx + "." + fieldName;
+                               boolean isAccessible = m.isAccessible();
+                               if (!isAccessible) {
+                                   m.setAccessible(true);
+                               }
+                               IpAddress retValue = (IpAddress) m.invoke(fromObj);
+                               if (!isAccessible) {
+                                   m.setAccessible(isAccessible);
+                               }
 
-                                       } else {
+                               if (retValue != null) {
+                                   propVal = new String(retValue.getValue());
+                                   LOG.debug("Setting property " + propName + " to " + propVal);
+                                   props.setProperty(propName, propVal);
 
-                                               // Method returns something that is not a List and not
-                                               // yang-generated.
-                                               // Save its value
-                                               try {
-                                                       String propName = propNamePfx + "." + fieldName;
-                                                       boolean isAccessible = m.isAccessible();
-                                                       if (!isAccessible) {
-                                                               m.setAccessible(true);
-                                                       }
-                                                       Object propValObj = m.invoke(fromObj);
-                                                       if (!isAccessible) {
-                                                               m.setAccessible(isAccessible);
-                                                       }
+                               }
+                           } catch (Exception e) {
+                               LOG.error("Caught exception trying to convert value returned by " + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                           }
+                       } else if (isIpPrefix(returnType)) {
+                           // Save its value
+                           try {
+                               String propName = propNamePfx + "." + fieldName;
+                               boolean isAccessible = m.isAccessible();
+                               if (!isAccessible) {
+                                   m.setAccessible(true);
+                               }
+                               IpPrefix retValue = (IpPrefix) m.invoke(fromObj);
+                               if (!isAccessible) {
+                                   m.setAccessible(isAccessible);
+                               }
 
-                                                       if (propValObj != null) {
-                                                               if (propValObj instanceof byte[]) {
-                                                                       LOG.trace(m.getName()+" returns a byte[]");
-                                                                       propVal = new String((byte[]) propValObj, "UTF-8");
-                                                                       LOG.trace("Converted byte array "+propNamePfx+"."+fieldName+"to string "+ propVal );
+                               if (retValue != null) {
+                                   propVal = new String(retValue.getValue());
+                                   LOG.debug("Setting property " + propName + " to " + propVal);
+                                   props.setProperty(propName, propVal);
 
-                                                               } else {
-                                                                       propVal = propValObj.toString();
-                                                               }
-                                                               LOG.debug("Setting property " + propName
-                                                                               + " to " + propVal);
-                                                               props.setProperty(propName, propVal);
+                               }
+                           } catch (Exception e) {
+                               LOG.error("Caught exception trying to convert value returned by " + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                           }
+                       } else {
+                           try {
+                               boolean isAccessible = m.isAccessible();
+                               if (!isAccessible) {
+                                   m.setAccessible(true);
+                               }
+                               Object retValue = m.invoke(fromObj);
 
-                                                       }
-                                               } catch (Exception e) {
-                                                       if (m.getName().equals("getKey")) {
-                                                               LOG.trace("Caught "+e.getClass().getName()+" exception trying to convert results from getKey() - ignoring");
-                                                       } else {
-                                                               LOG.error(
-                                                                               "Caught exception trying to convert value returned by"
-                                                                                               + fromClass.getName() + "."
-                                                                                               + m.getName()
-                                                                                               + "() to Properties entry", e);
-                                                       }
-                                               }
-                                       }
+                               if (retValue instanceof byte[]) {
+                                   LOG.trace(m.getName() + " returns a byte[]");
+                                   retValue = new String((byte[]) retValue, "UTF-8");
+                                   LOG.trace("Converted byte array " + propNamePfx + "." + fieldName + "to string " + retValue);
+                               }
+                               if (!isAccessible) {
+                                   m.setAccessible(isAccessible);
+                               }
+                               if (retValue != null) {
+                                   toProperties(props, propNamePfx + "." + fieldName, retValue, returnType);
+                               }
+                           } catch (Exception e) {
 
+                               if (m.getName().equals("getKey")) {
+                                   LOG.trace("Caught " + e.getClass().getName() + " exception trying to convert results from getKey() - ignoring");
+                               } else {
+                                   LOG.error("Caught exception trying to convert Yang-generated class returned by" + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
                                }
+                           }
                        }
-                       
-                       // End of method loop.  If there was only one getter, named "getValue", then
-                       // set value identified by "prefix" to that one value.
-                       if ((numGetters == 1) && ("getValue".equals(lastGetterName))) {
-                               LOG.trace("getValueFIX : "+ propNamePfx+" only has getValue() getter - setting "+propNamePfx+" = "+propVal);
-                               props.setProperty(propNamePfx, propVal);
-                       } else {
-                               LOG.trace("getValueFIX : " + propNamePfx+" has "+numGetters+" getter(s), last one found was "+lastGetterName);
-                               
+                   } else if (returnType.equals(Class.class)) {
+
+                       LOG.trace(m.getName() + " returns a Class object - not interested");
+
+                   } else if (List.class.isAssignableFrom(returnType)) {
+
+                       // This getter method returns a list.
+                       try {
+                           boolean isAccessible = m.isAccessible();
+                           if (!isAccessible) {
+                               m.setAccessible(true);
+                           }
+                           Object retList = m.invoke(fromObj);
+                           if (!isAccessible) {
+                               m.setAccessible(isAccessible);
+                           }
+                           // Figure out what type of elements are stored in
+                           // this array.
+                           Type paramType = m.getGenericReturnType();
+                           Type elementType = ((ParameterizedType) paramType).getActualTypeArguments()[0];
+                           toProperties(props, propNamePfx + "." + fieldName, retList, (Class) elementType);
+                       } catch (Exception e) {
+                           LOG.error("Caught exception trying to convert List returned by " + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
                        }
 
-               } else {
-                       // Class is not yang generated and not a list
-                       // It must be an element of a leaf list - set "prefix" to value
-                       String fromVal = null;
-                       if (fromObj instanceof byte[]) {
-                               try {
-                               fromVal = new String((byte[]) fromObj, "UTF-8");
-                               LOG.trace("Converted byte array "+pfx+"to string "+ fromVal );
-                               } catch (Exception e) {
-                                       LOG.warn("Caught exception trying to convert "+pfx+" from byte[] to String", e);
-                                       fromVal = fromObj.toString();
+                   } else {
+
+                       // Method returns something that is not a List and not
+                       // yang-generated.
+                       // Save its value
+                       try {
+                           String propName = propNamePfx + "." + fieldName;
+                           boolean isAccessible = m.isAccessible();
+                           if (!isAccessible) {
+                               m.setAccessible(true);
+                           }
+                           Object propValObj = m.invoke(fromObj);
+                           if (!isAccessible) {
+                               m.setAccessible(isAccessible);
+                           }
+
+                           if (propValObj != null) {
+                               if (propValObj instanceof byte[]) {
+                                   LOG.trace(m.getName() + " returns a byte[]");
+                                   propVal = new String((byte[]) propValObj, "UTF-8");
+                                   LOG.trace("Converted byte array " + propNamePfx + "." + fieldName + "to string " + propVal);
+
+                               } else {
+                                   propVal = propValObj.toString();
                                }
+                               LOG.debug("Setting property " + propName + " to " + propVal);
+                               props.setProperty(propName, propVal);
 
-                       } else {
-                               fromVal = fromObj.toString();
+                           }
+                       } catch (Exception e) {
+                           if (m.getName().equals("getKey")) {
+                               LOG.trace("Caught " + e.getClass().getName() + " exception trying to convert results from getKey() - ignoring");
+                           } else {
+                               LOG.error("Caught exception trying to convert value returned by" + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                           }
                        }
-                       LOG.debug("Setting property " + pfx
-                                       + " to " + fromVal);
-                       props.setProperty(pfx, fromVal);
+                   }
+
+               }
+           }
+
+           // End of method loop. If there was only one getter, named
+           // "getValue", then
+           // set value identified by "prefix" to that one value.
+           if ((numGetters == 1) && ("getValue".equals(lastGetterName))) {
+               LOG.trace("getValueFIX : " + propNamePfx + " only has getValue() getter - setting " + propNamePfx + " = " + propVal);
+               props.setProperty(propNamePfx, propVal);
+           } else {
+               LOG.trace("getValueFIX : " + propNamePfx + " has " + numGetters + " getter(s), last one found was " + lastGetterName);
+
+           }
+
+       } else {
+           // Class is not yang generated and not a list
+           // It must be an element of a leaf list - set "prefix" to value
+           String fromVal = null;
+           if (fromObj instanceof byte[]) {
+               try {
+                   fromVal = new String((byte[]) fromObj, "UTF-8");
+                   LOG.trace("Converted byte array " + pfx + "to string " + fromVal);
+               } catch (Exception e) {
+                   LOG.warn("Caught exception trying to convert " + pfx + " from byte[] to String", e);
+                   fromVal = fromObj.toString();
                }
 
-               return (props);
+           } else {
+               fromVal = fromObj.toString();
+           }
+           LOG.debug("Setting property " + pfx + " to " + fromVal);
+           props.setProperty(pfx, fromVal);
        }
 
-       public static Object toBuilder(Properties props, Object toObj) {
+       return (props);
+    }
 
-               return (toBuilder(props, "", toObj));
-       }
+    public static Object toBuilder(Properties props, Object toObj) {
 
-       public static List toList(Properties props, String pfx, List toObj,
-                       Class elemType) {
+       return (toBuilder(props, "", toObj));
+    }
 
-               int maxIdx = -1;
-               boolean foundValue = false;
+    public static List toList(Properties props, String pfx, List toObj, Class elemType) {
 
-               LOG.trace("Saving properties to List<" + elemType.getName()
-                               + ">  from " + pfx);
+       int maxIdx = -1;
+       boolean foundValue = false;
 
-               if (props.contains(pfx+"_length")) {
-                       try {
-                               int listLength = Integer.parseInt(props.getProperty(pfx+"_length"));
-                               
-                               if (listLength > 0) {
-                                       maxIdx = listLength - 1;
-                               }
-                       } catch (Exception e) {
-                               // Ignore exception
+       LOG.trace("Saving properties to List<" + elemType.getName() + ">  from " + pfx);
+
+       if (props.contains(pfx + "_length")) {
+           try {
+               int listLength = Integer.parseInt(props.getProperty(pfx + "_length"));
+
+               if (listLength > 0) {
+                   maxIdx = listLength - 1;
+               }
+           } catch (Exception e) {
+               // Ignore exception
+           }
+       }
+
+       if (maxIdx == -1) {
+           // Figure out array size
+           for (Object pNameObj : props.keySet()) {
+               String key = (String) pNameObj;
+
+               if (key.startsWith(pfx + "[")) {
+                   String idxStr = key.substring(pfx.length() + 1);
+                   int endloc = idxStr.indexOf("]");
+                   if (endloc != -1) {
+                       idxStr = idxStr.substring(0, endloc);
+                   }
+
+                   try {
+                       int curIdx = Integer.parseInt(idxStr);
+                       if (curIdx > maxIdx) {
+                           maxIdx = curIdx;
                        }
+                   } catch (Exception e) {
+                       LOG.error("Illegal subscript in property " + key);
+                   }
+
                }
-               
-               if (maxIdx == -1) {
-                       // Figure out array size
-                       for (Object pNameObj : props.keySet()) {
-                               String key = (String) pNameObj;
-
-                               if (key.startsWith(pfx + "[")) {
-                                       String idxStr = key.substring(pfx.length() + 1);
-                                       int endloc = idxStr.indexOf("]");
-                                       if (endloc != -1) {
-                                               idxStr = idxStr.substring(0, endloc);
-                                       }
+           }
+       }
 
-                                       try {
-                                               int curIdx = Integer.parseInt(idxStr);
-                                               if (curIdx > maxIdx) {
-                                                       maxIdx = curIdx;
-                                               }
-                                       } catch (Exception e) {
-                                               LOG.error("Illegal subscript in property " + key);
-                                       }
+       LOG.trace(pfx + " has max index of " + maxIdx);
+       for (int i = 0; i <= maxIdx; i++) {
+
+           String curBase = pfx + "[" + i + "]";
+
+           if (isYangGenerated(elemType)) {
+               String builderName = elemType.getName() + "Builder";
+               try {
+                   Class builderClass = Class.forName(builderName);
+                   Object builderObj = builderClass.newInstance();
+                   Method buildMethod = builderClass.getMethod("build");
+                   builderObj = toBuilder(props, curBase, builderObj, true);
+                   if (builderObj != null) {
+                       LOG.trace("Calling " + builderObj.getClass().getName() + "." + buildMethod.getName() + "()");
+                       Object builtObj = buildMethod.invoke(builderObj);
+                       toObj.add(builtObj);
+                       foundValue = true;
+                   }
+
+               } catch (ClassNotFoundException e) {
+                   LOG.warn("Could not find builder class " + builderName, e);
+               } catch (Exception e) {
+                   LOG.error("Caught exception trying to populate list from " + pfx);
+               }
+           } else {
+               // Must be a leaf list
+               String curValue = props.getProperty(curBase, "");
 
-                               }
-                       }
+               toObj.add(curValue);
+
+               if ((curValue != null) && (curValue.length() > 0)) {
+                   foundValue = true;
                }
-               
+           }
 
-               LOG.trace(pfx + " has max index of " + maxIdx);
-               for (int i = 0; i <= maxIdx; i++) {
+       }
 
-                       String curBase = pfx + "[" + i + "]";
+       if (foundValue) {
+           return (toObj);
+       } else {
+           return (null);
+       }
 
-                       if (isYangGenerated(elemType)) {
-                               String builderName = elemType.getName() + "Builder";
-                               try {
-                                       Class builderClass = Class.forName(builderName);
-                                       Object builderObj = builderClass.newInstance();
-                                       Method buildMethod = builderClass.getMethod("build");
-                                       builderObj = toBuilder(props, curBase, builderObj, true);
-                                       if (builderObj != null) {
-                                               LOG.trace("Calling " + builderObj.getClass().getName()
-                                                               + "." + buildMethod.getName() + "()");
-                                               Object builtObj = buildMethod.invoke(builderObj);
-                                               toObj.add(builtObj);
-                                               foundValue = true;
-                                       }
+    }
 
-                               } catch (ClassNotFoundException e) {
-                                       LOG.warn("Could not find builder class " + builderName, e);
-                               } catch (Exception e) {
-                                       LOG.error("Caught exception trying to populate list from "
-                                                       + pfx);
-                               }
-                       } else {
-                               // Must be a leaf list
-                               String curValue = props.getProperty(curBase, "");
-                               
-                               toObj.add(curValue);
-                               
-                               if ((curValue != null) && (curValue.length() > 0)) {
-                                       foundValue = true;
-                               }
-                       }
+    public static Object toBuilder(Properties props, String pfx, Object toObj) {
+       return (toBuilder(props, pfx, toObj, false));
+    }
 
-               }
+    public static Object toBuilder(Properties props, String pfx, Object toObj, boolean preservePfx) {
+       Class toClass = toObj.getClass();
+       boolean foundValue = false;
+
+       LOG.trace("Saving properties to " + toClass.getName() + " class from " + pfx);
+
+       Ipv4Address addr;
+
+       if (isYangGenerated(toClass)) {
+           // Class is yang generated.
+           LOG.trace(toClass.getName() + " is a Yang-generated class");
 
-               if (foundValue) {
-                       return (toObj);
+           String propNamePfx = null;
+           if (preservePfx) {
+               propNamePfx = pfx;
+           } else {
+
+               if ((pfx != null) && (pfx.length() > 0)) {
+                   propNamePfx = pfx + "." + toLowerHyphen(toClass.getSimpleName());
                } else {
-                       return (null);
+                   propNamePfx = toLowerHyphen(toClass.getSimpleName());
                }
 
-       }
-       
-       public static Object toBuilder(Properties props, String pfx, Object toObj) {
-               return(toBuilder(props, pfx, toObj, false));
-       }
+               if (propNamePfx.endsWith("-builder")) {
+                   propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-builder".length());
+               }
 
-       public static Object toBuilder(Properties props, String pfx, Object toObj, boolean preservePfx) {
-               Class toClass = toObj.getClass();
-               boolean foundValue = false;
+               if (propNamePfx.endsWith("-impl")) {
+                   propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-impl".length());
+               }
+           }
 
-               LOG.trace("Saving properties to " + toClass.getName() + " class from "
-                               + pfx);
+           if (toObj instanceof Identifier) {
+               LOG.trace(toClass.getName() + " is a Key - skipping");
+               return (toObj);
+           }
 
-               Ipv4Address addr;
+           // Iterate through getter methods to figure out values we need to
+           // set
 
-               if (isYangGenerated(toClass)) {
-                       // Class is yang generated.
-                       LOG.trace(toClass.getName() + " is a Yang-generated class");
+           for (Method m : toClass.getMethods()) {
+               if (isSetter(m)) {
+                   Class paramTypes[] = m.getParameterTypes();
+                   Class paramClass = paramTypes[0];
 
-                       String propNamePfx = null;
-                       if (preservePfx) {
-                               propNamePfx = pfx;
-                       } else {
+                   String fieldName = toLowerHyphen(m.getName().substring(3));
+                   fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
 
-                               if ((pfx != null) && (pfx.length() > 0)) {
-                                       propNamePfx = pfx + "."
-                                                       + toLowerHyphen(toClass.getSimpleName());
-                               } else {
-                                       propNamePfx = toLowerHyphen(toClass.getSimpleName());
-                               }
+                   String propName = propNamePfx + "." + fieldName;
 
-                               if (propNamePfx.endsWith("-builder")) {
-                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
-                                                       - "-builder".length());
-                               }
+                   String paramValue = props.getProperty(propName);
+                   if (paramValue == null) {
+                       LOG.trace(propName + " is unset");
+                   } else {
+                       LOG.trace(propName + " = " + paramValue);
+                   }
 
-                               if (propNamePfx.endsWith("-impl")) {
-                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
-                                                       - "-impl".length());
+                   // Is the return type a yang generated class?
+                   if (isYangGenerated(paramClass)) {
+                       // Is it an enum?
+                       if (paramClass.isEnum()) {
+
+                           LOG.trace(m.getName() + " expects an Enum");
+                           // Param type is a typedef.
+                           if ((paramValue != null) && (paramValue.length() > 0)) {
+                               Object paramObj = null;
+
+                               try {
+                                   paramObj = Enum.valueOf(paramClass, toJavaEnum(paramValue));
+                               } catch (Exception e) {
+                                   LOG.error("Caught exception trying to convert field " + propName + " to enum " + paramClass.getName(), e);
                                }
-                       }
 
-                       if (toObj instanceof Identifier) {
-                               LOG.trace(toClass.getName() + " is a Key - skipping");
-                               return (toObj);
-                       }
+                               try {
+                                   boolean isAccessible = m.isAccessible();
+                                   if (!isAccessible) {
+                                       m.setAccessible(true);
+                                   }
+
+                                   LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(" + paramValue + ")");
+                                   m.invoke(toObj, paramObj);
 
-                       // Iterate through getter methods to figure out values we need to
-                       // set
+                                   if (!isAccessible) {
+                                       m.setAccessible(isAccessible);
+                                   }
+                                   foundValue = true;
 
-                       for (Method m : toClass.getMethods()) {
-                               if (isSetter(m)) {
-                                       Class paramTypes[] = m.getParameterTypes();
-                                       Class paramClass = paramTypes[0];
+                               } catch (Exception e) {
+                                   LOG.error("Caught exception trying to create Yang-generated enum expected by" + toClass.getName() + "." + m.getName() + "() from Properties entry", e);
+                               }
+                           }
+                       } else {
+
+                           String simpleName = paramClass.getSimpleName();
+
+                           if ("Ipv4Address".equals(simpleName) || "Ipv6Address".equals(simpleName) || "IpAddress".equals(simpleName)) {
 
-                                       String fieldName = toLowerHyphen(m.getName().substring(3));
-                                       fieldName = fieldName.substring(0, 1).toLowerCase()
-                                                       + fieldName.substring(1);
+                               if ((paramValue != null) && (paramValue.length() > 0)) {
+                                   try {
+                                       IpAddress ipAddr = IpAddressBuilder.getDefaultInstance(paramValue);
 
-                                       String propName = propNamePfx + "." + fieldName;
+                                       if ("Ipv4Address".equals(simpleName)) {
+                                           m.invoke(toObj, ipAddr.getIpv4Address());
+                                       } else if ("Ipv6Address".equals(simpleName)) {
+                                           m.invoke(toObj, ipAddr.getIpv6Address());
 
-                                       String paramValue = props.getProperty(propName);
-                                       if (paramValue == null) {
-                                               LOG.trace(propName + " is unset");
                                        } else {
-                                               LOG.trace(propName + " = " + paramValue);
+                                           m.invoke(toObj, ipAddr);
                                        }
+                                       foundValue = true;
+                                   } catch (Exception e) {
+                                       LOG.error("Caught exception calling " + toClass.getName() + "." + m.getName() + "(" + paramValue + ")", e);
 
-                                       // Is the return type a yang generated class?
-                                       if (isYangGenerated(paramClass)) {
-                                               // Is it an enum?
-                                               if (paramClass.isEnum()) {
-
-                                                       LOG.trace(m.getName() + " expects an Enum");
-                                                       // Param type is a typedef.
-                                                       if ((paramValue != null)  && (paramValue.length() > 0)) {
-                                                               Object paramObj = null;
-
-                                                               try {
-                                                                       paramObj = Enum.valueOf(paramClass,
-                                                                                       toUpperCamelCase(paramValue));
-                                                               } catch (Exception e) {
-                                                                       LOG.error(
-                                                                                       "Caught exception trying to convert field "
-                                                                                                       + propName + " to enum "
-                                                                                                       + paramClass.getName(), e);
-                                                               }
-
-                                                               try {
-                                                                       boolean isAccessible = m.isAccessible();
-                                                                       if (!isAccessible) {
-                                                                               m.setAccessible(true);
-                                                                       }
-
-                                                                       LOG.trace("Calling "
-                                                                                       + toObj.getClass().getName() + "."
-                                                                                       + m.getName() + "(" + paramValue
-                                                                                       + ")");
-                                                                       m.invoke(toObj, paramObj);
-
-                                                                       if (!isAccessible) {
-                                                                               m.setAccessible(isAccessible);
-                                                                       }
-                                                                       foundValue = true;
-
-                                                               } catch (Exception e) {
-                                                                       LOG.error(
-                                                                                       "Caught exception trying to create Yang-generated enum expected by"
-                                                                                                       + toClass.getName()
-                                                                                                       + "."
-                                                                                                       + m.getName()
-                                                                                                       + "() from Properties entry",
-                                                                                       e);
-                                                               }
-                                                       }
-                                               } else {
-
-                                                       String simpleName = paramClass.getSimpleName();
-
-                                                       if ("Ipv4Address".equals(simpleName)
-                                                                       || "Ipv6Address".equals(simpleName) || "IpAddress".equals(simpleName)) {
-                                                               
-                                                               if ((paramValue != null) && (paramValue.length() > 0)) {
-                                                                       try {
-                                                                               IpAddress ipAddr = IpAddressBuilder
-                                                                                               .getDefaultInstance(paramValue);
-
-
-                                                                               if ("Ipv4Address".equals(simpleName))
-                                                                               {
-                                                                                       m.invoke(toObj, ipAddr.getIpv4Address());
-                                                                               }
-                                                                               else if ("Ipv6Address".equals(simpleName))
-                                                                               {
-                                                                                       m.invoke(toObj, ipAddr.getIpv6Address());
-
-                                                                               }
-                                                                               else
-                                                                               {
-                                                                                       m.invoke(toObj, ipAddr);
-                                                                               }
-                                                                               foundValue = true;
-                                                                       } catch (Exception e) {
-                                                                               LOG.error(
-                                                                                               "Caught exception calling "
-                                                                                                               + toClass.getName() + "."
-                                                                                                               + m.getName() + "("
-                                                                                                               + paramValue + ")", e);
-
-                                                                       }
-                                                               } else {
-                                                                       try {
-                                                                               boolean isAccessible = m.isAccessible();
-                                                                               if (!isAccessible) {
-                                                                                       m.setAccessible(true);
-                                                                               }
-                                                                               LOG.trace("Calling "
-                                                                                               + toObj.getClass().getName()
-                                                                                               + "." + m.getName() + "("
-                                                                                               + paramValue + ")");
-                                                                               m.invoke(toObj, paramValue);
-                                                                               if (!isAccessible) {
-                                                                                       m.setAccessible(isAccessible);
-                                                                               }
-                                                                               foundValue = true;
-
-                                                                       } catch (Exception e) {
-                                                                               LOG.error(
-                                                                                               "Caught exception trying to call "
-                                                                                                               + toClass.getName()
-                                                                                                               + "."
-                                                                                                               + m.getName()
-                                                                                                               + "() with Properties entry",
-                                                                                               e);
-                                                                       }
-                                                               }
-                                                       } else if ("IpPrefix".equals(simpleName)) {
-                                                                       if ((paramValue != null) && (paramValue.length() > 0)) {
-                                                                               try {
-                                                                                       IpPrefix ipPrefix = IpPrefixBuilder.getDefaultInstance(paramValue);
-                                                                                       m.invoke(toObj, ipPrefix);
-                                                                                       foundValue = true;
-                                                                               } catch (Exception e) {
-                                                                                       LOG.error(
-                                                                                                       "Caught exception calling "
-                                                                                                                       + toClass.getName() + "."
-                                                                                                                       + m.getName() + "("
-                                                                                                                       + paramValue + ")", e);
-                                                                               }
-                                                                       }
-                                                       } else {
-                                                               // setter expects a yang-generated class. Need
-                                                               // to
-                                                               // create a builder to set it.
-
-                                                               String builderName = paramClass.getName()
-                                                                               + "Builder";
-                                                               Class builderClass = null;
-                                                               Object builderObj = null;
-                                                               Object paramObj = null;
-
-                                                               Object constObj = null;
-                                                               
-                                                               LOG.trace(m.getName()
-                                                                               + " expects a yang-generated class - looking for builder "
-                                                                               + builderName);
-                                                               try {
-                                                                       builderClass = Class.forName(builderName);
-                                                                       builderObj = builderClass.newInstance();
-                                                                       paramObj = toBuilder(props, propNamePfx,
-                                                                                       builderObj);
-                                                               } catch (ClassNotFoundException e) {
-                                                                       
-                                                                       if (paramValue == null) {
-                                                                               try {
-                                                                                       boolean isAccessible = m
-                                                                                                       .isAccessible();
-                                                                                       if (!isAccessible) {
-                                                                                               m.setAccessible(true);
-                                                                                       }
-                                                                                       LOG.trace("Calling "
-                                                                                                       + toObj.getClass()
-                                                                                                                       .getName() + "."
-                                                                                                       + m.getName() + "(null)");
-                                                                                       m.invoke(toObj, new Object[]{null});
-                                                                                       if (!isAccessible) {
-                                                                                               m.setAccessible(isAccessible);
-                                                                                       }
-                                                                                       foundValue = true;
-
-                                                                               } catch (Exception e1) {
-                                                                                       LOG.error(
-                                                                                                       "Caught exception trying to cally"
-                                                                                                                       + toClass.getName()
-                                                                                                                       + "."
-                                                                                                                       + m.getName()
-                                                                                                                       + "() with Properties entry",
-                                                                                                       e1);
-                                                                               }
-                                                                       } else {
-                                                                               try {
-                                                                                       // See if I can find a constructor I
-                                                                                       // can
-                                                                                       // use
-                                                                                       Constructor[] constructors = paramClass
-                                                                                                       .getConstructors();
-                                                                                       // Is there a String constructor?
-                                                                                       for (Constructor c : constructors) {
-                                                                                               Class[] cParms = c
-                                                                                                               .getParameterTypes();
-                                                                                               if ((cParms != null)
-                                                                                                               && (cParms.length == 1)) {
-                                                                                                       if (String.class
-                                                                                                                       .isAssignableFrom(cParms[0])) {
-                                                                                                               constObj = c
-                                                                                                                               .newInstance(paramValue);
-                                                                                                       }
-                                                                                               }
-                                                                                       }
-
-                                                                                       if (constObj == null) {
-                                                                                               // Is there a Long constructor?
-                                                                                               for (Constructor c : constructors) {
-                                                                                                       Class[] cParms = c
-                                                                                                                       .getParameterTypes();
-                                                                                                       if ((cParms != null)
-                                                                                                                       && (cParms.length == 1)) {
-                                                                                                               if (Long.class
-                                                                                                                               .isAssignableFrom(cParms[0])) {
-                                                                                                                       constObj = c
-                                                                                                                                       .newInstance(Long
-                                                                                                                                                       .parseLong(paramValue));
-                                                                                                               }
-                                                                                                       }
-                                                                                               }
-
-                                                                                       }
-
-                                                                                       if (constObj == null) {
-
-                                                                                               // Last chance - see if
-                                                                                               // parameter class has a static
-                                                                                               // method
-                                                                                               // getDefaultInstance(String)
-                                                                                               try {
-                                                                                                       Method gm = paramClass
-                                                                                                                       .getMethod(
-                                                                                                                                       "getDefaultInstance",
-                                                                                                                                       String.class);
-
-                                                                                                       int gmodifier = gm
-                                                                                                                       .getModifiers();
-                                                                                                       if (Modifier
-                                                                                                                       .isStatic(gmodifier)) {
-                                                                                                               // Invoke static
-                                                                                                               // getDefaultInstance(String)
-                                                                                                               paramObj = gm.invoke(
-                                                                                                                               null,
-                                                                                                                               paramValue);
-                                                                                                       }
-
-                                                                                               } catch (Exception gme) {
-                                                                                                       // Ignore exceptions
-                                                                                               }
-                                                                                       }
-                                                                                       
-                                                                                       
-                                                                               } catch (Exception e1) {
-                                                                                       LOG.warn(
-                                                                                                       "Could not find a suitable constructor for "
-                                                                                                                       + paramClass
-                                                                                                                                       .getName(),
-                                                                                                       e1);
-                                                                               }
-
-                                                                               if (constObj == null) {
-                                                                                       LOG.warn("Could not find builder class "
-                                                                                                       + builderName
-                                                                                                       + " and could not find a String or Long constructor or static getDefaultInstance(String) - trying just to set passing paramValue");
-
-                                                                               }
-                                                                       }
-                                                               } catch (Exception e) {
-                                                                       LOG.error(
-                                                                                       "Caught exception trying to create builder "
-                                                                                                       + builderName, e);
-                                                               }
-
-                                                               if (paramObj != null) {
-
-                                                                       try {
-
-                                                                               Method buildMethod = builderClass
-                                                                                               .getMethod("build");
-                                                                               LOG.trace("Calling "
-                                                                                               + paramObj.getClass().getName()
-                                                                                               + "." + buildMethod.getName()
-                                                                                               + "()");
-                                                                               Object builtObj = buildMethod
-                                                                                               .invoke(paramObj);
-
-                                                                               boolean isAccessible = m.isAccessible();
-                                                                               if (!isAccessible) {
-                                                                                       m.setAccessible(true);
-                                                                               }
-
-                                                                               LOG.trace("Calling "
-                                                                                               + toObj.getClass().getName()
-                                                                                               + "." + m.getName() + "()");
-                                                                               m.invoke(toObj, builtObj);
-                                                                               if (!isAccessible) {
-                                                                                       m.setAccessible(isAccessible);
-                                                                               }
-                                                                               foundValue = true;
-
-                                                                       } catch (Exception e) {
-                                                                               LOG.error(
-                                                                                               "Caught exception trying to set Yang-generated class expected by"
-                                                                                                               + toClass.getName()
-                                                                                                               + "."
-                                                                                                               + m.getName()
-                                                                                                               + "() from Properties entry",
-                                                                                               e);
-                                                                       }
-                                                               } else {
-                                                                       try {
-                                                                               boolean isAccessible = m.isAccessible();
-                                                                               if (!isAccessible) {
-                                                                                       m.setAccessible(true);
-                                                                               }
-                                                                               
-                                                                               if (constObj != null) {
-
-                                                                                       LOG.trace("Calling "
-                                                                                                       + toObj.getClass()
-                                                                                                                       .getName() + "."
-                                                                                                       + m.getName() + "("
-                                                                                                       + constObj.toString() + ")");
-                                                                                       m.invoke(toObj, constObj);
-                                                                               } else {
-                                                                                       LOG.trace("Calling "
-                                                                                                       + toObj.getClass()
-                                                                                                                       .getName() + "."
-                                                                                                       + m.getName() + "("
-                                                                                                       + paramValue + ")");
-                                                                                       m.invoke(toObj, paramValue);
-
-                                                                               }
-                                                                               if (!isAccessible) {
-                                                                                       m.setAccessible(isAccessible);
-                                                                               }
-                                                                               foundValue = true;
-
-                                                                       } catch (Exception e) {
-                                                                               LOG.error(
-                                                                                               "Caught exception trying to convert value returned by"
-                                                                                                               + toClass.getName()
-                                                                                                               + "."
-                                                                                                               + m.getName()
-                                                                                                               + "() to Properties entry",
-                                                                                               e);
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       } else {
+                                   }
+                               } else {
+                                   try {
+                                       boolean isAccessible = m.isAccessible();
+                                       if (!isAccessible) {
+                                           m.setAccessible(true);
+                                       }
+                                       LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(" + paramValue + ")");
+                                       m.invoke(toObj, paramValue);
+                                       if (!isAccessible) {
+                                           m.setAccessible(isAccessible);
+                                       }
+                                       foundValue = true;
 
-                                               // Setter's argument is not a yang-generated class. See
-                                               // if it is a List.
+                                   } catch (Exception e) {
+                                       LOG.error("Caught exception trying to call " + toClass.getName() + "." + m.getName() + "() with Properties entry", e);
+                                   }
+                               }
+                           } else if ("IpPrefix".equals(simpleName)) {
+                               if ((paramValue != null) && (paramValue.length() > 0)) {
+                                   try {
+                                       IpPrefix ipPrefix = IpPrefixBuilder.getDefaultInstance(paramValue);
+                                       m.invoke(toObj, ipPrefix);
+                                       foundValue = true;
+                                   } catch (Exception e) {
+                                       LOG.error("Caught exception calling " + toClass.getName() + "." + m.getName() + "(" + paramValue + ")", e);
+                                   }
+                               }
+                           } else {
+                               // setter expects a yang-generated class. Need
+                               // to
+                               // create a builder to set it.
 
-                                               if (List.class.isAssignableFrom(paramClass)) {
+                               String builderName = paramClass.getName() + "Builder";
+                               Class builderClass = null;
+                               Object builderObj = null;
+                               Object paramObj = null;
 
-                                                       LOG.trace("Parameter class " + paramClass.getName()
-                                                                       + " is a List");
+                               Object constObj = null;
 
-                                                       // Figure out what type of args are in List and pass
-                                                       // that to toList().
+                               LOG.trace(m.getName() + " expects a yang-generated class - looking for builder " + builderName);
+                               try {
+                                   builderClass = Class.forName(builderName);
+                                   builderObj = builderClass.newInstance();
+                                   paramObj = toBuilder(props, propNamePfx, builderObj);
+                               } catch (ClassNotFoundException e) {
 
-                                                       Type paramType = m.getGenericParameterTypes()[0];
-                                                       Type elementType = ((ParameterizedType) paramType)
-                                                                       .getActualTypeArguments()[0];
-                                                       Object paramObj = new LinkedList();
-                                                       try {
-                                                               paramObj = toList(props, propName,
-                                                                               (List) paramObj, (Class) elementType);
-                                                       } catch (Exception e) {
-                                                               LOG.error("Caught exception trying to create list expected as argument to "
-                                                                               + toClass.getName() + "." + m.getName());
+                                   if (paramValue == null) {
+                                       try {
+                                           boolean isAccessible = m.isAccessible();
+                                           if (!isAccessible) {
+                                               m.setAccessible(true);
+                                           }
+                                           LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(null)");
+                                           m.invoke(toObj, new Object[] { null });
+                                           if (!isAccessible) {
+                                               m.setAccessible(isAccessible);
+                                           }
+                                           foundValue = true;
+
+                                       } catch (Exception e1) {
+                                           LOG.error("Caught exception trying to cally" + toClass.getName() + "." + m.getName() + "() with Properties entry", e1);
+                                       }
+                                   } else {
+                                       try {
+                                           // See if I can find a constructor I
+                                           // can
+                                           // use
+                                           Constructor[] constructors = paramClass.getConstructors();
+                                           // Is there a String constructor?
+                                           for (Constructor c : constructors) {
+                                               Class[] cParms = c.getParameterTypes();
+                                               if ((cParms != null) && (cParms.length == 1)) {
+                                                   if (String.class.isAssignableFrom(cParms[0])) {
+                                                       constObj = c.newInstance(paramValue);
+                                                   }
+                                               }
+                                           }
+
+                                           if (constObj == null) {
+                                               // Is there a Long constructor?
+                                               for (Constructor c : constructors) {
+                                                   Class[] cParms = c.getParameterTypes();
+                                                   if ((cParms != null) && (cParms.length == 1)) {
+                                                       if (Long.class.isAssignableFrom(cParms[0])) {
+                                                           constObj = c.newInstance(Long.parseLong(paramValue));
                                                        }
+                                                   }
+                                               }
 
-                                                       if (paramObj != null) {
-                                                               try {
-                                                                       boolean isAccessible = m.isAccessible();
-                                                                       if (!isAccessible) {
-                                                                               m.setAccessible(true);
-                                                                       }
-                                                                       LOG.trace("Calling "
-                                                                                       + toObj.getClass().getName() + "."
-                                                                                       + m.getName() + "(" + paramValue
-                                                                                       + ")");
-                                                                       m.invoke(toObj, paramObj);
-                                                                       if (!isAccessible) {
-                                                                               m.setAccessible(isAccessible);
-                                                                       }
-                                                                       foundValue = true;
-
-                                                               } catch (Exception e) {
-                                                                       LOG.error(
-                                                                                       "Caught exception trying to convert List returned by"
-                                                                                                       + toClass.getName() + "."
-                                                                                                       + m.getName()
-                                                                                                       + "() to Properties entry",
-                                                                                       e);
-                                                               }
-                                                       }
-                                               } else {
-
-                                                       // Setter expects something that is not a List and
-                                                       // not yang-generated. Just pass the parameter value
-
-                                                       LOG.trace("Parameter class "
-                                                                       + paramClass.getName()
-                                                                       + " is not a yang-generated class or a List");
-
-                                                       if ((paramValue != null) && (paramValue.length() > 0)) {
-
-                                                               Object constObj = null;
-
-                                                               try {
-                                                                       // See if I can find a constructor I can use
-                                                                       Constructor[] constructors = paramClass
-                                                                                       .getConstructors();
-                                                                       // Is there a String constructor?
-                                                                       for (Constructor c : constructors) {
-                                                                               Class[] cParms = c.getParameterTypes();
-                                                                               if ((cParms != null)
-                                                                                               && (cParms.length == 1)) {
-                                                                                       if (String.class
-                                                                                                       .isAssignableFrom(cParms[0])) {
-                                                                                               constObj = c
-                                                                                                               .newInstance(paramValue);
-                                                                                       }
-                                                                               }
-                                                                       }
-
-                                                                       if (constObj == null) {
-                                                                               // Is there a Long constructor?
-                                                                               for (Constructor c : constructors) {
-                                                                                       Class[] cParms = c
-                                                                                                       .getParameterTypes();
-                                                                                       if ((cParms != null)
-                                                                                                       && (cParms.length == 1)) {
-                                                                                               if (Long.class
-                                                                                                               .isAssignableFrom(cParms[0])) {
-                                                                                                       constObj = c
-                                                                                                                       .newInstance(Long
-                                                                                                                                       .parseLong(paramValue));
-                                                                                               }
-                                                                                       }
-                                                                               }
-
-                                                                       }
-
-                                                                       if (constObj != null) {
-                                                                               try {
-                                                                                       LOG.trace("Calling "
-                                                                                                       + toObj.getClass()
-                                                                                                                       .getName() + "."
-                                                                                                       + m.getName() + "("
-                                                                                                       + constObj + ")");
-                                                                                       m.invoke(toObj, constObj);
-                                                                                       foundValue = true;
-                                                                               } catch (Exception e2) {
-                                                                                       LOG.error(
-                                                                                                       "Caught exception trying to call "
-                                                                                                                       + m.getName(), e2);
-                                                                               }
-                                                                       } else {
-                                                                               try {
-                                                                                       boolean isAccessible = m
-                                                                                                       .isAccessible();
-                                                                                       if (!isAccessible) {
-                                                                                               m.setAccessible(true);
-                                                                                       }
-                                                                                       LOG.trace("Calling "
-                                                                                                       + toObj.getClass()
-                                                                                                                       .getName() + "."
-                                                                                                       + m.getName() + "("
-                                                                                                       + paramValue + ")");
-                                                                                       m.invoke(toObj, paramValue);
-                                                                                       if (!isAccessible) {
-                                                                                               m.setAccessible(isAccessible);
-                                                                                       }
-                                                                                       foundValue = true;
-
-                                                                               } catch (Exception e) {
-                                                                                       LOG.error(
-                                                                                                       "Caught exception trying to convert value returned by"
-                                                                                                                       + toClass.getName()
-                                                                                                                       + "."
-                                                                                                                       + m.getName()
-                                                                                                                       + "() to Properties entry",
-                                                                                                       e);
-                                                                               }
-                                                                       }
-                                                               } catch (Exception e1) {
-                                                                       LOG.warn(
-                                                                                       "Could not find a suitable constructor for "
-                                                                                                       + paramClass.getName(), e1);
-                                                               }
+                                           }
 
+                                           if (constObj == null) {
 
-                                                       }
+                                               // Last chance - see if
+                                               // parameter class has a static
+                                               // method
+                                               // getDefaultInstance(String)
+                                               try {
+                                                   Method gm = paramClass.getMethod("getDefaultInstance", String.class);
+
+                                                   int gmodifier = gm.getModifiers();
+                                                   if (Modifier.isStatic(gmodifier)) {
+                                                       // Invoke static
+                                                       // getDefaultInstance(String)
+                                                       paramObj = gm.invoke(null, paramValue);
+                                                   }
+
+                                               } catch (Exception gme) {
+                                                   // Ignore exceptions
                                                }
+                                           }
+
+                                       } catch (Exception e1) {
+                                           LOG.warn("Could not find a suitable constructor for " + paramClass.getName(), e1);
                                        }
-                               } // End of section handling "setter" method
-                       } // End of loop through Methods
-               } // End of section handling yang-generated class
 
-               if (foundValue) {
-                       return (toObj);
-               } else {
-                       return (null);
-               }
-       }
+                                       if (constObj == null) {
+                                           LOG.warn("Could not find builder class " + builderName + " and could not find a String or Long constructor or static getDefaultInstance(String) - trying just to set passing paramValue");
 
-       public static void printPropertyList(PrintStream pstr, String pfx,
-                       Class toClass) {
-               boolean foundValue = false;
+                                       }
+                                   }
+                               } catch (Exception e) {
+                                   LOG.error("Caught exception trying to create builder " + builderName, e);
+                               }
 
-               LOG.trace("Analyzing " + toClass.getName() + " class : pfx " + pfx);
+                               if (paramObj != null) {
 
-               if (isYangGenerated(toClass)
-                               && (!Identifier.class.isAssignableFrom(toClass))) {
-                       // Class is yang generated.
-                       LOG.trace(toClass.getName() + " is a Yang-generated class");
+                                   try {
 
-                       if (toClass.getName().endsWith("Key")) {
-                               if (Identifier.class.isAssignableFrom(toClass)) {
-                                       LOG.trace(Identifier.class.getName()
-                                                       + " is assignable from " + toClass.getName());
-                               } else {
+                                       Method buildMethod = builderClass.getMethod("build");
+                                       LOG.trace("Calling " + paramObj.getClass().getName() + "." + buildMethod.getName() + "()");
+                                       Object builtObj = buildMethod.invoke(paramObj);
 
-                                       LOG.trace(Identifier.class.getName()
-                                                       + " is NOT assignable from " + toClass.getName());
-                               }
-                       }
+                                       boolean isAccessible = m.isAccessible();
+                                       if (!isAccessible) {
+                                           m.setAccessible(true);
+                                       }
 
-                       String propNamePfx = null;
-                       if (pfx.endsWith("]")) {
-                               propNamePfx = pfx;
-                       } else {
+                                       LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "()");
+                                       m.invoke(toObj, builtObj);
+                                       if (!isAccessible) {
+                                           m.setAccessible(isAccessible);
+                                       }
+                                       foundValue = true;
 
-                               if ((pfx != null) && (pfx.length() > 0)) {
-                                       propNamePfx = pfx + "."
-                                                       + toLowerHyphen(toClass.getSimpleName());
+                                   } catch (Exception e) {
+                                       LOG.error("Caught exception trying to set Yang-generated class expected by" + toClass.getName() + "." + m.getName() + "() from Properties entry", e);
+                                   }
                                } else {
-                                       propNamePfx = toLowerHyphen(toClass.getSimpleName());
-                               }
+                                   try {
+                                       boolean isAccessible = m.isAccessible();
+                                       if (!isAccessible) {
+                                           m.setAccessible(true);
+                                       }
 
-                               if (propNamePfx.endsWith("-builder")) {
-                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
-                                                       - "-builder".length());
-                               }
+                                       if (constObj != null) {
 
-                               if (propNamePfx.endsWith("-impl")) {
-                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
-                                                       - "-impl".length());
+                                           LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(" + constObj.toString() + ")");
+                                           m.invoke(toObj, constObj);
+                                       } else {
+                                           LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(" + paramValue + ")");
+                                           m.invoke(toObj, paramValue);
+
+                                       }
+                                       if (!isAccessible) {
+                                           m.setAccessible(isAccessible);
+                                       }
+                                       foundValue = true;
+
+                                   } catch (Exception e) {
+                                       LOG.error("Caught exception trying to convert value returned by" + toClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                                   }
                                }
+                           }
                        }
+                   } else {
 
-                       // Iterate through getter methods to figure out values we need to
-                       // set
-
-                       for (Method m : toClass.getMethods()) {
-                               LOG.trace("Is " + m.getName() + " method a getter?");
-                               if (isGetter(m)) {
-                                       LOG.trace(m.getName() + " is a getter");
-                                       Class returnClass = m.getReturnType();
-
-                                       String fieldName = toLowerHyphen(m.getName().substring(3));
-                                       fieldName = fieldName.substring(0, 1).toLowerCase()
-                                                       + fieldName.substring(1);
-
-                                       String propName = propNamePfx + "." + fieldName;
-
-                                       // Is the return type a yang generated class?
-                                       if (isYangGenerated(returnClass)) {
-                                               // Is it an enum?
-                                               if (returnClass.isEnum()) {
-
-                                                       LOG.trace(m.getName() + " is an Enum");
-                                                       pstr.print("\n\n     * " + propName);
-
-                                               } else {
-                                                       
-                                                       String simpleName = returnClass.getSimpleName();
-                                                       
-                                                       if ("Ipv4Address".equals(simpleName) || "Ipv6Address".equals(simpleName) || "IpAddress".equals(simpleName) || "IpPrefix".equals(simpleName)) {
-                                                               LOG.trace(m.getName()+" is an "+simpleName);
-                                                               pstr.print("\n\n     * " + propName);
-                                                       } else {
-                                                               printPropertyList(pstr, propNamePfx, returnClass);
-                                                       }
+                       // Setter's argument is not a yang-generated class. See
+                       // if it is a List.
 
-                                               }
-                                       } else {
+                       if (List.class.isAssignableFrom(paramClass)) {
 
-                                               // Setter's argument is not a yang-generated class. See
-                                               // if it is a List.
+                           LOG.trace("Parameter class " + paramClass.getName() + " is a List");
 
-                                               if (List.class.isAssignableFrom(returnClass)) {
+                           // Figure out what type of args are in List and pass
+                           // that to toList().
 
-                                                       LOG.trace("Parameter class "
-                                                                       + returnClass.getName() + " is a List");
+                           Type paramType = m.getGenericParameterTypes()[0];
+                           Type elementType = ((ParameterizedType) paramType).getActualTypeArguments()[0];
+                           Object paramObj = new LinkedList();
+                           try {
+                               paramObj = toList(props, propName, (List) paramObj, (Class) elementType);
+                           } catch (Exception e) {
+                               LOG.error("Caught exception trying to create list expected as argument to " + toClass.getName() + "." + m.getName());
+                           }
 
-                                                       // Figure out what type of args are in List and pass
-                                                       // that to toList().
+                           if (paramObj != null) {
+                               try {
+                                   boolean isAccessible = m.isAccessible();
+                                   if (!isAccessible) {
+                                       m.setAccessible(true);
+                                   }
+                                   LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(" + paramValue + ")");
+                                   m.invoke(toObj, paramObj);
+                                   if (!isAccessible) {
+                                       m.setAccessible(isAccessible);
+                                   }
+                                   foundValue = true;
 
-                                                       Type returnType = m.getGenericReturnType();
-                                                       Type elementType = ((ParameterizedType) returnType)
-                                                                       .getActualTypeArguments()[0];
-                                                       Class elementClass = (Class) elementType;
-                                                       LOG.trace("Calling printPropertyList on list type ("
-                                                                       + elementClass.getName()
-                                                                       + "), pfx is ("
-                                                                       + pfx
-                                                                       + "), toClass is ("
-                                                                       + toClass.getName() + ")");
-                                                       printPropertyList(
-                                                                       pstr,
-                                                                       propNamePfx
-                                                                                       + "."
-                                                                                       + toLowerHyphen(elementClass
-                                                                                                       .getSimpleName()) + "[]",
-                                                                       elementClass);
+                               } catch (Exception e) {
+                                   LOG.error("Caught exception trying to convert List returned by" + toClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                               }
+                           }
+                       } else {
 
-                                               } else if (!returnClass.equals(Class.class)) {
+                           // Setter expects something that is not a List and
+                           // not yang-generated. Just pass the parameter value
 
-                                                       // Setter expects something that is not a List and
-                                                       // not yang-generated. Just pass the parameter value
+                           LOG.trace("Parameter class " + paramClass.getName() + " is not a yang-generated class or a List");
 
-                                                       LOG.trace("Parameter class "
-                                                                       + returnClass.getName()
-                                                                       + " is not a yang-generated class or a List");
+                           if ((paramValue != null) && (paramValue.length() > 0)) {
 
-                                                       pstr.print("\n\n     * " + propName);
+                               Object constObj = null;
 
+                               try {
+                                   // See if I can find a constructor I can use
+                                   Constructor[] constructors = paramClass.getConstructors();
+                                   // Is there a String constructor?
+                                   for (Constructor c : constructors) {
+                                       Class[] cParms = c.getParameterTypes();
+                                       if ((cParms != null) && (cParms.length == 1)) {
+                                           if (String.class.isAssignableFrom(cParms[0])) {
+                                               constObj = c.newInstance(paramValue);
+                                           }
+                                       }
+                                   }
+
+                                   if (constObj == null) {
+                                       // Is there a Long constructor?
+                                       for (Constructor c : constructors) {
+                                           Class[] cParms = c.getParameterTypes();
+                                           if ((cParms != null) && (cParms.length == 1)) {
+                                               if (Long.class.isAssignableFrom(cParms[0])) {
+                                                   constObj = c.newInstance(Long.parseLong(paramValue));
                                                }
+                                           }
                                        }
-                               } // End of section handling "setter" method
-                       } // End of loop through Methods
-               } // End of section handling yang-generated class
 
+                                   }
+
+                                   if (constObj != null) {
+                                       try {
+                                           LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(" + constObj + ")");
+                                           m.invoke(toObj, constObj);
+                                           foundValue = true;
+                                       } catch (Exception e2) {
+                                           LOG.error("Caught exception trying to call " + m.getName(), e2);
+                                       }
+                                   } else {
+                                       try {
+                                           boolean isAccessible = m.isAccessible();
+                                           if (!isAccessible) {
+                                               m.setAccessible(true);
+                                           }
+                                           LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "(" + paramValue + ")");
+                                           m.invoke(toObj, paramValue);
+                                           if (!isAccessible) {
+                                               m.setAccessible(isAccessible);
+                                           }
+                                           foundValue = true;
+
+                                       } catch (Exception e) {
+                                           LOG.error("Caught exception trying to convert value returned by" + toClass.getName() + "." + m.getName() + "() to Properties entry", e);
+                                       }
+                                   }
+                               } catch (Exception e1) {
+                                   LOG.warn("Could not find a suitable constructor for " + paramClass.getName(), e1);
+                               }
+
+                           }
+                       }
+                   }
+               } // End of section handling "setter" method
+           } // End of loop through Methods
+       } // End of section handling yang-generated class
+
+       if (foundValue) {
+           return (toObj);
+       } else {
+           return (null);
        }
+    }
+
+    public static void printPropertyList(PrintStream pstr, String pfx, Class toClass) {
+       boolean foundValue = false;
+
+       LOG.trace("Analyzing " + toClass.getName() + " class : pfx " + pfx);
 
-       public static boolean isYangGenerated(Class c) {
-               if (c == null) {
-                       return (false);
+       if (isYangGenerated(toClass) && (!Identifier.class.isAssignableFrom(toClass))) {
+           // Class is yang generated.
+           LOG.trace(toClass.getName() + " is a Yang-generated class");
+
+           if (toClass.getName().endsWith("Key")) {
+               if (Identifier.class.isAssignableFrom(toClass)) {
+                   LOG.trace(Identifier.class.getName() + " is assignable from " + toClass.getName());
                } else {
-                       return (c.getName().startsWith("org.opendaylight.yang.gen."));
+
+                   LOG.trace(Identifier.class.getName() + " is NOT assignable from " + toClass.getName());
                }
-       }
-       
-       public static boolean isIpPrefix(Class c) {
-               
-               if (c == null ) {
-                       return (false);
+           }
+
+           String propNamePfx = null;
+           if (pfx.endsWith("]")) {
+               propNamePfx = pfx;
+           } else {
+
+               if ((pfx != null) && (pfx.length() > 0)) {
+                   propNamePfx = pfx + "." + toLowerHyphen(toClass.getSimpleName());
+               } else {
+                   propNamePfx = toLowerHyphen(toClass.getSimpleName());
                }
-               String simpleName = c.getSimpleName();
-               return ("IpPrefix".equals(simpleName)) ;
-       }
-       
-       
-       
-       public static boolean isIpv4Address(Class c) {
-               
-               if (c == null ) {
-                       return (false);
+
+               if (propNamePfx.endsWith("-builder")) {
+                   propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-builder".length());
                }
-               String simpleName = c.getSimpleName();
-               return ("Ipv4Address".equals(simpleName)) ;
+
+               if (propNamePfx.endsWith("-impl")) {
+                   propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-impl".length());
+               }
+           }
+
+           // Iterate through getter methods to figure out values we need to
+           // set
+
+           for (Method m : toClass.getMethods()) {
+               LOG.trace("Is " + m.getName() + " method a getter?");
+               if (isGetter(m)) {
+                   LOG.trace(m.getName() + " is a getter");
+                   Class returnClass = m.getReturnType();
+
+                   String fieldName = toLowerHyphen(m.getName().substring(3));
+                   fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
+
+                   String propName = propNamePfx + "." + fieldName;
+
+                   // Is the return type a yang generated class?
+                   if (isYangGenerated(returnClass)) {
+                       // Is it an enum?
+                       if (returnClass.isEnum()) {
+
+                           LOG.trace(m.getName() + " is an Enum");
+                           pstr.print("\n\n     * " + propName);
+
+                       } else {
+
+                           String simpleName = returnClass.getSimpleName();
+
+                           if ("Ipv4Address".equals(simpleName) || "Ipv6Address".equals(simpleName) || "IpAddress".equals(simpleName) || "IpPrefix".equals(simpleName)) {
+                               LOG.trace(m.getName() + " is an " + simpleName);
+                               pstr.print("\n\n     * " + propName);
+                           } else {
+                               printPropertyList(pstr, propNamePfx, returnClass);
+                           }
+
+                       }
+                   } else {
+
+                       // Setter's argument is not a yang-generated class. See
+                       // if it is a List.
+
+                       if (List.class.isAssignableFrom(returnClass)) {
+
+                           LOG.trace("Parameter class " + returnClass.getName() + " is a List");
+
+                           // Figure out what type of args are in List and pass
+                           // that to toList().
+
+                           Type returnType = m.getGenericReturnType();
+                           Type elementType = ((ParameterizedType) returnType).getActualTypeArguments()[0];
+                           Class elementClass = (Class) elementType;
+                           LOG.trace("Calling printPropertyList on list type (" + elementClass.getName() + "), pfx is (" + pfx + "), toClass is (" + toClass.getName() + ")");
+                           printPropertyList(pstr, propNamePfx + "." + toLowerHyphen(elementClass.getSimpleName()) + "[]", elementClass);
+
+                       } else if (!returnClass.equals(Class.class)) {
+
+                           // Setter expects something that is not a List and
+                           // not yang-generated. Just pass the parameter value
+
+                           LOG.trace("Parameter class " + returnClass.getName() + " is not a yang-generated class or a List");
+
+                           pstr.print("\n\n     * " + propName);
+
+                       }
+                   }
+               } // End of section handling "setter" method
+           } // End of loop through Methods
+       } // End of section handling yang-generated class
+
+    }
+
+    public static boolean isYangGenerated(Class c) {
+       if (c == null) {
+           return (false);
+       } else {
+           return (c.getName().startsWith("org.opendaylight.yang.gen."));
        }
-       
-       public static boolean isIpv6Address(Class c) {
-               
-               if (c == null ) {
-                       return (false);
-               } 
-               String simpleName = c.getSimpleName();
-               return ("Ipv6Address".equals(simpleName)) ;
+    }
+
+    public static boolean isIpPrefix(Class c) {
+
+       if (c == null) {
+           return (false);
        }
-       
-       public static boolean isIpAddress(Class c) {
-               
-               if (c == null ) {
-                       return (false);
-               } 
-               String simpleName = c.getSimpleName();
-               return ("IpAddress".equals(simpleName)) ;
+       String simpleName = c.getSimpleName();
+       return ("IpPrefix".equals(simpleName));
+    }
+
+    public static boolean isIpv4Address(Class c) {
+
+       if (c == null) {
+           return (false);
        }
+       String simpleName = c.getSimpleName();
+       return ("Ipv4Address".equals(simpleName));
+    }
 
-       public static String toLowerHyphen(String inStr) {
-               if (inStr == null) {
-                       return (null);
-               }
+    public static boolean isIpv6Address(Class c) {
 
-               String str = inStr.substring(0, 1).toLowerCase();
-               if (inStr.length() > 1) {
-                       str = str + inStr.substring(1);
-               }
+       if (c == null) {
+           return (false);
+       }
+       String simpleName = c.getSimpleName();
+       return ("Ipv6Address".equals(simpleName));
+    }
+
+    public static boolean isIpAddress(Class c) {
 
-               String regex = "(([a-z0-9])([A-Z]))";
-               String replacement = "$2-$3";
+       if (c == null) {
+           return (false);
+       }
+       String simpleName = c.getSimpleName();
+       return ("IpAddress".equals(simpleName));
+    }
 
-               String retval = str.replaceAll(regex, replacement).toLowerCase();
+    public static String toLowerHyphen(String inStr) {
+       if (inStr == null) {
+           return (null);
+       }
 
-               LOG.trace("Converting " + inStr + " => " + str + " => " + retval);
-               return (retval);
+       String str = inStr.substring(0, 1).toLowerCase();
+       if (inStr.length() > 1) {
+           str = str + inStr.substring(1);
        }
 
-       public static String toUpperCamelCase(String inStr) {
-               if (inStr == null) {
-                       return (null);
-               } else if (inStr.length() == 0) {
-                       return(inStr);
-               }
+       String regex = "(([a-z0-9])([A-Z]))";
+       String replacement = "$2-$3";
 
-               String[] terms = inStr.split("-");
-               StringBuffer sbuff = new StringBuffer();
-               // Check if string begins with a digit
-               if (Character.isDigit(inStr.charAt(0))) {
-                       sbuff.append('_');
-               }
-               for (String term : terms) {
-                       sbuff.append(term.substring(0, 1).toUpperCase());
-                       if (term.length() > 1) {
-                               sbuff.append(term.substring(1));
-                       }
-               }
-               return (sbuff.toString());
+       String retval = str.replaceAll(regex, replacement).toLowerCase();
+
+       LOG.trace("Converting " + inStr + " => " + str + " => " + retval);
+       return (retval);
+    }
 
+    //This is called when mapping the yang value back to a valid java enumeration
+    public static String toJavaEnum(String inStr) {
+       if (inStr == null) {
+           return (null);
+       } else if (inStr.length() == 0) {
+           return (inStr);
        }
 
-       public static boolean isGetter(Method m) {
-               if (m == null) {
-                       return (false);
-               }
+       //This will strip out all periods, which cannot be in a java enum
+    inStr = inStr.replaceAll("\\.", "");
 
-               if (Modifier.isPublic(m.getModifiers())
-                               && (m.getParameterTypes().length == 0)) {
-                       if (m.getName().matches("^get[A-Z].*")
-                                       && !m.getReturnType().equals(void.class)) {
-                               if (!"getClass".equals(m.getName())) {
-                                       return (true);
-                               }
-                       }
+       String[] terms = inStr.split("-");
+       StringBuffer sbuff = new StringBuffer();
 
-                       if (m.getName().matches("^get[A-Z].*")
-                                       && m.getReturnType().equals(boolean.class)) {
-                               return (true);
-                       }
-                       
-                       if (m.getName().matches("^is[A-Z].*")
-                                       && m.getReturnType().equals(Boolean.class)) {
-                               return(true);
-                       }
-               }
+       //appends an _ if the string starts with a digit to make it a valid java enum
+       if (Character.isDigit(inStr.charAt(0))) {
+           sbuff.append('_');
+       }
+       //If the string contains hyphens it will convert the string to upperCamelCase without hyphens
+       for (String term : terms) {
+           sbuff.append(term.substring(0, 1).toUpperCase());
+           if (term.length() > 1) {
+               sbuff.append(term.substring(1));
+           }
+       }
+       return (sbuff.toString());
+
+    }
 
-               return (false);
+    public static boolean isGetter(Method m) {
+       if (m == null) {
+           return (false);
        }
 
-       public static boolean isSetter(Method m) {
-               if (m == null) {
-                       return (false);
+       if (Modifier.isPublic(m.getModifiers()) && (m.getParameterTypes().length == 0)) {
+           if (m.getName().matches("^get[A-Z].*") && !m.getReturnType().equals(void.class)) {
+               if (!"getClass".equals(m.getName())) {
+                   return (true);
                }
+           }
 
-               if (Modifier.isPublic(m.getModifiers())
-                               && (m.getParameterTypes().length == 1)) {
-                       if (m.getName().matches("^set[A-Z].*")) {
-                               Class[] paramTypes = m.getParameterTypes();
-                               if (paramTypes[0].isAssignableFrom(Identifier.class)
-                                               || Identifier.class.isAssignableFrom(paramTypes[0])) {
-                                       return (false);
-                               } else {
-                                       return (true);
-                               }
-                       }
+           if (m.getName().matches("^get[A-Z].*") && m.getReturnType().equals(boolean.class)) {
+               return (true);
+           }
+
+           if (m.getName().matches("^is[A-Z].*") && m.getReturnType().equals(Boolean.class)) {
+               return (true);
+           }
+       }
+
+       return (false);
+    }
 
+    public static boolean isSetter(Method m) {
+       if (m == null) {
+           return (false);
+       }
+
+       if (Modifier.isPublic(m.getModifiers()) && (m.getParameterTypes().length == 1)) {
+           if (m.getName().matches("^set[A-Z].*")) {
+               Class[] paramTypes = m.getParameterTypes();
+               if (paramTypes[0].isAssignableFrom(Identifier.class) || Identifier.class.isAssignableFrom(paramTypes[0])) {
+                   return (false);
+               } else {
+                   return (true);
                }
+           }
 
-               return (false);
        }
 
+       return (false);
+    }
+
+    public static String getFullPropertiesPath(String propertiesFileName) {
+       return "/opt/bvc/controller/configuration/" + propertiesFileName;
+    }
+    
+    //This is called when mapping a valid java enumeration back to the yang model value
+    public static String mapEnumeratedValue(String propertyName, String propertyValue) {
+        LOG.info("mapEnumeratedValue called with propertyName=" + propertyName + " and value=" + propertyValue);
+        String mappingKey = "yang." + propertyName + "." + propertyValue;
+        if (yangMappingProperties.containsKey(mappingKey)) {
+            return (yangMappingProperties.getProperty(mappingKey));
+        } else {
+            LOG.info("yangMappingProperties did not contain the key " + mappingKey + " returning the original value.");
+            return propertyValue;
+        }
+    }
+
 }
index 5002604..4dc4a93 100644 (file)
@@ -56,15 +56,7 @@ public class NotifyNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
-
-               ServiceReference sref = bctx.getServiceReference(plugin);
-
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
-
+        SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
                        if (resourcePlugin != null) {
 
                                try {
@@ -88,10 +80,6 @@ public class NotifyNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -114,5 +102,21 @@ public class NotifyNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
+
 
 }
index d07a4d6..f75752b 100644 (file)
@@ -50,8 +50,8 @@ public class RecordNodeExecutor extends SvcLogicNodeExecutor {
                                node.getAttribute("plugin"), node, ctx);
                String outValue = "failure";
 
-               if (LOG.isDebugEnabled()) {
-                       LOG.debug(node.getNodeType()
+               if (LOG.isTraceEnabled()) {
+                       LOG.trace(node.getNodeType()
                                        + " node encountered - looking for recorder class "
                                        + plugin);
                }
@@ -71,21 +71,15 @@ public class RecordNodeExecutor extends SvcLogicNodeExecutor {
                        String curExprValue = SvcLogicExpressionResolver.evaluate(curExpr,
                                        node, ctx);
 
-                       if (LOG.isDebugEnabled()) {
-                               LOG.debug("executeRecordNode : parameter " + curName + " = "
+                       if (LOG.isTraceEnabled()) {
+                               LOG.trace("executeRecordNode : parameter " + curName + " = "
                                                + curExpr + " => " + curExprValue);
                        }
                        parmMap.put(curName, curExprValue);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
-
-               ServiceReference sref = bctx.getServiceReference(plugin);
 
-               if (sref != null) {
-                       SvcLogicRecorder recorder = (SvcLogicRecorder) bctx
-                                       .getService(sref);
+                       SvcLogicRecorder recorder = getSvcLogicResource(plugin);
 
                        if (recorder != null) {
 
@@ -99,9 +93,6 @@ public class RecordNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicRecorder object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Cound not find service reference for plugin " + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -117,13 +108,28 @@ public class RecordNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.debug("about to execute Other branch");
                        }
                } else {
-                       if (LOG.isDebugEnabled()) {
-                               LOG.debug("no failure or Other branch found");
+                       if (LOG.isTraceEnabled()) {
+                               LOG.trace("no failure or Other branch found");
                        }
                }
                return (nextNode);
        }
 
+    protected SvcLogicRecorder getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicRecorder resourcePlugin = (SvcLogicRecorder) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            return null;
+        }
+    }
+
 
 
 }
index 12e85db..b51cf9f 100644 (file)
@@ -53,15 +53,7 @@ public class ReleaseNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
-
-               ServiceReference sref = bctx.getServiceReference(plugin);
-
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
-
+        SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
                        if (resourcePlugin != null) {
 
                                try {
@@ -85,10 +77,6 @@ public class ReleaseNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -112,5 +100,21 @@ public class ReleaseNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
+
 
 }
index aa5d5ef..7db233f 100644 (file)
@@ -65,14 +65,9 @@ public class ReserveNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
 
-               ServiceReference sref = bctx.getServiceReference(plugin);
 
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
+        SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
 
                        if (resourcePlugin != null) {
 
@@ -96,10 +91,6 @@ public class ReserveNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -123,5 +114,21 @@ public class ReserveNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
+
 
 }
index fc3adcc..f57eac8 100644 (file)
@@ -93,14 +93,9 @@ public class SaveNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
 
-               ServiceReference sref = bctx.getServiceReference(plugin);
 
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
+        SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
 
                        if (resourcePlugin != null) {
 
@@ -125,10 +120,6 @@ public class SaveNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -151,4 +142,20 @@ public class SaveNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
+
 }
index 0de109b..55ad737 100644 (file)
@@ -173,7 +173,7 @@ public class SetNodeExecutor extends SvcLogicNodeExecutor {
                                                        curEnt.getValue(), node, ctx);
 
                                        if (LOG.isDebugEnabled()) {
-                                               LOG.debug("Parameter value "
+                                               LOG.trace("Parameter value "
                                                                + curEnt.getValue().asParsedExpr()
                                                                + " resolves to " + curValue);
                                                LOG.debug("Setting context attribute " + lhsVarName
index 33de964..691ad40 100644 (file)
@@ -69,6 +69,7 @@ public class SvcLogicActivator implements BundleActivator {
                        put("set", new SetNodeExecutor());
                        put("switch", new SwitchNodeExecutor());
                        put("update", new UpdateNodeExecutor());
+            put("break", new BreakNodeExecutor());
 
                }
        };
index f248a59..29bd9b4 100644 (file)
@@ -65,12 +65,12 @@ public class SvcLogicExpressionResolver {
                                
                                if (atomType == AtomType.CONTEXT_VAR)
                                {
-                                       LOG.debug("Evaluating context variable $"+varName);
+                                       LOG.trace("Evaluating context variable $"+varName);
                                        
                                        String varValue = ctx.getAttribute(varName);
                                        
                                        if (varValue == null) {
-                                               LOG.debug("Context variable $"+varName+" unset - treating as empty string");
+                                               LOG.trace("Context variable $"+varName+" unset - treating as empty string");
                                                varValue = "";
                                        }
                                                
@@ -78,7 +78,7 @@ public class SvcLogicExpressionResolver {
                                }
                                SvcLogicExpression parm = node.getParameter(varName);
                                if (parm != null) {
-                                       LOG.debug("Evaluating value of parameter "+varName+": "+parm.asParsedExpr());
+                                       LOG.trace("Evaluating value of parameter "+varName+": "+parm.asParsedExpr());
                                        
                                        return (evaluate(parm, node, ctx));
                                }
@@ -98,7 +98,7 @@ public class SvcLogicExpressionResolver {
                                List<SvcLogicExpression> operands = binExpr.getOperands();
                                if (operands.size() == 1)
                                {
-                                       LOG.debug("SvcLogicBinaryExpression as no operator and one operand - evaluating its operand");
+                                       LOG.trace("SvcLogicBinaryExpression as no operator and one operand - evaluating its operand");
                                        return(evaluate(operands.get(0), node, ctx));
                                }
                                else
index 14366a9..6ee264e 100644 (file)
@@ -268,6 +268,8 @@ public class SvcLogicServiceImpl implements SvcLogicService {
 
                LOG.info("Executing root node");
                SvcLogicContext ctx = new SvcLogicContext(props);
+        ctx.setAttribute("currentGraph", graph.toString());
+        ctx.setAttribute("X-ECOMP-RequestID", MDC.get("X-ECOMP-RequestID"));
                ctx.setDomDataBroker(domDataBroker);
                SvcLogicNode curNode = graph.getRootNode();
 
index 4ea851f..2e32a58 100644 (file)
@@ -55,8 +55,7 @@ public class SwitchNodeExecutor extends SvcLogicNodeExecutor {
 
                if (LOG.isDebugEnabled()) {
                        if (nextNode != null) {
-                               LOG.debug("Next node to execute is node "
-                                               + nextNode.getNodeId());
+                LOG.debug("Next node to execute is node " + nextNode.getNodeId());
                        } else {
                                LOG.debug("No next node found");
                        }
index ac1144c..e7a6621 100644 (file)
@@ -87,14 +87,9 @@ public class UpdateNodeExecutor extends SvcLogicNodeExecutor {
                                        + plugin);
                }
 
-               BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
-                               .getBundleContext();
 
-               ServiceReference sref = bctx.getServiceReference(plugin);
+        SvcLogicResource resourcePlugin = getSvcLogicResource(plugin);
 
-               if (sref != null) {
-                       SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
-                                       .getService(sref);
 
                        if (resourcePlugin != null) {
 
@@ -119,10 +114,6 @@ public class UpdateNodeExecutor extends SvcLogicNodeExecutor {
                                LOG.warn("Could not find SvcLogicResource object for plugin "
                                                + plugin);
                        }
-               } else {
-                       LOG.warn("Could not find service reference object for plugin "
-                                       + plugin);
-               }
 
                SvcLogicNode nextNode = node.getOutcomeValue(outValue);
                if (nextNode != null) {
@@ -145,4 +136,19 @@ public class UpdateNodeExecutor extends SvcLogicNodeExecutor {
                return (nextNode);
        }
 
+    protected SvcLogicResource getSvcLogicResource(String plugin) {
+        BundleContext bctx = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+
+        ServiceReference sref = bctx.getServiceReference(plugin);
+        if (sref != null) {
+            SvcLogicResource resourcePlugin = (SvcLogicResource) bctx
+                    .getService(sref);
+            return resourcePlugin;
+        }
+        else {
+            LOG.warn("Could not find service reference object for plugin " + plugin);
+            return null;
+        }
+    }
 }
diff --git a/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/BadPlugin.java b/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/BadPlugin.java
new file mode 100644 (file)
index 0000000..d1ab4cf
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import java.util.Map;
+
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
+
+
+public class BadPlugin implements SvcLogicJavaPlugin {
+    public String selectLunch(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        String day = parameters.get("day");
+        if (day == null || day.length() < 1) {
+            throw new SvcLogicException("What day is it?");
+        }
+        switch (day) {
+        case ("monday"): {
+            return "pizza";
+        }
+        case ("tuesday"): {
+            return "soup";
+        }
+        case ("wednesday"): {
+            return "salad";
+        }
+        case ("thursday"): {
+            return "sushi";
+        }
+        case ("friday"): {
+            return "bbq";
+        }
+        }
+        throw new SvcLogicException("Lunch cannot be served");
+    }
+}
diff --git a/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/ExecuteNodeExecutorTest.java b/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/ExecuteNodeExecutorTest.java
new file mode 100644 (file)
index 0000000..3d43ee1
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import java.util.Map.Entry;
+
+import org.openecomp.sdnc.sli.DuplicateValueException;
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.openecomp.sdnc.sli.SvcLogicExpression;
+import org.openecomp.sdnc.sli.SvcLogicGraph;
+import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
+import org.openecomp.sdnc.sli.SvcLogicNode;
+
+import junit.framework.TestCase;
+
+public class ExecuteNodeExecutorTest extends TestCase {
+    public class MockExecuteNodeExecutor extends ExecuteNodeExecutor {
+
+        protected SvcLogicJavaPlugin getSvcLogicJavaPlugin(String pluginName) {
+            return (SvcLogicJavaPlugin) new LunchSelectorPlugin();
+        }
+
+        protected String evaluate(SvcLogicExpression expr, SvcLogicNode node,
+                SvcLogicContext ctx) throws SvcLogicException {
+            return "selectLunch";
+        }
+    }
+
+    public void testBadPlugin() throws DuplicateValueException, SvcLogicException {
+        LunchSelectorPlugin p = new LunchSelectorPlugin();
+        MockExecuteNodeExecutor execute = new MockExecuteNodeExecutor();
+        SvcLogicNode node = new SvcLogicNode(0, "", "", new SvcLogicGraph());
+        node.setAttribute("method", "selectLunch");
+        execute.execute(new SvcLogicServiceImpl(), new SvcLogicNode(0, "", "", new SvcLogicGraph()), new SvcLogicContext());
+    }
+
+}
diff --git a/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/LunchSelectorPlugin.java b/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/LunchSelectorPlugin.java
new file mode 100644 (file)
index 0000000..b9156bc
--- /dev/null
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import java.util.Map;
+
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
+
+
+
+public class LunchSelectorPlugin implements SvcLogicJavaPlugin {
+    public class UnknownLunchDayException extends Exception{
+
+        public UnknownLunchDayException(String string) {
+            super(string);
+        }
+
+    }
+    class Sandwhich {
+        String meat;
+        String cheese;
+
+        public Sandwhich(String meat, String cheese) {
+            this.meat = meat;
+            this.cheese = cheese;
+        }
+    }
+
+    public String selectLunch(Map<String, String> parameters, SvcLogicContext ctx) throws Exception {
+        String day = parameters.get("day");
+        if (day == null || day.length() < 1) {
+            throw new UnknownLunchDayException("What day is it?");
+        }
+        switch (day) {
+        case ("monday"): {
+            return "pizza";
+        }
+        case ("tuesday"): {
+            return "soup";
+        }
+        case ("wednesday"): {
+            return "salad";
+        }
+        case ("thursday"): {
+            return "sushi";
+        }
+        case ("friday"): {
+            return "bbq";
+        }
+        }
+        throw new SvcLogicException("Lunch cannot be served");
+    }
+
+    public Sandwhich makeLunch(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        return new Sandwhich("ham", "american");
+    }
+}
diff --git a/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/MdsalHelperTest.java b/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/MdsalHelperTest.java
new file mode 100644 (file)
index 0000000..a4e41bb
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import junit.framework.TestCase;
+
+public class MdsalHelperTest extends TestCase {
+
+    public static final String pathToSdnPropertiesFile = "./src/test/resources/l3sdn.properties";
+
+    public void testSdnProperties() {
+        MdsalHelperTesterUtil.loadProperties(pathToSdnPropertiesFile);
+        assertEquals("synccomplete", MdsalHelperTesterUtil.mapEnumeratedValue("request-status", "Synccomplete"));
+        assertEquals("asynccomplete", MdsalHelperTesterUtil.mapEnumeratedValue("request-status", "asynccomplete"));
+        assertEquals("notifycomplete", MdsalHelperTesterUtil.mapEnumeratedValue("request-status", "notifycomplete"));
+        assertEquals("service-configuration-operation", MdsalHelperTesterUtil.mapEnumeratedValue("rpc-name",
+                "ServiceConfigurationOperation"));
+    }
+
+    public void testNegativeSdnProperties() {
+        assertNotSame("synccomplete", MdsalHelperTesterUtil.mapEnumeratedValue("request-status", "Synccomplete"));
+    }
+
+}
diff --git a/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/MdsalHelperTesterUtil.java b/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/MdsalHelperTesterUtil.java
new file mode 100644 (file)
index 0000000..01e333f
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import org.openecomp.sdnc.sli.provider.MdsalHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MdsalHelperTesterUtil extends MdsalHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalHelperTesterUtil.class);
+    
+    //Normally static init of classes goes here for some weird classloader thing
+    static {
+        String str = "Hello World!";
+    }
+
+}
diff --git a/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/PluginTest.java b/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/PluginTest.java
new file mode 100644 (file)
index 0000000..035cd3e
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicGraph;
+import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
+import org.openecomp.sdnc.sli.SvcLogicNode;
+
+import junit.framework.TestCase;
+
+public class PluginTest extends TestCase {
+
+    // The existing plugins work just like a VoidDummyPlugin
+    // They will return null simply because they are all void
+    // The attribute emitsOutcome will not be present, the expected outcome is success when no exception is thrown by the plugin
+    public void testOldPlugin() throws Exception {
+        ExecuteNodeExecutor executor = new ExecuteNodeExecutor();
+        SvcLogicJavaPlugin plugin = new VoidDummyPlugin();
+
+        Class pluginClass = plugin.getClass();
+        Method pluginMethod = pluginClass.getMethod("dummy", Map.class, SvcLogicContext.class);
+        Map<String, String> parmMap = new HashMap<String, String>();
+        SvcLogicContext ctx = new SvcLogicContext();
+        Object o = pluginMethod.invoke(plugin, parmMap, ctx);
+
+        SvcLogicGraph graph = new SvcLogicGraph();
+        SvcLogicNode node = new SvcLogicNode(1, "return", graph);
+        String emitsOutcome = SvcLogicExpressionResolver.evaluate(node.getAttribute("emitsOutcome"),  node, ctx);
+        String outValue = executor.mapOutcome(o, emitsOutcome);
+        assertEquals("success",outValue);
+    }
+
+    //Newer plugins can set the attribute emitsOutcome to true, if so they should return a string
+    //The string represents the outcome value
+    public void testNewPlugin() throws Exception {
+        ExecuteNodeExecutor executor = new ExecuteNodeExecutor();
+        SvcLogicJavaPlugin plugin = new LunchSelectorPlugin();
+
+        Class pluginClass = plugin.getClass();
+        Method pluginMethod = pluginClass.getMethod("selectLunch", Map.class, SvcLogicContext.class);
+
+        Map<String, String> parmMap = new HashMap<String, String>();
+        SvcLogicContext ctx = new SvcLogicContext();
+
+        parmMap.put("day", "monday");
+        Object o = pluginMethod.invoke(plugin, parmMap, ctx);
+        SvcLogicGraph graph = new SvcLogicGraph();
+        SvcLogicNode node = new SvcLogicNode(1, "return", graph);
+        node.setAttribute("emitsOutcome", "true");
+        String emitsOutcome = SvcLogicExpressionResolver.evaluate(node.getAttribute("emitsOutcome"),  node, ctx);
+        String outValue = executor.mapOutcome(o, emitsOutcome);
+        assertEquals("pizza", outValue);
+
+        parmMap.put("day", "tuesday");
+        outValue = (String) pluginMethod.invoke(plugin, parmMap, ctx);
+        o = pluginMethod.invoke(plugin, parmMap, ctx);
+        outValue = executor.mapOutcome(o, emitsOutcome);
+        assertEquals("soup",outValue);
+
+    }
+
+    //APPC had some legacy plugins returning objects which should not be treated as outcomes
+    //The attribute emitsOutcome will not be set
+    //The outcome should be success as it has always been
+    public void testObjPlugin() throws Exception{
+        ExecuteNodeExecutor executor = new ExecuteNodeExecutor();
+        SvcLogicJavaPlugin plugin = new LunchSelectorPlugin();
+
+        Class pluginClass = plugin.getClass();
+        Method pluginMethod = pluginClass.getMethod("makeLunch", Map.class, SvcLogicContext.class);
+
+        Map<String, String> parmMap = new HashMap<String, String>();
+        SvcLogicContext ctx = new SvcLogicContext();
+        Object o = pluginMethod.invoke(plugin, parmMap, ctx);
+        SvcLogicGraph graph = new SvcLogicGraph();
+        SvcLogicNode node = new SvcLogicNode(1, "return", graph);
+        String emitsOutcome = SvcLogicExpressionResolver.evaluate(node.getAttribute("emitsOutcome"),  node, ctx);
+        String outValue = executor.mapOutcome(o, emitsOutcome);
+        assertEquals("success",outValue);
+    }
+
+}
diff --git a/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/VoidDummyPlugin.java b/sli/provider/src/test/java/org/openecomp/sdnc/sli/provider/VoidDummyPlugin.java
new file mode 100644 (file)
index 0000000..6c8214a
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.provider;
+
+import java.util.Map;
+
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
+
+
+
+public class VoidDummyPlugin implements SvcLogicJavaPlugin {
+
+    public void dummy(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        return;
+    }
+
+}
index 093d585..739f89d 100755 (executable)
                        <artifactId>commons-lang3</artifactId>
                        <version>3.1</version>
                </dependency>
+               <dependency>
+                       <groupId>org.hamcrest</groupId>
+                       <artifactId>hamcrest-library</artifactId>
+                       <version>1.3</version>
+                       <scope>test</scope>
+               </dependency>
        </dependencies>
 
        <build>
diff --git a/sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/DME2.java b/sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/DME2.java
new file mode 100644 (file)
index 0000000..0acaf5f
--- /dev/null
@@ -0,0 +1,110 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.SliPluginUtils;
+
+import java.util.Map;
+
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+
+/**
+ * A SvcLogicJavaPlugin that generates DME2 proxy urls using parameters from context memory.
+ */
+public class DME2 implements SvcLogicJavaPlugin {
+    String aafUserName;
+    String aafPassword;
+    String envContext;
+    String routeOffer;
+    String[] proxyUrls;
+    Integer index;
+    String commonServiceVersion;
+    String partner;
+
+    private static final Logger LOG = LoggerFactory.getLogger(DME2.class);
+
+    public void setPartner(String partner) {
+        if (partner != null && partner.length() > 0) {
+            this.partner = partner;
+        }
+    }
+
+    public DME2(String aafUserName, String aafPassword, String envContext, String routeOffer, String[] proxyUrls, String commonServiceVersion) {
+        this.aafUserName = aafUserName;
+        this.aafPassword = aafPassword;
+        this.envContext = envContext;
+        this.routeOffer = routeOffer;
+        this.proxyUrls = proxyUrls;
+        this.index = 0;
+        this.commonServiceVersion = commonServiceVersion;
+    }
+
+    // constructs a URL to contact the proxy which contacts a DME2 service
+    public String constructUrl(String service, String version, String subContext) {
+        StringBuilder sb = new StringBuilder();
+
+        // The hostname is assigned in a round robin fashion
+        sb.append(acquireHostName());
+        sb.append("/service=" + service);
+
+        //If the directedGraph passes an explicit version use that, if not use the commonServiceVersion found in the properties file
+        if (version == null) {
+            version = this.commonServiceVersion;
+        }
+        sb.append("/version=" + version);
+
+        sb.append("/envContext=" + this.envContext);
+        if (this.routeOffer != null && this.routeOffer.length() > 0) {
+            sb.append("/routeOffer=" + this.routeOffer);
+        }
+        if (subContext != null && subContext.length() > 0) {
+            sb.append("/subContext=" + subContext);
+        }
+        sb.append("?dme2.password=" + this.aafPassword);
+        sb.append("&dme2.username=" + this.aafUserName);
+        if (this.partner != null) {
+            sb.append("&dme2.partner=" + this.partner);
+        }
+        return (sb.toString());
+    }
+
+    public synchronized String acquireHostName() {
+        String retVal = proxyUrls[index];
+        index++;
+        if (index == this.proxyUrls.length) {
+            index = 0;
+        }
+        return retVal;
+    }
+
+    // Node entry point
+    public void constructUrl(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[] { "service", "outputPath" }, LOG);
+        String completeProxyUrl = constructUrl(parameters.get("service"), parameters.get("version"), parameters.get("subContext"));
+        ctx.setAttribute(parameters.get("outputPath"), completeProxyUrl);
+    }
+
+}
index ea8df51..1dd29a5 100644 (file)
 
 package org.openecomp.sdnc.sli.SliPluginUtils;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
+import java.util.Set;
 import java.util.UUID;
 
 import org.apache.commons.lang3.StringUtils;
@@ -43,582 +49,706 @@ import org.slf4j.LoggerFactory;
  * @see org.openecomp.sdnc.sli.SvcLogicContext
  */
 public class SliPluginUtils implements SvcLogicJavaPlugin {
-    public enum LogLevel {
-        TRACE, DEBUG, INFO, WARN, ERROR;
-    }
-
-    private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils.class);
-
-
-    // ========== CONSTRUCTORS ==========
-
-    public SliPluginUtils() {}
-
-    public SliPluginUtils( Properties props ) {}
-
-
-
-    // ========== CONTEXT MEMORY FUNCTIONS ==========
+       public enum LogLevel {
+               TRACE, DEBUG, INFO, WARN, ERROR;
+       }
+
+       private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils.class);
+
+
+       // ========== CONSTRUCTORS ==========
+
+       public SliPluginUtils() {}
+
+       public SliPluginUtils( Properties props ) {}
+
+
+
+       // ========== CONTEXT MEMORY FUNCTIONS ==========
+
+       /**
+        * Removes 1 or more elements from a list in context memory.
+        * <p>
+        * Values are removed based on either the index in the list, a key-value
+        * pair, or a list of key-value pairs that all must match in the element.
+        * @param parameters
+        * @param ctx Reference to context memory
+        * @throws SvcLogicException All exceptions are wrapped in
+        * SvcLogicException for compatibility with SLI.
+        * @since 7.0.1
+        */
+       public void ctxListRemove( Map<String,String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
+               try{
+                       LOG.debug( "ENTERING Execute Node \"ctxListRemove\"" );
+
+                       // Validate, Log, & read parameters
+                       checkParameters(parameters, new String[]{"list_pfx"}, LOG);
+                       logExecuteNodeParameters(parameters, LOG, LogLevel.DEBUG);
+                       String list_pfx = parameters.get("list_pfx");
+                       String param_index = parameters.get("index");
+                       String param_key = parameters.get("key");
+                       String param_value = parameters.get("value");
+                       String param_keys_length = parameters.get("keys_length");
+
+                       // Initialize context memory list mimic
+                       SvcLogicContextList list;
+
+                       // Process based on input parameters:
+                       //   index: remove object at specific index
+                       //   key & value: remove all objects with key-value pair
+                       //   keys_length: remove all objects that match all key-value pairs
+                       //                in list
+                       if( param_index != null ) {
+                               // Parse index
+                               LOG.trace("executing remove by index logic");
+                               int index;
+                               try {
+                                       index = Integer.parseInt(param_index);
+                               }
+                               catch( NumberFormatException e ) {
+                                       throw new IllegalArgumentException("\"index\" parameter is not a number. index = " + param_index, e);
+                               }
+
+                               // Extract list from context memory & remove object @ index
+                               LOG.trace("extracting list from context memory");
+                               list = SvcLogicContextList.extract(ctx, list_pfx);
+                               LOG.trace("removing elements from list");
+                               list.remove(index);
+                       }
+                       else if( param_value != null ) {
+                               if( param_key == null ) { param_key = ""; }
+
+                               // Extract list from context memory & remove objects with
+                               // key-value pair
+                               LOG.trace("executing remove by key-value pair logic");
+                               LOG.trace("extracting list from context memory");
+                               list = SvcLogicContextList.extract(ctx, list_pfx);
+                               LOG.trace("removing elements from list");
+                               list.remove( param_key, param_value );
+                       }
+                       else if( param_keys_length != null ) {
+                               // Parse keys_length
+                               LOG.trace("executing remove by key-value pair list logic");
+                               int keys_length;
+                               try {
+                                       keys_length = Integer.parseInt(param_keys_length);
+                               }
+                               catch( NumberFormatException e ) {
+                                       throw new IllegalArgumentException("\"keys_length\" parameters is not a number. keys_length = " + param_keys_length, e);
+                               }
+
+                               // Obtain key-value pairs to check from parameters
+                               LOG.trace("reading keys parameter list");
+                               HashMap<String,String> keys_values = new HashMap<String,String>();
+                               for( int i = 0; i < keys_length; i++ ) {
+                                       keys_values.put(parameters.get("keys[" + i + "].key"), parameters.get("keys[" + i + "].value"));
+                               }
+
+                               // Extract list from context memory & remove objects with all
+                               // key-value pairs matching
+                               LOG.trace("extracting list from context memory");
+                               list = SvcLogicContextList.extract(ctx, list_pfx);
+                               LOG.trace("removing elements from list");
+                               list.remove(keys_values);
+                       }
+                       else {
+                               throw new IllegalArgumentException("Required parameters missing. Requires one of: index, key & value, or keys_length array");
+                       }
+
+                       // Remove index from list
+                       LOG.trace("writing list back into context memory");
+                       list.writeToContext(ctx);
+               }
+               catch( Exception e ) {
+                       throw new SvcLogicException( "An error occurred in the ctxListRemove Execute node", e );
+               }
+               finally {
+                       LOG.debug( "EXITING Execute Node \"ctxListRemove\"" );
+               }
+       }
 
     /**
-     * Removes 1 or more elements from a list in context memory.
-     * <p>
-     * Values are removed based on either the index in the list, a key-value
-     * pair, or a list of key-value pairs that all must match in the element.
-     * @param parameters
+     * ctxSortList
+     * @param parameters - the set of required parameters must contain list and delimiter.
      * @param ctx Reference to context memory
-     * @throws SvcLogicException All exceptions are wrapped in
-     * SvcLogicException for compatibility with SLI.
-     * @since 7.0.1
+     * @throws SvcLogicException if a required parameter is missing an exception is thrown
      */
-    public void ctxListRemove( Map<String,String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
-        try{
-            LOG.debug( "ENTERING Execute Node \"ctxListRemove\"" );
-
-            // Validate, Log, & read parameters
-            checkParameters(parameters, new String[]{"list_pfx"}, LOG);
-            logExecuteNodeParameters(parameters, LOG, LogLevel.DEBUG);
-            String list_pfx = parameters.get("list_pfx");
-            String param_index = parameters.get("index");
-            String param_key = parameters.get("key");
-            String param_value = parameters.get("value");
-            String param_keys_length = parameters.get("keys_length");
-
-            // Initialize context memory list mimic
-            SvcLogicContextList list;
-
-            // Process based on input parameters:
-            //   index: remove object at specific index
-            //   key & value: remove all objects with key-value pair
-            //   keys_length: remove all objects that match all key-value pairs
-            //                in list
-            if( param_index != null ) {
-                // Parse index
-                LOG.trace("executing remove by index logic");
-                int index;
-                try {
-                    index = Integer.parseInt(param_index);
-                }
-                catch( NumberFormatException e ) {
-                    throw new IllegalArgumentException("\"index\" parameter is not a number. index = " + param_index, e);
-                }
-
-                // Extract list from context memory & remove object @ index
-                LOG.trace("extracting list from context memory");
-                list = SvcLogicContextList.extract(ctx, list_pfx);
-                LOG.trace("removing elements from list");
-                list.remove(index);
-            }
-            else if( param_value != null ) {
-                if( param_key == null ) { param_key = ""; }
-
-                // Extract list from context memory & remove objects with
-                // key-value pair
-                LOG.trace("executing remove by key-value pair logic");
-                LOG.trace("extracting list from context memory");
-                list = SvcLogicContextList.extract(ctx, list_pfx);
-                LOG.trace("removing elements from list");
-                list.remove( param_key, param_value );
-            }
-            else if( param_keys_length != null ) {
-                // Parse keys_length
-                LOG.trace("executing remove by key-value pair list logic");
-                int keys_length;
-                try {
-                    keys_length = Integer.parseInt(param_keys_length);
-                }
-                catch( NumberFormatException e ) {
-                    throw new IllegalArgumentException("\"keys_length\" parameters is not a number. keys_length = " + param_keys_length, e);
-                }
-
-                // Obtain key-value pairs to check from parameters
-                LOG.trace("reading keys parameter list");
-                HashMap<String,String> keys_values = new HashMap<>();
-                for( int i = 0; i < keys_length; i++ ) {
-                    keys_values.put(parameters.get("keys[" + i + "].key"), parameters.get("keys[" + i + "].value"));
-                }
-
-                // Extract list from context memory & remove objects with all
-                // key-value pairs matching
-                LOG.trace("extracting list from context memory");
-                list = SvcLogicContextList.extract(ctx, list_pfx);
-                LOG.trace("removing elements from list");
-                list.remove(keys_values);
-            }
-            else {
-                throw new IllegalArgumentException("Required parameters missing. Requires one of: index, key & value, or keys_length array");
-            }
-
-            // Remove index from list
-            LOG.trace("writing list back into context memory");
-            list.writeToContext(ctx);
-        }
-        catch( Exception e ) {
-            throw new SvcLogicException( "An error occurred in the ctxListRemove Execute node", e );
-        }
-        finally {
-            LOG.debug( "EXITING Execute Node \"ctxListRemove\"" );
-        }
-    }
-
-    // TODO: javadoc
-    public void ctxSortList( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
-        checkParameters(parameters, new String[]{"list","delimiter"}, LOG);
-        ArrayList<SortableCtxListElement> list = new ArrayList<>();
-
-        String[] sort_fields = null;
-        if( parameters.containsKey("sort-fields") ) {
-            sort_fields = parameters.get("sort-fields").split(parameters.get("delimiter"), 0);
-        }
-
-        String ctx_list_str = parameters.get("list");
-        int listSz = getArrayLength(ctx, ctx_list_str);
-
-
-
-        for( int i = 0; i < listSz; i++ ) {
-            list.add( new SortableCtxListElement(ctx, ctx_list_str + '[' + i + ']', sort_fields) );
-        }
-        Collections.sort(list);
-
-        ctxBulkErase(ctx, ctx_list_str);
-        int i = 0;
-        for( SortableCtxListElement list_element : list ) {
-            for( Map.Entry<String,String> entry : list_element.child_elements.entrySet() ) {
-                if( sort_fields == null ) {
-                    ctx.setAttribute(ctx_list_str + '[' + i + ']', entry.getValue());
-                }
-                else {
-                    ctx.setAttribute(ctx_list_str + '[' + i + "]." + entry.getKey(), entry.getValue());
-                }
-            }
-            i++;
-        }
-        // Reset list length (removed by ctxBulkErase above)
-        ctx.setAttribute(ctx_list_str+"_length",  ""+listSz);
-    }
-
-    // TODO: javadoc
-    public void generateUUID( Map<String, String> parameters, SvcLogicContext ctx )  throws SvcLogicException {
-        checkParameters(parameters, new String[]{"ctx-destination"}, LOG);
-        ctx.setAttribute(parameters.get("ctx-destination"), UUID.randomUUID().toString() );
-    }
+       public void ctxSortList( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
+               checkParameters(parameters, new String[]{"list","delimiter"}, LOG);
+               ArrayList<SortableCtxListElement> list = new ArrayList<SortableCtxListElement>();
+
+               String[] sort_fields = null;
+               if( parameters.containsKey("sort-fields") ) {
+                       sort_fields = parameters.get("sort-fields").split(parameters.get("delimiter"), 0);
+               }
+
+               String ctx_list_str = parameters.get("list");
+               int listSz = getArrayLength(ctx, ctx_list_str);
+
+
+
+               for( int i = 0; i < listSz; i++ ) {
+                       list.add( new SortableCtxListElement(ctx, ctx_list_str + '[' + i + ']', sort_fields) );
+               }
+               Collections.sort(list);
+
+               ctxBulkErase(ctx, ctx_list_str);
+               int i = 0;
+               for( SortableCtxListElement list_element : list ) {
+                       for( Map.Entry<String,String> entry : list_element.child_elements.entrySet() ) {
+                               if( sort_fields == null ) {
+                                       ctx.setAttribute(ctx_list_str + '[' + i + ']', entry.getValue());
+                               }
+                               else {
+                                       ctx.setAttribute(ctx_list_str + '[' + i + "]." + entry.getKey(), entry.getValue());
+                               }
+                       }
+                       i++;
+               }
+               // Reset list length (removed by ctxBulkErase above)
+               ctx.setAttribute(ctx_list_str+"_length",  ""+listSz);
+       }
 
     /**
-     * Provides substring functionality to Directed Graphs.
-     * <p>
-     * Calls either String.substring(String beginIndex) or
-     * String.substring(String beginInded, String endIndex) if the end-index
-     * is present or not.
-     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
-     * <table border="1">
-     *     <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
-     *     <tbody>
-     *         <tr><td>string</td><td>Mandatory</td><td>String to perform substring on</td></tr>
-     *         <tr><td>result</td><td>Mandatory</td><td>Key in context memory to populate the resulting string in</td></tr>
-     *         <tr><td>begin-index</td><td>Mandatory</td><td>Beginning index to pass to Java substring function</td></tr>
-     *         <tr><td>end-index</td><td>Optional</td><td>Ending index to pass to Java substring function. If not included, String.substring(begin) will be called.</td></tr>
-     *     </tbody>
-     * </table>
+     * generates a UUID and writes it to context memory
+     * @param parameters - ctx-destination is a required parameter
      * @param ctx Reference to context memory
-     * @throws SvcLogicException
-     * @since 8.0.1
+     * @throws SvcLogicException thrown if a UUID cannot be generated or if ctx-destination is missing or null
      */
-    public void substring( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
-        try {
-            checkParameters( parameters, new String[]{"string","begin-index","result"}, LOG );
-            final String string = parameters.get("string");
-            final String result = parameters.get("result");
-            final String begin = parameters.get("begin-index");
-            final String end = parameters.get("end-index");
-
-            if( StringUtils.isEmpty(end) ) {
-                ctx.setAttribute( result, string.substring(Integer.parseInt(begin)) );
-            }
-            else {
-                ctx.setAttribute( result, string.substring(Integer.parseInt(begin), Integer.parseInt(end)) );
-            }
+       public void generateUUID( Map<String, String> parameters, SvcLogicContext ctx )  throws SvcLogicException {
+               checkParameters(parameters, new String[]{"ctx-destination"}, LOG);
+               ctx.setAttribute(parameters.get("ctx-destination"), UUID.randomUUID().toString() );
+       }
+
+       /**
+        * Provides substring functionality to Directed Graphs.
+        * <p>
+        * Calls either String.substring(String beginIndex) or
+        * String.substring(String beginInded, String endIndex) if the end-index
+        * is present or not.
+        * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+        * <table border="1">
+        *      <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+        *      <tbody>
+        *              <tr><td>string</td><td>Mandatory</td><td>String to perform substring on</td></tr>
+        *              <tr><td>result</td><td>Mandatory</td><td>Key in context memory to populate the resulting string in</td></tr>
+        *              <tr><td>begin-index</td><td>Mandatory</td><td>Beginning index to pass to Java substring function</td></tr>
+        *              <tr><td>end-index</td><td>Optional</td><td>Ending index to pass to Java substring function. If not included, String.substring(begin) will be called.</td></tr>
+        *      </tbody>
+        * </table>
+        * @param ctx Reference to context memory
+        * @throws SvcLogicException
+        * @since 8.0.1
+        * @see SliPluginUtils#substring(Map, SvcLogicContext)
+        */
+       @Deprecated
+       public void substring( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
+               try {
+                       checkParameters( parameters, new String[]{"string","begin-index","result"}, LOG );
+                       final String string = parameters.get("string");
+                       final String result = parameters.get("result");
+                       final String begin = parameters.get("begin-index");
+                       final String end = parameters.get("end-index");
+
+                       if( StringUtils.isEmpty(end) ) {
+                               ctx.setAttribute( result, string.substring(Integer.parseInt(begin)) );
+                       }
+                       else {
+                               ctx.setAttribute( result, string.substring(Integer.parseInt(begin), Integer.parseInt(end)) );
+                       }
+               }
+               catch( Exception e ) {
+                       throw new SvcLogicException( "An error occurred while the Directed Graph was performing a substring", e );
+               }
+       }
+
+
+
+       // ========== PUBLIC STATIC UTILITY FUNCTIONS ==========
+
+       /**
+        * Throws an exception and writes an error to the log file if a required
+        * parameters is not found in the parametersMap.
+        * <p>
+        * Use at the beginning of functions that can be called by Directed Graphs
+        * and can take parameters to verify that all parameters have been provided
+        * by the Directed Graph.
+        * @param parametersMap parameters Map passed to this node
+        * @param requiredParams Array of parameters required by the calling function
+        * @param log Reference to Logger to log to
+        * @throws SvcLogicException if a String in the requiredParams array is
+        * not a key in parametersMap.
+        * @since 1.0
+        */
+        public static final void checkParameters(Map<String, String> parametersMap, String[] requiredParams, Logger log) throws SvcLogicException {
+        if( requiredParams == null || requiredParams.length < 1){
+            log.debug("required parameters was empty, exiting early.");
+            return;
         }
-        catch( Exception e ) {
-            throw new SvcLogicException( "An error occurred while the Directed Graph was performing a substring", e );
+        if (parametersMap == null || parametersMap.keySet().size() < 1){
+            String errorMessage = "This method requires the parameters [" +   StringUtils.join(requiredParams,",") + "], but no parameters were passed in.";
+            log.error(errorMessage);
+            throw new SvcLogicException(errorMessage);
         }
-    }
 
-
-
-    // ========== PUBLIC STATIC UTILITY FUNCTIONS ==========
-
-    /**
-     * Throws an exception and writes an error to the log file if a required
-     * parameters is not found in the parametersMap.
-     * <p>
-     * Use at the beginning of functions that can be called by Directed Graphs
-     * and can take parameters to verify that all parameters have been provided
-     * by the Directed Graph.
-     * @param parametersMap parameters Map passed to this node
-     * @param requiredParams Array of parameters required by the calling function
-     * @param log Reference to Logger to log to
-     * @throws SvcLogicException if a String in the requiredParams array is
-     * not a key in parametersMap.
-     * @since 1.0
-     */
-    public static final void checkParameters( Map<String,String> parametersMap, String[] requiredParams, Logger log ) throws SvcLogicException {
-        for( String param : requiredParams ) {
-            if( !parametersMap.containsKey(param) ) {
-                log.error("Required parameter \"" + param + "\" was not found in parameter list.");
-                throw new SvcLogicException("Required parameter \"" + param + "\" was not found in parameter list");
-            }
+       for (String param : requiredParams) {
+           if (!parametersMap.containsKey(param)) {
+               String errorMessage = "Required parameter \"" + param + "\" was not found in parameter list.";
+               log.error(errorMessage);
+               log.error("Total list of required parameters is [" + StringUtils.join(requiredParams, ",") + "].");
+               throw new SvcLogicException(errorMessage);
+           }
+       }
         }
-    }
 
-    /**
-     * Removes all key-value pairs with keys that begin with pfx
+       /**
+        * Removes all key-value pairs with keys that begin with pfx
+        * @param ctx Reference to context memory
+        * @param pfx Prefix of key-value pairs to remove
+        * @since 1.0
+        */
+       public static final void ctxBulkErase( SvcLogicContext ctx, String pfx ) {
+               ArrayList<String> Keys = new ArrayList<String>( ctx.getAttributeKeySet() );
+               for( String key : Keys ) {
+                       if( key.startsWith( pfx ) ) {
+                               ctx.setAttribute( pfx + key.substring(pfx.length()) , null);
+                       }
+               }
+       }
+
+       /**
+        * Copies all context memory key-value pairs that start with src_pfx to
+        * the keys that start with dest_pfx + suffix, where suffix is the result
+        * of {@code key.substring(src_pfx.length())}.
+        * <p>
+        * Does NOT guarantee removal of all keys at the destination before
+        * copying, but will overwrite any destination keys that have a
+        * corresponding source key. Use {@link #ctxBulkErase(SvcLogicContext, String) ctxBulkErase}
+        * before copy to erase destination root before copying from source.
+        * @param ctx Reference to context memory.
+        * @param src_pfx Prefix of the keys to copy values from.
+        * @param dest_pfx Prefix of the keys to copy values to.
+        * @since 1.0
+        */
+       public static final void ctxBulkCopy( SvcLogicContext ctx, String src_pfx, String dest_pfx ) {
+               // Remove trailing period from dest_pfx
+               if( dest_pfx.charAt(dest_pfx.length()-1) == '.' ) {
+                       dest_pfx = dest_pfx.substring(0,dest_pfx.length()-1);
+               }
+
+               // For each context key that begins with src_pfx, set the value of the
+               // key dest_pfx + the suffix of the key to the key's value
+               ArrayList<String> Keys = new ArrayList<String>(ctx.getAttributeKeySet());
+               for( String key : Keys ) {
+                       if( key.startsWith(src_pfx) ) {
+                               // Get suffix (no leading period)
+                               String suffix = key.substring(src_pfx.length());
+                               if( suffix.charAt(0) == '.') {
+                                       suffix = suffix.substring(1);
+                               }
+
+                               // Set destination's value to key's value
+                               ctx.setAttribute(dest_pfx + '.' + suffix, ctx.getAttribute(key));
+                       }
+               }
+       }
+
+       /**
+        * Creates and returns a {@code Map<String, String>} that is a subset of
+        * context memory where all keys begin with the prefix.
+        * @param ctx Reference to context memory.
+        * @param prefix Returned map's keys should all begin with this value.
+        * @return A {@code Map<String, String>} containing all the key-value pairs
+        * in ctx whose key begins with prefix.
+        */
+       public static final Map<String, String> ctxGetBeginsWith( SvcLogicContext ctx, String prefix ) {
+               Map<String, String> prefixMap = new HashMap<String, String>();
+
+               for( String key : ctx.getAttributeKeySet() ) {
+                       if( key.startsWith(prefix) ) {
+                               prefixMap.put( key, ctx.getAttribute(key) );
+                       }
+               }
+
+               return prefixMap;
+       }
+
+       /**
+        * Returns true if key's value in context memory is "" or if it doesn't
+        * exist in context memory.
+        * @param ctx Reference to context memory.
+        * @param key Key to search for.
+        * @return true if key's value in context memory is "" or if it doesn't
+        * exist in context memory.
+        * @since 1.0
+        */
+       public static final boolean ctxKeyEmpty( SvcLogicContext ctx, String key ) {
+               String value = ctx.getAttribute(key);
+               return value == null || value.isEmpty();
+       }
+
+       /**
+        * Adds all key-value pairs in the entries Map to context memory.
+        * @param ctx Reference to context memory. Value's {@code toString()}
+        * function is used to add it.
+        * @param entries {@code Map<String, ?>} of key-value pairs to add to
+        * context memory. Value's {@code toString()} function is used to add it.
+        * @return Reference to context memory to be used for function chaining.
+        */
+       public static final SvcLogicContext ctxPutAll( SvcLogicContext ctx, Map<String, ?> entries ) {
+               for( Map.Entry<String, ?> entry : entries.entrySet() ) {
+                       ctxSetAttribute( ctx, entry.getKey(), entry.getValue() );
+                       //ctx.setAttribute(entry.getKey(), entry.getValue().toString());
+               }
+
+               return ctx;
+       }
+
+       /**
+        * Sets a key in context memory to the output of object's toString(). The
+        * key is deleted from context memory if object is null.
+        * @param ctx Reference to context memory.
+        * @param key Key to set.
+        * @param object Object whose toString() will be the value set
+        */
+       public static final void ctxSetAttribute( SvcLogicContext ctx, String key, Object object ) {
+               if( object == null ) {
+                       ctx.setAttribute(key, null);
+               }
+               else {
+                       ctx.setAttribute(key, object.toString());
+               }
+       }
+
+       /**
+        * Sets a key in context memory to the output of object's toString().
+        * <p>
+        * The key is deleted from context memory if object is null. The key and
+        * value set in context memory are logged to the Logger at the provided
+        * logLevel level.
+        * @param <O> Any Java object
+        * @param ctx Reference to context memory.
+        * @param key Key to set.
+        * @param obj Object whose toString() will be the value set
+        * @param LOG Logger to log to
+        * @param logLevel level to log at in Logger
+        */
+       public static final <O extends Object> void ctxSetAttribute( SvcLogicContext ctx, String key, O obj, Logger LOG, LogLevel logLevel ) {
+               String value = Objects.toString( obj, null );
+               ctx.setAttribute( key, value );
+               if( logLevelIsEnabled(LOG, logLevel ) ) {
+                       if( value == null ) {
+                               logMessageAtLevel( LOG, logLevel, "Deleting " + key );
+                       }
+                       else {
+                               logMessageAtLevel( LOG, logLevel, "Setting " + key + " = " + value );
+                       }
+               }
+       }
+
+       /**
+        * Utility function used to get an array's length from context memory.
+        * Will return 0 if key doesn't exist in context memory or isn't numeric.
+        * <p>
+        * Use to obtain a context memory array length without having to worry
+        * about throwing a NumberFormatException.
+        * @param ctx Reference to context memory
+        * @param key Key in context memory whose value is the array's length. If
+        * the key doesn't end in "_length", then "_length is appended.
+        * @param log Reference to Logger to log to
+        * @return The array length or 0 if the key is not found in context memory.
+        * @since 1.0
+        */
+       public static final int getArrayLength( SvcLogicContext ctx, String key ) {
+               return getArrayLength(ctx, key, null, null, null);
+       }
+
+       /**
+        * Utility function used to get an array's length from context memory.
+        * Will return 0 if key doesn't exist in context memory or isn't numeric
+        * and print the provided log message to the configured log file.
+        * <p>
+        * Use to obtain a context memory array length without having to worry
+        * about throwing a NumberFormatException.
+        * @param ctx Reference to context memory.
+        * @param key Key in context memory whose value is the array's length. If
+        * the key doesn't end in "_length", then "_length is appended.
+        * @param log Reference to Logger to log to. Doesn't log if null.
+        * @param logLevel Logging level to log the message at if the context
+        * memory key isn't found. Doesn't log if null.
+        * @param log_message Message to log if the context memory key isn't found.
+        * Doesn't log if null.
+        * @return The array length or 0 if the key is not found in context memory.
+        * @since 1.0
+        */
+       public static final int getArrayLength( SvcLogicContext ctx, String key, Logger log, LogLevel logLevel, String log_message ) {
+               String ctxKey = ( key.endsWith("_length") ) ? key : key + "_length";
+               try {
+                       return Integer.parseInt(ctx.getAttribute(ctxKey));
+               }
+               catch( NumberFormatException e ) {
+                       if( log != null && logLevel != null && log_message != null ) {
+                               switch( logLevel ) {
+                                       case TRACE:
+                                               log.trace(log_message);
+                                       case DEBUG:
+                                               log.debug(log_message);
+                                               break;
+                                       case INFO:
+                                               log.info(log_message);
+                                               break;
+                                       case WARN:
+                                               log.warn(log_message);
+                                               break;
+                                       case ERROR:
+                                               log.error(log_message);
+                                               break;
+                               }
+                       }
+               }
+
+               return 0;
+       }
+
+       /**
+        * Prints sorted context memory key-value pairs to the log file at the log
+        * level. Returns immediately if the log level isn't enabled.
+        * <p>
+        * O(n log(n)) time where n = size of context memory
+        * @param ctx Reference to context memory
+        * @param log Reference to Logger to log to
+        * @param logLevel Logging level to log the context memory key-value pairs
+        * at.
+        * @since 1.0
+        */
+       public static final void logContextMemory( SvcLogicContext ctx, Logger log, LogLevel logLevel ) {
+               logLevelIsEnabled( log, logLevel );
+
+               // Print sorted context memory key-value pairs to the log
+               ArrayList<String> keys = new ArrayList<String>(ctx.getAttributeKeySet());
+               Collections.sort(keys);
+               for( String key : keys ) {
+                       logMessageAtLevel( log, logLevel, key + " = " + ctx.getAttribute(key) );
+               }
+       }
+
+
+
+       // ========== PRIVATE FUNCTIONS ==========
+
+       // TODO: javadoc
+       /**
+        *
+        * @param parameters
+        * @param log
+        * @param loglevel
+        * @since 7.0.1
+        */
+       public static final void logExecuteNodeParameters( Map<String,String> parameters, Logger log, LogLevel loglevel ) {
+               logLevelIsEnabled( log, loglevel );
+
+               for( Map.Entry<String,String> param : parameters.entrySet() ) {
+                       logMessageAtLevel( log, loglevel, "PARAM: " + param.getKey() + " = " + param.getValue() );
+               }
+       }
+
+       // TODO: javadoc
+       /**
+        * Returns true if the loglevel is enabled. Otherwise, returns false.
+        * @param log Reference to logger
+        * @param loglevel Log level to check if enabled
+        * @return True if the loglevel is enabled. Otherwise, false
+        * @since 7.0.1
+        */
+       private static final boolean logLevelIsEnabled( Logger log, LogLevel loglevel ) {
+               // Return immediately if logging level isn't enabled
+               switch( loglevel ) {
+                       case TRACE:
+                               if( log.isTraceEnabled() ) { return true; }
+                               return false;
+                       case DEBUG:
+                               if( log.isDebugEnabled() ) { return true; }
+                               return false;
+                       case INFO:
+                               if( log.isInfoEnabled() ) { return true; }
+                               return false;
+                       case WARN:
+                               if( log.isWarnEnabled() ) { return true; }
+                               return false;
+                       case ERROR:
+                               if( log.isErrorEnabled() ) { return true; }
+                               return false;
+                       default:
+                               throw new IllegalArgumentException("Unknown LogLevel: " + loglevel.toString());
+               }
+       }
+
+       // TODO: javadoc
+       /**
+        *
+        * @param log
+        * @param loglevel
+        * @param msg
+        * @since 7.0.1
+        */
+       private static final void logMessageAtLevel( Logger log, LogLevel loglevel, String msg ) {
+               switch( loglevel ) {
+                       case TRACE:
+                               log.trace(msg);
+                               return;
+                       case DEBUG:
+                               log.debug(msg);
+                               return;
+                       case INFO:
+                               log.info(msg);
+                               return;
+                       case WARN:
+                               log.warn(msg);
+                               return;
+                       case ERROR:
+                               log.error(msg);
+                               return;
+               }
+       }
+
+
+
+       // ========== LOCAL CLASSES ==========
+
+       private class SortableCtxListElement implements Comparable<SortableCtxListElement> {
+               HashMap<String,String> child_elements = new HashMap<String,String>();
+               String[] sort_fields;
+
+               public SortableCtxListElement( SvcLogicContext ctx, String root, String[] sort_fields ) {
+                       this.sort_fields = sort_fields;
+
+                       for( String key : ctx.getAttributeKeySet() ) {
+                               if( key.startsWith(root) ) {
+                                       if( key.length() == root.length() ) {
+                                               child_elements.put("", ctx.getAttribute(key));
+                                               break;
+                                       }
+                                       else {
+                                               child_elements.put(key.substring(root.length()+1), ctx.getAttribute(key));
+                                       }
+                               }
+                       }
+               }
+
+               @Override
+               public int compareTo(SortableCtxListElement arg0) {
+                       if( sort_fields == null ) {
+                               return this.child_elements.get("").compareTo(arg0.child_elements.get(""));
+                       }
+
+                       for( String field : this.sort_fields ) {
+                               int result = this.child_elements.get(field).compareTo(arg0.child_elements.get(field));
+                               if( result != 0 ) {
+                                       return result;
+                               }
+                       }
+
+                       return 0;
+               }
+       }
+
+       /**
+     * Creates a file that contains the content of context memory.
+     * @param parameters - must contain the parameter filename
      * @param ctx Reference to context memory
-     * @param pfx Prefix of key-value pairs to remove
-     * @since 1.0
-     */
-    public static final void ctxBulkErase( SvcLogicContext ctx, String pfx ) {
-        ArrayList<String> Keys = new ArrayList<>( ctx.getAttributeKeySet() );
-        for( String key : Keys ) {
-            if( key.startsWith( pfx ) ) {
-                ctx.setAttribute( pfx + key.substring(pfx.length()) , null);
-            }
-        }
-    }
-
-    /**
-     * Copies all context memory key-value pairs that start with src_pfx to
-     * the keys that start with dest_pfx + suffix, where suffix is the result
-     * of {@code key.substring(src_pfx.length())}.
-     * <p>
-     * Does NOT guarantee removal of all keys at the destination before
-     * copying, but will overwrite any destination keys that have a
-     * corresponding source key. Use {@link #ctxBulkErase(SvcLogicContext, String) ctxBulkErase}
-     * before copy to erase destination root before copying from source.
-     * @param ctx Reference to context memory.
-     * @param src_pfx Prefix of the keys to copy values from.
-     * @param dest_pfx Prefix of the keys to copy values to.
-     * @since 1.0
-     */
-    public static final void ctxBulkCopy( SvcLogicContext ctx, String src_pfx, String dest_pfx ) {
-        // Remove trailing period from dest_pfx
-        if( dest_pfx.charAt(dest_pfx.length()-1) == '.' ) {
-            dest_pfx = dest_pfx.substring(0,dest_pfx.length()-1);
-        }
-
-        // For each context key that begins with src_pfx, set the value of the
-        // key dest_pfx + the suffix of the key to the key's value
-        ArrayList<String> Keys = new ArrayList<>(ctx.getAttributeKeySet());
-        for( String key : Keys ) {
-            if( key.startsWith(src_pfx) ) {
-                // Get suffix (no leading period)
-                String suffix = key.substring(src_pfx.length());
-                if( suffix.charAt(0) == '.') {
-                    suffix = suffix.substring(1);
-                }
-
-                // Set destination's value to key's value
-                ctx.setAttribute(dest_pfx + '.' + suffix, ctx.getAttribute(key));
-            }
-        }
-    }
-
-    /**
-     * Creates and returns a {@code Map<String, String>} that is a subset of
-     * context memory where all keys begin with the prefix.
-     * @param ctx Reference to context memory.
-     * @param prefix Returned map's keys should all begin with this value.
-     * @return A {@code Map<String, String>} containing all the key-value pairs
-     * in ctx whose key begins with prefix.
-     */
-    public static final Map<String, String> ctxGetBeginsWith( SvcLogicContext ctx, String prefix ) {
-        Map<String, String> prefixMap = new HashMap<>();
-
-        for( String key : ctx.getAttributeKeySet() ) {
-            if( key.startsWith(prefix) ) {
-                prefixMap.put( key, ctx.getAttribute(key) );
-            }
-        }
-
-        return prefixMap;
-    }
-
-    /**
-     * Returns true if key's value in context memory is "" or if it doesn't
-     * exist in context memory.
-     * @param ctx Reference to context memory.
-     * @param key Key to search for.
-     * @return true if key's value in context memory is "" or if it doesn't
-     * exist in context memory.
-     * @since 1.0
-     */
-    public static final boolean ctxKeyEmpty( SvcLogicContext ctx, String key ) {
-        String value = ctx.getAttribute(key);
-        return value == null || value.isEmpty();
-    }
-
-    /**
-     * Adds all key-value pairs in the entries Map to context memory.
-     * @param ctx Reference to context memory. Value's {@code toString()}
-     * function is used to add it.
-     * @param entries {@code Map<String, ?>} of key-value pairs to add to
-     * context memory. Value's {@code toString()} function is used to add it.
-     * @return Reference to context memory to be used for function chaining.
+     * @throws SvcLogicException thrown if file cannot be created or if parameters are missing
      */
-    public static final SvcLogicContext ctxPutAll( SvcLogicContext ctx, Map<String, ?> entries ) {
-        for( Map.Entry<String, ?> entry : entries.entrySet() ) {
-            ctxSetAttribute( ctx, entry.getKey(), entry.getValue() );
-            //ctx.setAttribute(entry.getKey(), entry.getValue().toString());
-        }
-
-        return ctx;
-    }
-
-    /**
-     * Sets a key in context memory to the output of object's toString(). The
-     * key is deleted from context memory if object is null.
-     * @param ctx Reference to context memory.
-     * @param key Key to set.
-     * @param object Object whose toString() will be the value set
-     */
-    public static final void ctxSetAttribute( SvcLogicContext ctx, String key, Object object ) {
-        if( object == null ) {
-            ctx.setAttribute(key, null);
-        }
-        else {
-            ctx.setAttribute(key, object.toString());
-        }
-    }
-
-    /**
-     * Sets a key in context memory to the output of object's toString().
-     * <p>
-     * The key is deleted from context memory if object is null. The key and
-     * value set in context memory are logged to the Logger at the provided
-     * logLevel level.
-     * @param <O> Any Java object
-     * @param ctx Reference to context memory.
-     * @param key Key to set.
-     * @param obj Object whose toString() will be the value set
-     * @param LOG Logger to log to
-     * @param logLevel level to log at in Logger
+       public static void printContext(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+               if (parameters == null || parameters.keySet().size() < 1) {
+                       throw new SvcLogicException("no parameters passed");
+               }
+
+               checkParameters(parameters, new String[]{"filename"}, LOG);
+
+               String fileName = parameters.get("filename");
+
+               PrintStream pstr = null;
+
+               try {
+                       pstr = new PrintStream(new FileOutputStream(new File(fileName), true));
+               } catch (Exception e) {
+                       throw new SvcLogicException("Cannot open file " + fileName, e);
+               }
+               pstr.println("#######################################");
+               for (String attr : ctx.getAttributeKeySet()) {
+                       pstr.println(attr + " = " + ctx.getAttribute(attr));
+               }
+               pstr.flush();
+               pstr.close();
+       }
+
+        /**
+     * Checks context memory for a set of required parameters
+     * Every parameter aside from prefix will be treated as mandatory
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>prefix</td><td>Optional</td><td>the prefix will be added to each parameter</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
      */
-    public static final <O extends Object> void ctxSetAttribute( SvcLogicContext ctx, String key, O obj, Logger LOG, LogLevel logLevel ) {
-        String value = Objects.toString( obj, null );
-        ctx.setAttribute( key, value );
-        if( logLevelIsEnabled(LOG, logLevel ) ) {
-            if( value == null ) {
-                logMessageAtLevel( LOG, logLevel, "Deleting " + key );
+       public static void requiredParameters(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+               if (parameters == null || parameters.keySet().size() < 1) {
+            String errorMessage = "requiredParameters should not be called if the parameters hashmap is null or empty!";
+            LOG.error(errorMessage);
+            throw new SvcLogicException(errorMessage);
+               }
+               String prefixValue = null;
+               String prefix = "prefix";
+               if(parameters.containsKey(prefix)){
+                   prefixValue = parameters.get(prefix);
+                   parameters.remove(prefix);
+               }
+               checkParameters(prefixValue, ctx.getAttributeKeySet(), parameters.keySet(), LOG);
+       }
+
+    private static void checkParameters(String prefixValue, Set<String> ctx, Set<String> parameters, Logger log) throws SvcLogicException {
+        for (String param : parameters) {
+            if (prefixValue != null) {
+                param = prefixValue + param;
             }
-            else {
-                logMessageAtLevel( LOG, logLevel, "Setting " + key + " = " + value );
+            if (!ctx.contains(param)) {
+                String errorMessage = "This method requires the parameters [" + StringUtils.join(parameters, ",")
+                        + "], but " + param + " was not passed in.";
+                log.error(errorMessage);
+                throw new SvcLogicException(errorMessage);
             }
         }
     }
 
     /**
-     * Utility function used to get an array's length from context memory.
-     * Will return 0 if key doesn't exist in context memory or isn't numeric.
-     * <p>
-     * Use to obtain a context memory array length without having to worry
-     * about throwing a NumberFormatException.
-     * @param ctx Reference to context memory
-     * @param key Key in context memory whose value is the array's length. If
-     * the key doesn't end in "_length", then "_length is appended.
-     * @param log Reference to Logger to log to
-     * @return The array length or 0 if the key is not found in context memory.
-     * @since 1.0
+     *  is in a different DG invocation just before/after we call NCS and set the state to InProgress
      */
-    public static final int getArrayLength( SvcLogicContext ctx, String key ) {
-        return getArrayLength(ctx, key, null, null, null);
-    }
-
     /**
-     * Utility function used to get an array's length from context memory.
-     * Will return 0 if key doesn't exist in context memory or isn't numeric
-     * and print the provided log message to the configured log file.
-     * <p>
-     * Use to obtain a context memory array length without having to worry
-     * about throwing a NumberFormatException.
-     * @param ctx Reference to context memory.
-     * @param key Key in context memory whose value is the array's length. If
-     * the key doesn't end in "_length", then "_length is appended.
-     * @param log Reference to Logger to log to. Doesn't log if null.
-     * @param logLevel Logging level to log the message at if the context
-     * memory key isn't found. Doesn't log if null.
-     * @param log_message Message to log if the context memory key isn't found.
-     * Doesn't log if null.
-     * @return The array length or 0 if the key is not found in context memory.
-     * @since 1.0
-     */
-    public static final int getArrayLength( SvcLogicContext ctx, String key, Logger log, LogLevel logLevel, String log_message ) {
-        String ctxKey = key.endsWith("_length") ? key : key + "_length";
+    * setTime write the current date time to a string located at outputPath
+    * @param parameters - requires outputPath to not be null
+    * @param ctx Reference to context memory
+    * @throws SvcLogicException if a required parameter is missing an exception is thrown
+    */
+    public static void setTime(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException
+    {
+        checkParameters(parameters, new String[] { "outputPath" }, LOG);
+
+        // Set the DateFormat
+        // "2015-03-16T12:18:35.138Z"
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+
+        // Parse the date
+        String ctxVariable = parameters.get("outputPath");
         try {
-            return Integer.parseInt(ctx.getAttribute(ctxKey));
-        }
-        catch( NumberFormatException e ) {
-            if( log != null && logLevel != null && log_message != null ) {
-                switch( logLevel ) {
-                    case TRACE:
-                        log.trace(log_message);
-                    case DEBUG:
-                        log.debug(log_message);
-                        break;
-                    case INFO:
-                        log.info(log_message);
-                        break;
-                    case WARN:
-                        log.warn(log_message);
-                        break;
-                    case ERROR:
-                        log.error(log_message);
-                        break;
-                }
-            }
-        }
-
-        return 0;
-    }
-
-    /**
-     * Prints sorted context memory key-value pairs to the log file at the log
-     * level. Returns immediately if the log level isn't enabled.
-     * <p>
-     * O(n log(n)) time where n = size of context memory
-     * @param ctx Reference to context memory
-     * @param log Reference to Logger to log to
-     * @param logLevel Logging level to log the context memory key-value pairs
-     * at.
-     * @since 1.0
-     */
-    public static final void logContextMemory( SvcLogicContext ctx, Logger log, LogLevel logLevel ) {
-        logLevelIsEnabled( log, logLevel );
-
-        // Print sorted context memory key-value pairs to the log
-        ArrayList<String> keys = new ArrayList<>(ctx.getAttributeKeySet());
-        Collections.sort(keys);
-        for( String key : keys ) {
-            logMessageAtLevel( log, logLevel, key + " = " + ctx.getAttribute(key) );
-        }
-    }
-
-
-
-    // ========== PRIVATE FUNCTIONS ==========
-
-    // TODO: javadoc
-    /**
-     *
-     * @param parameters
-     * @param log
-     * @param loglevel
-     * @since 7.0.1
-     */
-    public static final void logExecuteNodeParameters( Map<String,String> parameters, Logger log, LogLevel loglevel ) {
-        logLevelIsEnabled( log, loglevel );
-
-        for( Map.Entry<String,String> param : parameters.entrySet() ) {
-            logMessageAtLevel( log, loglevel, "PARAM: " + param.getKey() + " = " + param.getValue() );
-        }
-    }
-
-    // TODO: javadoc
-    /**
-     * Returns true if the loglevel is enabled. Otherwise, returns false.
-     * @param log Reference to logger
-     * @param loglevel Log level to check if enabled
-     * @return True if the loglevel is enabled. Otherwise, false
-     * @since 7.0.1
-     */
-    private static final boolean logLevelIsEnabled( Logger log, LogLevel loglevel ) {
-        // Return immediately if logging level isn't enabled
-        switch( loglevel ) {
-            case TRACE:
-                if( log.isTraceEnabled() ) { return true; }
-                return false;
-            case DEBUG:
-                if( log.isDebugEnabled() ) { return true; }
-                return false;
-            case INFO:
-                if( log.isInfoEnabled() ) { return true; }
-                return false;
-            case WARN:
-                if( log.isWarnEnabled() ) { return true; }
-                return false;
-            case ERROR:
-                if( log.isErrorEnabled() ) { return true; }
-                return false;
-            default:
-                throw new IllegalArgumentException("Unknown LogLevel: " + loglevel.toString());
-        }
-    }
-
-    // TODO: javadoc
-    /**
-     *
-     * @param log
-     * @param loglevel
-     * @param msg
-     * @since 7.0.1
-     */
-    private static final void logMessageAtLevel( Logger log, LogLevel loglevel, String msg ) {
-        switch( loglevel ) {
-            case TRACE:
-                log.trace(msg);
-                return;
-            case DEBUG:
-                log.debug(msg);
-                return;
-            case INFO:
-                log.info(msg);
-                return;
-            case WARN:
-                log.warn(msg);
-                return;
-            case ERROR:
-                log.error(msg);
-                return;
-        }
-    }
-
-
-
-    // ========== LOCAL CLASSES ==========
-
-    private class SortableCtxListElement implements Comparable<SortableCtxListElement> {
-        HashMap<String,String> child_elements = new HashMap<>();
-        String[] sort_fields;
-
-        public SortableCtxListElement( SvcLogicContext ctx, String root, String[] sort_fields ) {
-            this.sort_fields = sort_fields;
-
-            for( String key : ctx.getAttributeKeySet() ) {
-                if( key.startsWith(root) ) {
-                    if( key.length() == root.length() ) {
-                        child_elements.put("", ctx.getAttribute(key));
-                        break;
-                    }
-                    else {
-                        child_elements.put(key.substring(root.length()+1), ctx.getAttribute(key));
-                    }
-                }
-            }
-        }
-
-        @Override
-        public int compareTo(SortableCtxListElement arg0) {
-            if( sort_fields == null ) {
-                return this.child_elements.get("").compareTo(arg0.child_elements.get(""));
-            }
-
-            for( String field : this.sort_fields ) {
-                int result = this.child_elements.get(field).compareTo(arg0.child_elements.get(field));
-                if( result != 0 ) {
-                    return result;
-                }
-            }
-
-            return 0;
+            String dateTime = format.format(new Date());
+            ctx.setAttribute(ctxVariable, dateTime);
+        } catch (Exception ex) {
+            throw new SvcLogicException("problem with setTime", ex);
         }
     }
 }
index 27addba..e0568ab 100644 (file)
 
 package org.openecomp.sdnc.sli.SliPluginUtils;
 
-
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Properties;
@@ -32,55 +35,59 @@ import org.osgi.framework.ServiceRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 public class SliPluginUtilsActivator implements BundleActivator {
-
-//    private static final String SLIPLUGINUTILS_PROP_VAR = "/slipluginutils.properties";
-//    private static final String SDNC_CONFIG_DIR = "SDNC_CONFIG_DIR";
-
-    @SuppressWarnings("rawtypes")
-    private final List<ServiceRegistration> registrations = new LinkedList<>();
+    @SuppressWarnings("rawtypes") private List<ServiceRegistration> registrations = new LinkedList<ServiceRegistration>();
 
     private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtilsActivator.class);
+    private static final String SDNC_ROOT_DIR = "SDNC_CONFIG_DIR";
+    private static final String DME2_PROPERTIES_FILE_NAME = "dme2.properties";
 
     @Override
     public void start(BundleContext ctx) throws Exception {
-        // Read properties
-        Properties props = new Properties();
-
-        // ---uncomment below when adding properties file---
-        /*
-        String propDir = System.getenv(SDNC_CONFIG_DIR);
-        if (propDir == null) {
-            throw new ConfigurationException(
-            "Cannot find config file - " + SLIPLUGINUTILS_PROP_VAR + " and " + SDNC_CONFIG_DIR + " unset");
-        }
-        String propPath = propDir + SLIPLUGINUTILS_PROP_VAR;
-
-        File propFile = new File(propPath);
+        SliPluginUtils plugin = new SliPluginUtils(new Properties());
+        LOG.info("Registering service " + plugin.getClass().getName());
+        registrations.add(ctx.registerService(plugin.getClass().getName(), plugin, null));
 
-        if (!propFile.exists()) {
-            throw new ConfigurationException("Missing configuration properties file : " + propFile);
-        }
+        SliStringUtils sliStringUtils_Plugin = new SliStringUtils();
+        LOG.info("Registering service " + sliStringUtils_Plugin.getClass().getName());
+        registrations.add(ctx.registerService(sliStringUtils_Plugin.getClass().getName(), sliStringUtils_Plugin, null));
 
         try {
-            props.load(new FileInputStream(propFile));
+            String path = System.getenv(SDNC_ROOT_DIR) + File.separator + DME2_PROPERTIES_FILE_NAME;
+            DME2 dmePlugin = initDme2(path);
+            if (dmePlugin != null) {
+                LOG.info("Registering service " + dmePlugin.getClass().getName());
+                registrations.add(ctx.registerService(dmePlugin.getClass().getName(), dmePlugin, null));
+            }
         } catch (Exception e) {
-            throw new ConfigurationException("Could not load properties file " + propPath, e);
+            LOG.error("DME2 plugin could not be started", e);
         }
-        */
+    }
 
-        SliPluginUtils plugin = new SliPluginUtils(props);
+    public DME2 initDme2(String pathToDmeProperties) {
+        Properties dme2properties = new Properties();
+        String loadPropertiesErrorMessage = "Couldn't load DME2 properties at path " + pathToDmeProperties;
+        File dme2propertiesFile = new File(pathToDmeProperties);
 
-        LOG.info("Registering service "+plugin.getClass().getName());
-        registrations.add(ctx.registerService(plugin.getClass().getName(), plugin, null));
+        try {
+            dme2properties.load(new FileReader(dme2propertiesFile));
+            String proxyUrlProperty = dme2properties.getProperty("proxyUrl");
+            String[] proxyUrls = proxyUrlProperty.split(",");
+            DME2 dmePlugin = new DME2(dme2properties.getProperty("aafUserName"), dme2properties.getProperty("aafPassword"), dme2properties.getProperty("envContext"), dme2properties.getProperty("routeOffer"), proxyUrls, dme2properties.getProperty("commonServiceVersion"));
+            dmePlugin.setPartner(dme2properties.getProperty("partner"));
+            return dmePlugin;
+        } catch (FileNotFoundException e) {
+            LOG.error(loadPropertiesErrorMessage);
+        } catch (IOException e) {
+            LOG.error(loadPropertiesErrorMessage);
+        }
+        LOG.error("Couldn't create DME2 plugin");
+        return null;
     }
 
     @Override
     public void stop(BundleContext ctx) throws Exception {
-
-        for (@SuppressWarnings("rawtypes") ServiceRegistration registration: registrations)
-        {
+        for (@SuppressWarnings("rawtypes") ServiceRegistration registration : registrations) {
             registration.unregister();
             registration = null;
         }
diff --git a/sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/SliStringUtils.java b/sliPluginUtils/provider/src/main/java/org/openecomp/sdnc/sli/SliPluginUtils/SliStringUtils.java
new file mode 100644 (file)
index 0000000..43af6f5
--- /dev/null
@@ -0,0 +1,396 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.SliPluginUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A SvcLogicJavaPlugin that exposes java.lang.String functions to DirectedGraph
+ */
+public class SliStringUtils implements SvcLogicJavaPlugin {
+       private static final Logger LOG = LoggerFactory.getLogger(SliStringUtils.class);
+
+       public SliStringUtils() {}
+
+       /**
+        * Provides split functionality to Directed Graphs.
+        * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+        * <table border="1">
+        *      <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+        *      <tbody>
+        *              <tr><td>original_string</td><td>Mandatory</td><td>String to perform split on</td></tr>
+        *              <tr><td>regex</td><td>Mandatory</td><td>the delimiting regular expression</td></tr>
+        *              <tr><td>limit</td><td>Optional</td><td>result threshold. See String.split method for further description. Defaults to 0</td></tr>
+        *              <tr><td>ctx_memory_result_key</td><td>Mandatory</td><td>Key in context memory to populate the resulting array of strings under</td></tr>
+        *      </tbody>
+        * </table>
+        * @param ctx Reference to context memory
+        * @throws SvcLogicException
+        * @since 11.0.2
+        * @see String#split(String, int)
+        */
+       public void split( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
+               final String original_string = parameters.get("original_string");
+               LOG.trace("original_string = " + original_string);
+               final String regex = parameters.get("regex");
+               LOG.trace("regex = " + regex);
+               final String limit_str = parameters.get("limit");
+               LOG.trace("limit_str = " + limit_str);
+               final String ctx_memory_result_key = parameters.get("ctx_memory_result_key");
+               LOG.trace("ctx_memory_result_key = " + ctx_memory_result_key);
+
+               try {
+                       // Validation that parameters are not null
+                       SliPluginUtils.checkParameters( parameters, new String[]{"original_string","regex","ctx_memory_result_key"}, LOG );
+
+                       // Read limit from context memory. Default to 0 if null/empty
+                       int limit = 0;
+                       if( StringUtils.isNotEmpty(limit_str) ) {
+                               try {
+                                       limit = Integer.parseInt(limit_str);
+                               }
+                               catch( NumberFormatException e ) {
+                                       throw new IllegalArgumentException( "The limit parameter of the SliStringUtils.split() function must be a number, empty string, or null", e );
+                               }
+                       }
+
+                       // Call String.split(regex,limit) on string passed in
+                       String[] split_string = original_string.split(regex, limit);
+
+                       // Populate context memory with results
+                       for( int i = 0; i < split_string.length; i++ ) {
+                               SliPluginUtils.ctxSetAttribute(ctx, ctx_memory_result_key + '[' + i + ']', split_string[i], LOG, SliPluginUtils.LogLevel.DEBUG);
+                       }
+                       SliPluginUtils.ctxSetAttribute(ctx, ctx_memory_result_key + "_length", new Integer(split_string.length), LOG, SliPluginUtils.LogLevel.DEBUG);
+               }
+               catch( Exception e ) {
+                       // Have error message print parameters
+                       throw new SvcLogicException( "An error occurred during SliStringUtils.split() where original_string = " + quotedOrNULL(regex) +
+                                       " regex = " + quotedOrNULL(regex) +
+                                       " limit = " + quotedOrNULL(regex) +
+                                       " ctx_memory_result_key = " + quotedOrNULL(regex), e );
+               }
+       }
+
+       private static String quotedOrNULL( String str ) {
+               return (str == null) ? "NULL" : '"' + str + '"';
+       }
+
+    /**
+     * exposes equalsIgnoreCase to directed graph
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * emits a true or false outcome
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>target</td><td>Mandatory</td><td>target string</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static String equalsIgnoreCase(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","target"}, LOG);
+        if(parameters.get("source").equalsIgnoreCase(parameters.get("target"))){
+            return "true";
+        }
+        return "false";
+    }
+
+    /**
+     * exposes toUpperCase to directed graph
+     * writes an upperCase version of source to outputPath
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>outputPath</td><td>Mandatory</td><td>the location in context memory the result is written to</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static void toUpper(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","outputPath"}, LOG);
+        ctx.setAttribute(parameters.get("outputPath"), parameters.get("source").toUpperCase());
+    }
+
+    /**
+     * exposes toLowerCase to directed graph
+     * writes a lowerCase version of source to outputPath
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>outputPath</td><td>Mandatory</td><td>the location in context memory the result is written to</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static void toLower(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","outputPath"}, LOG);
+        ctx.setAttribute(parameters.get("outputPath"), parameters.get("source").toLowerCase());
+    }
+
+    /**
+     * exposes contains to directed graph to test if one string contains another
+     * tests if the source contains the target
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * emits a true or false outcome
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>target</td><td>Mandatory</td><td>target string</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static String contains(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","target"}, LOG);
+        if(parameters.get("source").contains(parameters.get("target"))){
+            return "true";
+        }
+        return "false";
+    }
+
+    /**
+     * exposes endsWith to directed graph to test if one string endsWith another string
+     * tests if the source ends with the target
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * emits a true or false outcome
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>target</td><td>Mandatory</td><td>target string</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static String endsWith(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","target"}, LOG);
+        if(parameters.get("source").endsWith(parameters.get("target"))){
+            return "true";
+        }
+        return "false";
+    }
+
+    /**
+     * exposes startsWith to directed graph to test if one string endsWith another string
+     * tests if the source ends with the target
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * emits a true or false outcome
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>target</td><td>Mandatory</td><td>target string</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static String startsWith(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","target"}, LOG);
+        if(parameters.get("source").startsWith(parameters.get("target"))){
+            return "true";
+        }
+        return "false";
+    }
+
+    /**
+     * exposes trim to directed graph
+     * writes a trimmed version of the string to the outputPath
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>outputPath</td><td>Mandatory</td><td>the location in context memory the result is written to</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static void trim(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","outputPath"}, LOG);
+        ctx.setAttribute(parameters.get("outputPath"), parameters.get("source").trim());
+    }
+
+    /**
+     * exposes String.length() to directed graph
+     * writes the length of source to outputPath
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>outputPath</td><td>Mandatory</td><td>the location in context memory the result is written to</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static void getLength(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","outputPath"}, LOG);
+        ctx.setAttribute(parameters.get("outputPath"), String.valueOf(parameters.get("source").length()));
+    }
+
+    /**
+     * exposes replace to directed graph
+     * writes the length of source to outputPath
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>target</td><td>Mandatory</td><td>The sequence of char values to be replaced</td></tr>
+     *      <tr><td>replacement</td><td>Mandatory</td><td>The replacement sequence of char values</td></tr>
+     *      <tr><td>outputPath</td><td>Mandatory</td><td>the location in context memory the result is written to</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static void replace(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[]{"source","outputPath","target","replacement"}, LOG);
+        ctx.setAttribute(parameters.get("outputPath"), (parameters.get("source").replace(parameters.get("target"), parameters.get("replacement"))));
+    }
+
+    /**
+     * Provides substring functionality to Directed Graphs.
+     * <p>
+     * Calls either String.substring(String beginIndex) or
+     * String.substring(String beginInded, String endIndex) if the end-index
+     * is present or not.
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>string</td><td>Mandatory</td><td>String to perform substring on</td></tr>
+     *      <tr><td>result</td><td>Mandatory</td><td>Key in context memory to populate the resulting string in</td></tr>
+     *      <tr><td>begin-index</td><td>Mandatory</td><td>Beginning index to pass to Java substring function</td></tr>
+     *      <tr><td>end-index</td><td>Optional</td><td>Ending index to pass to Java substring function. If not included, String.substring(begin) will be called.</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public void substring( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
+        try {
+            SliPluginUtils.checkParameters( parameters, new String[]{"string","begin-index","result"}, LOG );
+            final String string = parameters.get("string");
+            final String result = parameters.get("result");
+            final String begin = parameters.get("begin-index");
+            final String end = parameters.get("end-index");
+            if( StringUtils.isEmpty(end) ) {
+                ctx.setAttribute( result, string.substring(Integer.parseInt(begin)) );
+            }
+            else {
+                ctx.setAttribute( result, string.substring(Integer.parseInt(begin), Integer.parseInt(end)) );
+            }
+        }
+        catch( Exception e ) {
+            throw new SvcLogicException( "An error occurred while the Directed Graph was performing a substring", e );
+        }
+    }
+
+    /**
+     * Provides concat functionality to Directed Graphs.
+     * <p>
+     * Will concat target to source and write the result to outputPath
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>target</td><td>Mandatory</td><td>The sequence of char values to be replaced</td></tr>
+     *      <tr><td>outputPath</td><td>Mandatory</td><td>the location in context memory the result is written to</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     * @since 11.0.2
+     */
+    public static void concat( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
+            SliPluginUtils.checkParameters( parameters, new String[]{"source","target","outputPath"}, LOG );
+            String result = parameters.get("source").concat(parameters.get("target"));
+            ctx.setAttribute(parameters.get("outputPath"), result);
+    }
+
+    /**
+     * Provides url encoding functionality to Directed Graphs.
+     * <p>
+     * Will url encode the source and write the result to outputPath
+     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
+     *  <tbody>
+     *      <tr><td>source</td><td>Mandatory</td><td>source string</td></tr>
+     *      <tr><td>encoding</td><td>Optional</td><td>the name of a supported character encoding, defaulted to UTF-8 if not supplied</td></tr>
+     *      <tr><td>outputPath</td><td>Mandatory</td><td>the location in context memory the result is written to</td></tr>
+     *  </tbody>
+     * </table>
+     * @param ctx Reference to context memory
+     * @throws SvcLogicException
+     */
+    public static void urlEncode(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
+        SliPluginUtils.checkParameters(parameters, new String[] { "source", "outputPath" }, LOG);
+        String encoding = parameters.get("encoding");
+        if (encoding == null) {
+            encoding = "UTF-8";
+        }
+        try {
+            String result = URLEncoder.encode(parameters.get("source"), encoding);
+            ctx.setAttribute(parameters.get("outputPath"), result);
+        } catch (UnsupportedEncodingException e) {
+            throw new SvcLogicException("Url encode failed.", e);
+        }
+    }
+
+}
index 22f07f9..89a4a98 100644 (file)
@@ -60,14 +60,14 @@ public class SvcLogicContextList {
 
         // Initialize list
         int capacity = getCtxListLength(ctx, prefix);
-        this.list = new ArrayList<>( capacity );
+        this.list = new ArrayList<HashMap<String, String>>(capacity);
         for( int i = 0; i < capacity; i++ ) {
             this.list.add(i, new HashMap<String,String>());
         }
 
         // Populate "elements" in list
         String prefix_bracket = this.prefix + '[';
-        for( String key : new HashSet<>(ctx.getAttributeKeySet()) ) {
+        for (String key : new HashSet<String>(ctx.getAttributeKeySet())) {
             if( key.startsWith(prefix_bracket) ) {
                 // Extract the index of the list
                 int index = getCtxListIndex(key, this.prefix, capacity);
@@ -160,8 +160,7 @@ public class SvcLogicContextList {
             for( Map.Entry<String,String> entry : this.list.get(i).entrySet() ) {
                 if( entry.getKey().equals("") ) {
                     ctx.setAttribute(prefix + '[' + i + ']', entry.getValue());
-                }
-                else {
+                } else {
                     ctx.setAttribute(prefix + '[' + i + "]." + entry.getKey(), entry.getValue());
                 }
             }
@@ -176,16 +175,9 @@ public class SvcLogicContextList {
     private static int getCtxListIndex( String key, String prefix, int list_size ) {
         int index = getCtxListIndex( key, prefix );
         if( index >= list_size ) {
-            throw new IllegalArgumentException(
-                    "Context memory list \"" + prefix + "[]\" contains an index >= the size of the list",
-                    new ArrayIndexOutOfBoundsException( "index \"" + index + "\" is outside the bounds of the context memory list \"" + prefix + "[]. List Length = " + list_size )
-            );
-        }
-        else if( index < 0 ) {
-            throw new IllegalArgumentException(
-                    "Context memory list \"" + prefix + "[]\" contains a negative index",
-                    new NegativeArraySizeException( "index \"" + index + "\" of context memory list is negative" )
-            );
+            throw new IllegalArgumentException("Context memory list \"" + prefix + "[]\" contains an index >= the size of the list", new ArrayIndexOutOfBoundsException("index \"" + index + "\" is outside the bounds of the context memory list \"" + prefix + "[]. List Length = " + list_size));
+        } else if (index < 0) {
+            throw new IllegalArgumentException("Context memory list \"" + prefix + "[]\" contains a negative index", new NegativeArraySizeException("index \"" + index + "\" of context memory list is negative"));
         }
 
         return index;
@@ -196,8 +188,7 @@ public class SvcLogicContextList {
         String ctx_index_str = StringUtils.substringBetween(key.substring(prefix.length()), "[", "]");
         try {
             return Integer.parseInt( ctx_index_str );
-        }
-        catch( NumberFormatException e ) {
+        } catch (NumberFormatException e) {
             throw new IllegalStateException("Could not parse index value \"" + ctx_index_str + "\" in context memory key \"" + key + "\"", e);
         }
     }
@@ -208,12 +199,10 @@ public class SvcLogicContextList {
         String _length_val_str = ctx.getAttribute(_length_key);
         try {
             return Integer.parseInt(_length_val_str);
-        }
-        catch( NumberFormatException e ) {
+        } catch (NumberFormatException e) {
             if( _length_val_str == null ) {
                 throw new IllegalStateException( "Could not find list length \"" + _length_key + "\" in context memory." );
-            }
-            else {
+            } else {
                 throw new IllegalStateException( "Could not parse index value \"" + _length_val_str + "\" of context memory list length \"" + _length_key + "\"" , e );
             }
         }
diff --git a/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/CheckParametersTest.java b/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/CheckParametersTest.java
new file mode 100644 (file)
index 0000000..318e464
--- /dev/null
@@ -0,0 +1,116 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.SliPluginUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CheckParametersTest {
+
+    @Test
+    public void nullRequiredParameters() throws Exception {
+        Map<String, String> parametersMap = new HashMap<String, String>();
+        String[] requiredParams = null;
+        Logger Log = LoggerFactory.getLogger(SliPluginUtils.class);
+        SliPluginUtils.checkParameters(parametersMap, requiredParams, Log);
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void emptyParametersMap() throws Exception {
+        Map<String, String> parametersMap = new HashMap<String, String>();
+        String[] requiredParams = new String[] { "param1", "param2", "param3" };
+        Logger Log = LoggerFactory.getLogger(SliPluginUtils.class);
+        SliPluginUtils.checkParameters(parametersMap, requiredParams, Log);
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void paramNotFound() throws Exception {
+        Map<String, String> parametersMap = new HashMap<String, String>();
+        parametersMap.put("tst", "me");
+        String[] requiredParams = new String[] { "param1", "parm2", "param3" };
+        Logger Log = LoggerFactory.getLogger(SliPluginUtils.class);
+        SliPluginUtils.checkParameters(parametersMap, requiredParams, Log);
+    }
+
+    @Test
+    public void testSunnyRequiredParameters() throws Exception {
+        SvcLogicContext ctx = new SvcLogicContext();
+        ctx.setAttribute("param1", "hello");
+        ctx.setAttribute("param2", "world");
+        ctx.setAttribute("param3", "!");
+
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("param1", "dog");
+        parameters.put("param2", "cat");
+        parameters.put("param3", "fish");
+
+        SliPluginUtils.requiredParameters(parameters, ctx);
+    }
+
+    @Test
+    public void testSunnyRequiredParametersWithPrefix() throws Exception {
+        String prefixValue = "my.unique.path.";
+        SvcLogicContext ctx = new SvcLogicContext();
+        ctx.setAttribute(prefixValue + "param1", "hello");
+        ctx.setAttribute(prefixValue + "param2", "world");
+        ctx.setAttribute(prefixValue + "param3", "!");
+
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("prefix", prefixValue);
+        parameters.put("param1", "dog");
+        parameters.put("param2", "cat");
+        parameters.put("param3", "fish");
+
+        SliPluginUtils.requiredParameters(parameters, ctx);
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void testRainyMissingRequiredParameters() throws Exception {
+        SvcLogicContext ctx = new SvcLogicContext();
+        ctx.setAttribute("param1", "hello");
+        ctx.setAttribute("param3", "!");
+
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("param1", null);
+        parameters.put("param2", null);
+        parameters.put("param3", null);
+
+        SliPluginUtils.requiredParameters(parameters, ctx);
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void testEmptyRequiredParameters() throws Exception {
+        SvcLogicContext ctx = new SvcLogicContext();
+        ctx.setAttribute("param1", "hello");
+        ctx.setAttribute("param3", "!");
+
+        Map<String, String> parameters = new HashMap<String, String>();
+
+        SliPluginUtils.requiredParameters(parameters, ctx);
+    }
+}
diff --git a/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/Dme2Test.java b/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/Dme2Test.java
new file mode 100644 (file)
index 0000000..d66b011
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.SliPluginUtils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openecomp.sdnc.sli.SliPluginUtils.DME2;
+import org.openecomp.sdnc.sli.SliPluginUtils.SliPluginUtilsActivator;
+
+public class Dme2Test {
+
+    @Test
+    public void createInstarUrl() {
+        String instarUrl = "http://localhost:25055/service=sample.com/services/eim/v1/rest/version=1702.0/envContext=TEST/routeOffer=DEFAULT/subContext=/enterpriseConnection/getEnterpriseConnectionDetails/v1?dme2.password=fake&dme2.username=user@sample.com";
+        DME2 dme = new DME2("user@sample.com", "fake", "TEST", "DEFAULT", new String[] { "http://localhost:25055" }, "common");
+        String constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(instarUrl, constructedUrl);
+    }
+
+    @Test
+    public void createInstarUrlNoSubContext() {
+        String instarUrl = "http://localhost:25055/service=sample.com/services/eim/v1/rest/version=1702.0/envContext=TEST/routeOffer=DEFAULT?dme2.password=fake&dme2.username=user@sample.com";
+        DME2 dme = new DME2("user@sample.com", "fake", "TEST", "DEFAULT", new String[] { "http://localhost:25055" }, "common");
+        Map<String, String> parameters = new HashMap<String, String>();
+        String constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", parameters.get(null));
+        assertEquals(instarUrl, constructedUrl);
+    }
+
+    @Test
+    public void testRoundRobin() {
+        String[] proxyHostNames = new String[] { "http://one:25055", "http://two:25055", "http://three:25055" };
+        String urlSuffix = "/service=sample.com/services/eim/v1/rest/version=1702.0/envContext=TEST/routeOffer=DEFAULT/subContext=/enterpriseConnection/getEnterpriseConnectionDetails/v1?dme2.password=fake&dme2.username=user@sample.com";
+        DME2 dme = new DME2("user@sample.com", "fake", "TEST", "DEFAULT", proxyHostNames, "common");
+        String constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(proxyHostNames[0] + urlSuffix, constructedUrl);
+        constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(proxyHostNames[1] + urlSuffix, constructedUrl);
+        constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(proxyHostNames[2] + urlSuffix, constructedUrl);
+        constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(proxyHostNames[0] + urlSuffix, constructedUrl);
+        constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(proxyHostNames[1] + urlSuffix, constructedUrl);
+        constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(proxyHostNames[2] + urlSuffix, constructedUrl);
+        constructedUrl = dme.constructUrl("sample.com/services/eim/v1/rest", "1702.0", "/enterpriseConnection/getEnterpriseConnectionDetails/v1");
+        assertEquals(proxyHostNames[0] + urlSuffix, constructedUrl);
+    }
+
+    @Test
+    public void createDme2EndtoEnd() {
+        SliPluginUtilsActivator activator = new SliPluginUtilsActivator();
+        DME2 dme2 = activator.initDme2("src/test/resources/dme2.e2e.properties");
+        assertEquals("user@sample.com", dme2.aafUserName);
+        assertEquals("fake", dme2.aafPassword);
+        assertEquals("UAT", dme2.envContext);
+        assertEquals("UAT", dme2.routeOffer);
+        Assert.assertArrayEquals("http://sample.com:25055,http://sample.com:25055".split(","), dme2.proxyUrls);
+        assertEquals("1702.0", dme2.commonServiceVersion);
+        assertEquals(null, dme2.partner);
+
+        String constructedUrl = dme2.constructUrl("sample.com/restservices/instar/v1/assetSearch", null, "/mySubContext");
+        assertNotNull(constructedUrl);
+        System.out.println(constructedUrl);
+    }
+
+    @Test
+    public void createDme2Prod() {
+        SliPluginUtilsActivator activator = new SliPluginUtilsActivator();
+        DME2 dme2 = activator.initDme2("src/test/resources/dme2.prod.properties");
+        assertEquals("user@sample.com", dme2.aafUserName);
+        assertEquals("fake", dme2.aafPassword);
+        assertEquals("PROD", dme2.envContext);
+        assertEquals("", dme2.routeOffer);
+        Assert.assertArrayEquals("http://sample.com:25055,http://sample.com:25055".split(","), dme2.proxyUrls);
+        assertEquals("1.0", dme2.commonServiceVersion);
+        assertEquals("LPP_PROD", dme2.partner);
+
+        String constructedUrl = dme2.constructUrl("sample.com/restservices/instar/v1/assetSearch", null, "/mySubContext");
+        assertNotNull(constructedUrl);
+        System.out.println(constructedUrl);
+    }
+
+}
diff --git a/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtils_StaticFunctionsTest.java b/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtils_StaticFunctionsTest.java
new file mode 100644 (file)
index 0000000..e69d086
--- /dev/null
@@ -0,0 +1,250 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.SliPluginUtils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SliPluginUtils_StaticFunctionsTest {
+    private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils_StaticFunctionsTest.class);
+    SliPluginUtils utils = new SliPluginUtils();
+    private SvcLogicContext ctx;
+    private HashMap<String, String> parameters;
+
+    @Before
+    public void setUp() throws Exception {
+        this.ctx = new SvcLogicContext();
+        parameters = new HashMap<String, String>();
+    }
+
+    // TODO: javadoc
+    @Test
+    public final void testCtxGetBeginsWith() {
+        ctx.setAttribute("service-data.oper-status.order-status", "InProgress");
+        ctx.setAttribute("service-data.service-information.service-instance-id", "my-instance");
+        ctx.setAttribute("service-data.service-information.service-type", "my-service");
+
+        Map<String, String> entries = SliPluginUtils.ctxGetBeginsWith(ctx, "service-data.service-information");
+
+        assertEquals("my-instance", entries.get("service-data.service-information.service-instance-id"));
+        assertEquals("my-service", entries.get("service-data.service-information.service-type"));
+        assertFalse(entries.containsKey("service-data.oper-status.order-status"));
+    }
+
+    // TODO: javadoc
+    @Test
+    public final void testCtxListRemove_index() throws SvcLogicException {
+        LOG.trace("=== testCtxListRemove_index ===");
+        ctx.setAttribute("service-data.vnf-l3[0].vnf-host-name", "vnf-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[0].device-host-name", "device-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[1].vnf-host-name", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[1].device-host-name", "device-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[2].vnf-host-name", "vnf-host-name_2");
+        ctx.setAttribute("service-data.vnf-l3[2].device-host-name", "device-host-name_2");
+        ctx.setAttribute("service-data.vnf-l3_length", "3");
+
+        parameters.put("index", "1");
+        parameters.put("list_pfx", "service-data.vnf-l3");
+
+        utils.ctxListRemove(parameters, ctx);
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        assertEquals("2", ctx.getAttribute("service-data.vnf-l3_length"));
+        assertEquals("vnf-host-name_0", ctx.getAttribute("service-data.vnf-l3[0].vnf-host-name"));
+        assertEquals("device-host-name_0", ctx.getAttribute("service-data.vnf-l3[0].device-host-name"));
+        assertEquals("vnf-host-name_2", ctx.getAttribute("service-data.vnf-l3[1].vnf-host-name"));
+        assertEquals("device-host-name_2", ctx.getAttribute("service-data.vnf-l3[1].device-host-name"));
+    }
+
+    // TODO: javadoc
+    @Test
+    public final void textCtxListRemove_keyValue() throws SvcLogicException {
+        LOG.trace("=== textCtxListRemove_keyValue ===");
+        ctx.setAttribute("service-data.vnf-l3[0].vnf-host-name", "vnf-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[0].device-host-name", "device-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[1].vnf-host-name", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[1].device-host-name", "device-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[2].vnf-host-name", "vnf-host-name_2");
+        ctx.setAttribute("service-data.vnf-l3[2].device-host-name", "device-host-name_2");
+        // 2nd entry
+        ctx.setAttribute("service-data.vnf-l3[3].vnf-host-name", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[3].device-host-name", "device-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3_length", "4");
+
+        parameters.put("list_pfx", "service-data.vnf-l3");
+        parameters.put("key", "vnf-host-name");
+        parameters.put("value", "vnf-host-name_1");
+
+        utils.ctxListRemove(parameters, ctx);
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        assertEquals("2", ctx.getAttribute("service-data.vnf-l3_length"));
+        assertEquals("vnf-host-name_0", ctx.getAttribute("service-data.vnf-l3[0].vnf-host-name"));
+        assertEquals("device-host-name_0", ctx.getAttribute("service-data.vnf-l3[0].device-host-name"));
+        assertEquals("vnf-host-name_2", ctx.getAttribute("service-data.vnf-l3[1].vnf-host-name"));
+        assertEquals("device-host-name_2", ctx.getAttribute("service-data.vnf-l3[1].device-host-name"));
+    }
+
+    // TODO: javadoc
+    @Test
+    public final void textCtxListRemove_keyValue_nullkey() throws SvcLogicException {
+        LOG.trace("=== textCtxListRemove_keyValue_nullkey ===");
+        ctx.setAttribute("service-data.vnf-l3[0]", "vnf-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[1]", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[2]", "vnf-host-name_2");
+        ctx.setAttribute("service-data.vnf-l3_length", "3");
+
+        parameters.put("list_pfx", "service-data.vnf-l3");
+        parameters.put("value", "vnf-host-name_1");
+
+        utils.ctxListRemove(parameters, ctx);
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        assertEquals("2", ctx.getAttribute("service-data.vnf-l3_length"));
+        assertEquals("vnf-host-name_0", ctx.getAttribute("service-data.vnf-l3[0]"));
+        assertEquals("vnf-host-name_2", ctx.getAttribute("service-data.vnf-l3[1]"));
+    }
+
+    // TODO: javadoc
+    @Test
+    public final void textCtxListRemove_keyValueList() throws SvcLogicException {
+        LOG.trace("=== textCtxListRemove_keyValueList ===");
+        ctx.setAttribute("service-data.vnf-l3[0].vnf-host-name", "vnf-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[0].device-host-name", "device-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[1].vnf-host-name", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[1].device-host-name", "device-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[2].vnf-host-name", "vnf-host-name_2");
+        ctx.setAttribute("service-data.vnf-l3[2].device-host-name", "device-host-name_2");
+        // 2nd entry
+        ctx.setAttribute("service-data.vnf-l3[3].vnf-host-name", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[3].device-host-name", "device-host-name_1");
+        // entries with only 1 of 2 key-value pairs matching
+        ctx.setAttribute("service-data.vnf-l3[4].vnf-host-name", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[4].device-host-name", "device-host-name_4");
+        ctx.setAttribute("service-data.vnf-l3[5].vnf-host-name", "vnf-host-name_5");
+        ctx.setAttribute("service-data.vnf-l3[5].device-host-name", "device-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3_length", "6");
+
+        parameters.put("list_pfx", "service-data.vnf-l3");
+        parameters.put("keys_length", "2");
+        parameters.put("keys[0].key", "vnf-host-name");
+        parameters.put("keys[0].value", "vnf-host-name_1");
+        parameters.put("keys[1].key", "device-host-name");
+        parameters.put("keys[1].value", "device-host-name_1");
+
+        utils.ctxListRemove(parameters, ctx);
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        assertEquals("4", ctx.getAttribute("service-data.vnf-l3_length"));
+        assertEquals("vnf-host-name_0", ctx.getAttribute("service-data.vnf-l3[0].vnf-host-name"));
+        assertEquals("device-host-name_0", ctx.getAttribute("service-data.vnf-l3[0].device-host-name"));
+        assertEquals("vnf-host-name_2", ctx.getAttribute("service-data.vnf-l3[1].vnf-host-name"));
+        assertEquals("device-host-name_2", ctx.getAttribute("service-data.vnf-l3[1].device-host-name"));
+        assertEquals("vnf-host-name_1", ctx.getAttribute("service-data.vnf-l3[2].vnf-host-name"));
+        assertEquals("device-host-name_4", ctx.getAttribute("service-data.vnf-l3[2].device-host-name"));
+        assertEquals("vnf-host-name_5", ctx.getAttribute("service-data.vnf-l3[3].vnf-host-name"));
+        assertEquals("device-host-name_1", ctx.getAttribute("service-data.vnf-l3[3].device-host-name"));
+    }
+
+    // TODO: javadoc
+    @Test(expected = SvcLogicException.class)
+    public final void testCtxListRemove_nullListLength() throws SvcLogicException {
+        LOG.trace("=== testCtxListRemove_nullListLength ===");
+        ctx.setAttribute("service-data.vnf-l3[0].vnf-host-name", "vnf-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[0].device-host-name", "device-host-name_0");
+        ctx.setAttribute("service-data.vnf-l3[1].vnf-host-name", "vnf-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[1].device-host-name", "device-host-name_1");
+        ctx.setAttribute("service-data.vnf-l3[2].vnf-host-name", "vnf-host-name_2");
+        ctx.setAttribute("service-data.vnf-l3[2].device-host-name", "device-host-name_2");
+
+        parameters.put("index", "1");
+        parameters.put("list_pfx", "service-data.vnf-l3");
+
+        utils.ctxListRemove(parameters, ctx);
+    }
+
+    // TODO: javadoc
+    @Test
+    public final void testCtxPutAll() {
+        HashMap<String, Object> entries = new HashMap<String, Object>();
+        entries.put("service-data.oper-status.order-status", "InProgress");
+        entries.put("service-data.service-information.service-instance-id", "my-instance");
+        entries.put("service-data.request-information.order-number", 1234);
+        entries.put("service-data.request-information.request-id", null);
+
+        SliPluginUtils.ctxPutAll(ctx, entries);
+
+        assertEquals("InProgress", ctx.getAttribute("service-data.oper-status.order-status"));
+        assertEquals("my-instance", ctx.getAttribute("service-data.service-information.service-instance-id"));
+        assertEquals("1234", ctx.getAttribute("service-data.request-information.order-number"));
+        assertFalse(ctx.getAttributeKeySet().contains("service-data.request-information.request-id"));
+    }
+
+    // TODO: javadoc
+    @Test
+    public final void testCtxSetAttribute_LOG() {
+        LOG.debug("=== testCtxSetAttribute_LOG ===");
+        Integer i = new Integer(3);
+        SliPluginUtils.ctxSetAttribute(ctx, "test", i, LOG, SliPluginUtils.LogLevel.TRACE);
+    }
+
+    /*@Test
+    public void printContext() throws SvcLogicException, IOException {
+        String filePath = "/src/test/resources/printContext.txt";
+        parameters.put("filename", filePath);
+        File f = new File(filePath);
+        assert (f.exists());
+        assert (!f.isDirectory());
+        ctx.setAttribute("hello", "world");
+        ctx.setAttribute("name", "value");
+
+        SliPluginUtils.printContext(parameters, ctx);
+        BufferedReader br = new BufferedReader(new FileReader(f));
+        String line = br.readLine();
+        assertEquals("#######################################", line);
+        line = br.readLine();
+        assertEquals("hello = world", line);
+        line = br.readLine();
+        assertEquals("name = value", line);
+        br.close();
+        Files.delete(Paths.get(filePath));
+    }*/
+
+    @Test
+    public void setTime() throws SvcLogicException {
+        String outputPath = "output";
+        parameters.put("outputPath", outputPath);
+        SliPluginUtils.setTime(parameters, ctx);
+        assertNotNull(ctx.getAttribute(outputPath));
+    }
+}
diff --git a/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtils_ctxSortListTest.java b/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliPluginUtils_ctxSortListTest.java
new file mode 100644 (file)
index 0000000..e2fcb33
--- /dev/null
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdnc.sli.SliPluginUtils;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Random;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("unused")
+public class SliPluginUtils_ctxSortListTest {
+    private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils_ctxSortListTest.class);
+    SliPluginUtils utils = new SliPluginUtils();
+    SvcLogicContext ctx;
+    HashMap<String, String> parameters;
+    Random rand = new Random();
+
+    @Before
+    public void setUp() throws Exception {
+        this.ctx = new SvcLogicContext();
+        this.parameters = new HashMap<String, String>();
+    }
+
+    @Test
+    public final void list_of_containers() throws SvcLogicException {
+        this.parameters.put("list", "input.list");
+        this.parameters.put("sort-fields", "sort-key");
+        this.parameters.put("delimiter", ",");
+
+        ctx.setAttribute("input.list_length", "10");
+        for (int i = 0; i < 10; i++) {
+            this.ctx.setAttribute("input.list[" + i + "].sort-key", Integer.toString(rand.nextInt(10)));
+            this.ctx.setAttribute("input.list[" + i + "].value", Integer.toString(rand.nextInt(10)));
+        }
+
+        LOG.trace("BEFORE SORT:");
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        utils.ctxSortList(this.parameters, this.ctx);
+
+        LOG.trace("AFTER SORT:");
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        for (int i = 0; i < 9; i++) {
+            assertTrue(this.ctx.getAttribute("input.list[" + i + "].sort-key").compareTo(this.ctx.getAttribute("input.list[" + (i + 1) + "].sort-key")) < 1);
+        }
+    }
+
+    @Test
+    public final void list_of_elements() throws SvcLogicException {
+        this.parameters.put("list", "input.list");
+        this.parameters.put("delimiter", ",");
+
+        this.ctx.setAttribute("input.list_length", "10");
+        for (int i = 0; i < 10; i++) {
+            this.ctx.setAttribute("input.list[" + i + ']', Integer.toString(rand.nextInt(10)));
+        }
+
+        LOG.trace("BEFORE SORT:");
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        utils.ctxSortList(this.parameters, this.ctx);
+
+        LOG.trace("AFTER SORT:");
+        SliPluginUtils.logContextMemory(ctx, LOG, SliPluginUtils.LogLevel.TRACE);
+
+        for (int i = 0; i < 9; i++) {
+            assertTrue(this.ctx.getAttribute("input.list[" + i + ']').compareTo(this.ctx.getAttribute("input.list[" + (i + 1) + ']')) < 1);
+        }
+    }
+}
diff --git a/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliStringUtilsTest.java b/sliPluginUtils/provider/src/test/java/org/openecomp/sdnc/sli/SliPluginUtils/SliStringUtilsTest.java
new file mode 100644 (file)
index 0000000..d57cefa
--- /dev/null
@@ -0,0 +1,244 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ *
+ */
+package org.openecomp.sdnc.sli.SliPluginUtils;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openecomp.sdnc.sli.SvcLogicContext;
+import org.openecomp.sdnc.sli.SvcLogicException;
+
+/**
+ * @author km991u
+ *
+ */
+public class SliStringUtilsTest {
+    private SvcLogicContext ctx;
+    private HashMap<String, String> param;
+    private SliStringUtils stringUtils = new SliStringUtils();
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+        this.ctx = new SvcLogicContext();
+        param = new HashMap<String, String>();
+    }
+
+    /**
+     * @throws SvcLogicException
+     * @see SliStringUtils#split(Map, SvcLogicContext)
+     */
+    @Test
+    public final void testSplit() throws SvcLogicException {
+        param.put("original_string", "one ## two ## three");
+        param.put("regex", " ## ");
+        param.put("ctx_memory_result_key", "result");
+
+        stringUtils.split(param, ctx);
+
+        assertThat(ctx.getAttribute("result[0]"), equalTo("one"));
+        assertThat(ctx.getAttribute("result[1]"), equalTo("two"));
+        assertThat(ctx.getAttribute("result[2]"), equalTo("three"));
+        assertThat(ctx.getAttribute("result_length"), equalTo("3"));
+    }
+
+    /**
+     * @throws SvcLogicException
+     * @see SliStringUtils#split(Map, SvcLogicContext)
+     */
+    @Test
+    public final void testSplit_limit() throws SvcLogicException {
+        param.put("original_string", "one ## two ## three");
+        param.put("regex", " ## ");
+        param.put("limit", "2");
+        param.put("ctx_memory_result_key", "result");
+
+        stringUtils.split(param, ctx);
+
+        assertThat(ctx.getAttribute("result[0]"), equalTo("one"));
+        assertThat(ctx.getAttribute("result[1]"), equalTo("two ## three"));
+        assertThat(ctx.getAttribute("result_length"), equalTo("2"));
+    }
+
+    @Test
+    public void equalsIgnoreCaseTrue() throws SvcLogicException {
+        String sourceString = "HeLlOwORLD";
+        String targetSTring = "HELLOWORLD";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("true", SliStringUtils.equalsIgnoreCase(param, ctx));
+    }
+
+    @Test
+    public void equalsIgnoreCaseFalse() throws SvcLogicException {
+        String sourceString = "HeLlOwORLD";
+        String targetSTring = "goodbyeWORLD";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("false", SliStringUtils.equalsIgnoreCase(param, ctx));
+    }
+
+    @Test
+    public void toUpper() throws SvcLogicException {
+        String sourceString = "HeLlOwORLD";
+        param.put("source", sourceString);
+        String path = "my.unique.path.";
+        param.put("outputPath", path);
+        SliStringUtils.toUpper(param, ctx);
+        assertEquals(sourceString.toUpperCase(), ctx.getAttribute(path));
+    }
+
+    @Test
+    public void toLower() throws SvcLogicException {
+        String sourceString = "HeLlOwORLD";
+        param.put("source", sourceString);
+        String path = "my.unique.path.";
+        param.put("outputPath", path);
+        SliStringUtils.toLower(param, ctx);
+        assertEquals(sourceString.toLowerCase(), ctx.getAttribute(path));
+    }
+
+    @Test
+    public void containsTrue() throws SvcLogicException {
+        String sourceString = "Pizza";
+        String targetSTring = "izza";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("true", SliStringUtils.contains(param, ctx));
+    }
+
+    @Test
+    public void containsFalse() throws SvcLogicException {
+        String sourceString = "Pizza";
+        String targetSTring = "muffin";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("false", SliStringUtils.contains(param, ctx));
+    }
+
+    @Test
+    public void endsWithTrue() throws SvcLogicException {
+        String sourceString = "Pizza";
+        String targetSTring = "za";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("true", SliStringUtils.endsWith(param, ctx));
+    }
+
+    @Test
+    public void endsWithFalse() throws SvcLogicException {
+        String sourceString = "Pizza";
+        String targetSTring = "muffin";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("false", SliStringUtils.endsWith(param, ctx));
+    }
+
+    @Test
+    public void trim() throws SvcLogicException {
+        String sourceString = " H E L L O W O R L D";
+        String outputPath = "muffin";
+        param.put("source", sourceString);
+        param.put("outputPath", outputPath);
+        SliStringUtils.trim(param, ctx);
+        assertEquals(sourceString.trim(), ctx.getAttribute(outputPath));
+    }
+
+    @Test
+    public void getLength() throws SvcLogicException {
+        String sourceString = "SomeRandomString";
+        String outputPath = "muffin";
+        param.put("source", sourceString);
+        param.put("outputPath", outputPath);
+        SliStringUtils.getLength(param, ctx);
+        assertEquals(String.valueOf(sourceString.length()), ctx.getAttribute(outputPath));
+    }
+
+    @Test
+    public void startsWithFalse() throws SvcLogicException {
+        String sourceString = "Java";
+        String targetSTring = "DG";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("false", SliStringUtils.startsWith(param, ctx));
+    }
+
+    @Test
+    public void startsWithTrue() throws SvcLogicException {
+        String sourceString = "Java";
+        String targetSTring = "Ja";
+        param.put("source", sourceString);
+        param.put("target", targetSTring);
+        assertEquals("true", SliStringUtils.startsWith(param, ctx));
+    }
+
+    @Test
+    public void replace() throws SvcLogicException {
+        String sourceString = "cat Hello World cat";
+        String old = "cat";
+        String neww = "dog";
+        String outputPath = "out";
+
+        param.put("source", sourceString);
+        param.put("target", old);
+        param.put("replacement", neww);
+        param.put("outputPath", outputPath);
+        SliStringUtils.replace(param, ctx);
+        assertEquals(sourceString.replace(old, neww), ctx.getAttribute(outputPath));
+    }
+
+    @Test
+    public void concat() throws SvcLogicException {
+        String sourceString = "cat";
+        String targetString = "dog";
+        String outputPath = "out";
+
+        param.put("source", sourceString);
+        param.put("target", targetString);
+        param.put("outputPath", outputPath);
+        SliStringUtils.concat(param, ctx);
+        assertEquals(sourceString + targetString, ctx.getAttribute(outputPath));
+    }
+
+    @Test
+    public void urlEncode() throws SvcLogicException {
+        String sourceString = "102/GE100/SNJSCAMCJP8/SNJSCAMCJT4";
+        String outputPath = "out";
+
+        param.put("source", sourceString);
+        param.put("outputPath", outputPath);
+        SliStringUtils.urlEncode(param, ctx);
+        assertEquals("102%2FGE100%2FSNJSCAMCJP8%2FSNJSCAMCJT4", ctx.getAttribute(outputPath));
+    }
+
+}
index 52237dc..ec54c3e 100755 (executable)
@@ -8,7 +8,6 @@
                <version>1.1.0-SNAPSHOT</version>
        </parent>
        <artifactId>sliapi-installer</artifactId>
-       <name>SLI API  - Karaf  Installer</name>
        <packaging>pom</packaging>
 
        <properties>
index ae79cb3..7d7e4c9 100755 (executable)
@@ -30,7 +30,7 @@
                                        <dependency>
                                                <groupId>org.opendaylight.mdsal</groupId>
                                                <artifactId>maven-sal-api-gen-plugin</artifactId>
-                                               <version>${odl.yangtools.version}</version>
+                                               <version>${odl.sal.api.gen.plugin.version}</version>
                                                <type>jar</type>
                                        </dependency>
                                </dependencies>
@@ -58,7 +58,7 @@
                <dependency>
                        <groupId>org.opendaylight.mdsal</groupId>
                        <artifactId>yang-binding</artifactId>
-                       <version>${odl.yangtools.version}</version>
+                       <version>${odl.mdsal.yang.binding.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.opendaylight.yangtools</groupId>
index 2c77331..047fd69 100755 (executable)
@@ -48,7 +48,10 @@ module SLI-API {
         leaf ack-final-indicator {
             type string;
         }
-        leaf response-text {
+        leaf response-message {
+            type string;
+        }
+        leaf context-memory-json {
             type string;
         }
     }
index 96e81b4..62d9cb0 100755 (executable)
@@ -54,7 +54,7 @@
                                        <dependency>
                                                <groupId>org.opendaylight.mdsal</groupId>
                                                <artifactId>maven-sal-api-gen-plugin</artifactId>
-                                               <version>${odl.yangtools.version}</version>
+                                               <version>${odl.sal.api.gen.plugin.version}</version>
                                                <type>jar</type>
                                        </dependency>
                                        <dependency>
index 8189bc0..f8deef2 100644 (file)
@@ -203,7 +203,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
 
                if (svcLogic == null) {
                        respBuilder.setResponseCode("500");
-                       respBuilder.setResponseText("Could not locate OSGi SvcLogicService service");
+                       respBuilder.setResponseMessage("Could not locate OSGi SvcLogicService service");
                        respBuilder.setAckFinalIndicator("Y");
 
                    rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build();
@@ -214,7 +214,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                try {
                        if (!svcLogic.hasGraph(calledModule, calledRpc, null, modeStr)) {
                                respBuilder.setResponseCode("404");
-                               respBuilder.setResponseText("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found");
+                               respBuilder.setResponseMessage("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found");
                                respBuilder.setAckFinalIndicator("Y");
 
                            rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build();
@@ -224,7 +224,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                        LOG.error("Caught exception looking for directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr, e);
 
                        respBuilder.setResponseCode("500");
-                       respBuilder.setResponseText("Internal error : could not determine if target graph exists");
+                       respBuilder.setResponseMessage("Internal error : could not determine if target graph exists");
                        respBuilder.setAckFinalIndicator("Y");
 
                    rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build();
@@ -265,7 +265,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                try {
                        LOG.info("Calling directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr);
 
-                       if (LOG.isDebugEnabled()) {
+                       if (LOG.isTraceEnabled()) {
                                StringBuffer argList = new StringBuffer();
                                argList.append("Parameters : {");
                                Enumeration e = parms.propertyNames();
@@ -274,7 +274,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                                        argList.append(" ("+propName+","+parms.getProperty(propName)+") ");
                                }
                                argList.append("}");
-                               LOG.debug(argList.toString());
+                               LOG.trace(argList.toString());
                                argList = null;
                        }
 
@@ -283,9 +283,22 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                        Properties respProps = svcLogic.execute(calledModule, calledRpc,
                                        null, modeStr, parms, domDataBroker);
 
+                       StringBuilder sb = new StringBuilder("{");
+                       
+                       for (Object key : respProps.keySet()) {
+                               String keyValue = (String) key;
+                               if (keyValue != null && !"".equals(keyValue) && !keyValue.contains("input.sli-parameter")) {
+                                       sb.append("\"").append(keyValue).append("\": \"").append(respProps.getProperty(keyValue)).append("\",");
+                               }
+                       }
+                       
+                       sb.setLength(sb.length() - 1);
+                       sb.append("}");
+                       
                        respBuilder.setResponseCode(respProps.getProperty("error-code", "0"));
-                       respBuilder.setResponseText(respProps.getProperty("error-message", ""));
+                       respBuilder.setResponseMessage(respProps.getProperty("error-message", ""));// TODO change response-text to response-message to match other BVC APIs
                        respBuilder.setAckFinalIndicator(respProps.getProperty("ack-final", "Y"));
+                       respBuilder.setContextMemoryJson(sb.toString());
 
                        TestResultBuilder testResultBuilder = new TestResultBuilder();
 
@@ -308,7 +321,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
 
                        respBuilder.setResponseCode("500");
                        respBuilder
-                                       .setResponseText("Internal error : caught exception executing directed graph "
+                                       .setResponseMessage("Internal error : caught exception executing directed graph "
                                                        + calledModule
                                                        + "/"
                                                        + calledRpc
@@ -359,7 +372,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
 
                if (svcLogic == null) {
                        respBuilder.setResponseCode("500");
-                       respBuilder.setResponseText("Could not locate OSGi SvcLogicService service");
+                       respBuilder.setResponseMessage("Could not locate OSGi SvcLogicService service");
                        respBuilder.setAckFinalIndicator("Y");
 
                    rpcResult = RpcResultBuilder.<HealthcheckOutput> failed().withResult(respBuilder.build()).build();
@@ -369,7 +382,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                try {
                        if (!svcLogic.hasGraph(calledModule, calledRpc, null, modeStr)) {
                                respBuilder.setResponseCode("404");
-                               respBuilder.setResponseText("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found");
+                               respBuilder.setResponseMessage("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found");
 
                                respBuilder.setAckFinalIndicator("Y");
 
@@ -380,7 +393,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                        LOG.error("Caught exception looking for directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr, e);
 
                        respBuilder.setResponseCode("500");
-                       respBuilder.setResponseText("Internal error : could not determine if target graph exists");
+                       respBuilder.setResponseMessage("Internal error : could not determine if target graph exists");
                        respBuilder.setAckFinalIndicator("Y");
 
                    rpcResult = RpcResultBuilder.<HealthcheckOutput> failed().withResult(respBuilder.build()).build();
@@ -396,7 +409,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
                                        null, modeStr, parms);
 
                        respBuilder.setResponseCode(respProps.getProperty("error-code", "0"));
-                       respBuilder.setResponseText(respProps.getProperty("error-message", ""));
+                       respBuilder.setResponseMessage(respProps.getProperty("error-message", ""));
                        respBuilder.setAckFinalIndicator(respProps.getProperty("ack-final", "Y"));
 
                } catch (Exception e) {
@@ -405,7 +418,7 @@ public class sliapiProvider implements AutoCloseable, SLIAPIService{
 
                        respBuilder.setResponseCode("500");
                        respBuilder
-                                       .setResponseText("Internal error : caught exception executing directed graph "
+                                       .setResponseMessage("Internal error : caught exception executing directed graph "
                                                        + calledModule
                                                        + "/"
                                                        + calledRpc