diff options
Diffstat (limited to 'dblib')
38 files changed, 4680 insertions, 0 deletions
diff --git a/dblib/.gitignore b/dblib/.gitignore new file mode 100755 index 000000000..b73caf31e --- /dev/null +++ b/dblib/.gitignore @@ -0,0 +1,34 @@ +#####standard .git ignore entries##### + +## IDE Specific Files ## +org.eclipse.core.resources.prefs +.classpath +.project +.settings +.idea +.externalToolBuilders +maven-eclipse.xml +workspace + +## Compilation Files ## +*.class +**/target +target +target-ide +MANIFEST.MF + +## Misc Ignores (OS specific etc) ## +bin/ +dist +*~ +*.ipr +*.iml +*.iws +classes +out/ +.DS_STORE +.metadata + +## Folders which contain auto generated source code ## +yang-gen-config +yang-gen-sal diff --git a/dblib/README.md b/dblib/README.md new file mode 100755 index 000000000..98e8f0c6f --- /dev/null +++ b/dblib/README.md @@ -0,0 +1,6 @@ +DBLIB Utility +--------------------- + +DBLIB utility is designed as a high availability connection manager. +It is configured to use multiple databases, and based on the configured rules +always provide the connection to te active database. diff --git a/dblib/features/pom.xml b/dblib/features/pom.xml new file mode 100755 index 000000000..6c174b1c8 --- /dev/null +++ b/dblib/features/pom.xml @@ -0,0 +1,138 @@ +<?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> + <artifactId>dblib</artifactId> + <groupId>org.openecomp.sdnc.core</groupId> + <version>0.0.1-SNAPSHOT</version> + </parent> + <artifactId>dblib-features</artifactId> + <name>DBLIB Adaptor - Features</name> + + <packaging>jar</packaging> + + <dependencies> + + + <dependency> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>dblib-provider</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.6</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>features-mdsal</artifactId> + <version>${odl.mdsal.features.version}</version> + <classifier>features</classifier> + <type>xml</type> + + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jdbc</artifactId> + <version>${tomcat-jdbc.version}</version> + </dependency> + + <!-- dependency for opendaylight-karaf-empty for use by testing --> + <dependency> + <groupId>org.opendaylight.odlparent</groupId> + <artifactId>opendaylight-karaf-empty</artifactId> + <version>${odl.karaf.empty.distro.version}</version> + <type>zip</type> + </dependency> + + <dependency> + <!-- Required for launching the feature tests --> + <groupId>org.opendaylight.odlparent</groupId> + <artifactId>features-test</artifactId> + <version>${odl.commons.opendaylight.version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>features-yangtools</artifactId> + <version>${odl.yangtools.version}</version> + <classifier>features</classifier> + <type>xml</type> + <scope>runtime</scope> + </dependency> + </dependencies> + + <build> + <resources> + <resource> + <filtering>true</filtering> + <directory>src/main/resources</directory> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>filter</id> + <goals> + <goal>resources</goal> + </goals> + <phase>generate-resources</phase> + </execution> + </executions> + </plugin> + <!-- launches the feature test, which validates that your karaf feature + can be installed inside of a karaf container. It doesn't validate that your + functionality works correctly, just that you have all of the dependent bundles + defined correctly. + <plugin> + + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.16</version> + <configuration> + <systemPropertyVariables> + <karaf.distro.groupId>org.opendaylight.odlparent</karaf.distro.groupId> + <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId> + <karaf.distro.version>${odl.karaf.empty.distro.version}</karaf.distro.version> + </systemPropertyVariables> + <dependenciesToScan> + <dependency>org.opendaylight.yangtools:features-test</dependency> + </dependenciesToScan> + </configuration> + </plugin> + --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>attach-artifacts</id> + <goals> + <goal>attach-artifact</goal> + </goals> + <phase>package</phase> + <configuration> + <artifacts> + <artifact> + <file>${project.build.directory}/classes/${features.file}</file> + <type>xml</type> + <classifier>features</classifier> + </artifact> + </artifacts> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/dblib/features/src/main/resources/features.xml b/dblib/features/src/main/resources/features.xml new file mode 100755 index 000000000..0c3e8fe38 --- /dev/null +++ b/dblib/features/src/main/resources/features.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<features name="sdnc-dblib-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0"> + + <repository>mvn:org.opendaylight.mdsal/features-mdsal/${odl.mdsal.features.version}/xml/features</repository> + + + <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>wrap:mvn:org.apache.tomcat/tomcat-jdbc/${tomcat-jdbc.version}/$DynamicImport-Package=com.mysql.*&overwrite=merge</bundle> + <bundle>mvn:org.openecomp.sdnc.core/dblib-provider/${project.version}</bundle> + <bundle>mvn:mysql/mysql-connector-java/${mysql.connector.version}</bundle> + </feature> + +</features> diff --git a/dblib/installer/pom.xml b/dblib/installer/pom.xml new file mode 100755 index 000000000..9da6a459f --- /dev/null +++ b/dblib/installer/pom.xml @@ -0,0 +1,143 @@ +<?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> + <artifactId>dblib</artifactId> + <groupId>org.openecomp.sdnc.core</groupId> + <version>0.0.1-SNAPSHOT</version> + </parent> + <artifactId>dblib-installer</artifactId> + <name>DBLIB Adaptor - Karaf Installer</name> + <packaging>pom</packaging> + + <properties> + <application.name>sdnc-dblib</application.name> + <features.boot>sdnc-dblib</features.boot> + <features.repositories>mvn:org.openecomp.sdnc.core/dblib-features/${project.version}/xml/features</features.repositories> + <include.transitive.dependencies>false</include.transitive.dependencies> + </properties> + + <dependencies> + + <dependency> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>dblib-features</artifactId> + <version>${project.version}</version> + <classifier>features</classifier> + <type>xml</type> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>dblib-provider</artifactId> + <version>${project.version}</version> + </dependency> + + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jdbc</artifactId> + <version>${tomcat-jdbc.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <id>maven-repo-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>false</attach> + <finalName>stage/${application.name}-${project.version}</finalName> + <descriptors> + <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + </execution> + <execution> + <id>installer-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>${application.name}-${project.version}-installer</finalName> + <descriptors> + <descriptor>src/assembly/assemble_installer_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <goals> + <goal>copy-dependencies</goal> + </goals> + <phase>prepare-package</phase> + <configuration> + <transitive>false</transitive> + <outputDirectory>${project.build.directory}/assembly/system</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <useRepositoryLayout>true</useRepositoryLayout> + <addParentPoms>false</addParentPoms> + <copyPom>false</copyPom> + <includeGroupIds>org.openecomp.sdnc,org.apache.tomcat</includeGroupIds> + <excludeArtifactIds>sli-common,sli-provider</excludeArtifactIds> + <scope>provided</scope> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>copy-version</id> + <goals> + <goal>copy-resources</goal> + </goals><!-- here the phase you need --> + <phase>validate</phase> + <configuration> + <outputDirectory>${basedir}/target/stage</outputDirectory> + <resources> + <resource> + <directory>src/main/resources/scripts</directory> + <includes> + <include>install-feature.sh</include> + </includes> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + + </executions> + </plugin> + + </plugins> + </build> + +</project> diff --git a/dblib/installer/src/assembly/assemble_installer_zip.xml b/dblib/installer/src/assembly/assemble_installer_zip.xml new file mode 100755 index 000000000..a6a22a9ba --- /dev/null +++ b/dblib/installer/src/assembly/assemble_installer_zip.xml @@ -0,0 +1,39 @@ +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>bin</id> + + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>755</fileMode> + <includes> + <include>*.sh</include> + </includes> + </fileSet> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>644</fileMode> + <excludes> + <exclude>*.sh</exclude> + </excludes> + </fileSet> + </fileSets> + + + +</assembly> diff --git a/dblib/installer/src/assembly/assemble_mvnrepo_zip.xml b/dblib/installer/src/assembly/assemble_mvnrepo_zip.xml new file mode 100755 index 000000000..d96c9f402 --- /dev/null +++ b/dblib/installer/src/assembly/assemble_mvnrepo_zip.xml @@ -0,0 +1,29 @@ +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>bin</id> + + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/assembly/</directory> + <outputDirectory>.</outputDirectory> + <excludes> + </excludes> + </fileSet> + </fileSets> + + + +</assembly> diff --git a/dblib/installer/src/main/resources/scripts/install-feature.sh b/dblib/installer/src/main/resources/scripts/install-feature.sh new file mode 100644 index 000000000..16b5be8c4 --- /dev/null +++ b/dblib/installer/src/main/resources/scripts/install-feature.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +ODL_HOME=${ODL_HOME:-/opt/opendaylight/current} +ODL_KARAF_CLIENT=${ODL_KARAF_CLIENT:-${ODL_HOME}/bin/client} +ODL_KARAF_CLIENT_OPTS=${ODL_KARAF_CLIENT_OPTS:-"-u karaf"} +INSTALLERDIR=$(dirname $0) + +REPOZIP=${INSTALLERDIR}/${features.boot}-${project.version}.zip + +if [ -f ${REPOZIP} ] +then + unzip -d ${ODL_HOME} ${REPOZIP} +else + echo "ERROR : repo zip ($REPOZIP) not found" + exit 1 +fi + +${ODL_KARAF_CLIENT} ${ODL_KARAF_CLIENT_OPTS} feature:repo-add ${features.repositories} +${ODL_KARAF_CLIENT} ${ODL_KARAF_CLIENT_OPTS} feature:install ${features.boot} diff --git a/dblib/pom.xml b/dblib/pom.xml new file mode 100755 index 000000000..78af665af --- /dev/null +++ b/dblib/pom.xml @@ -0,0 +1,114 @@ +<?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/maven-v4_0_0.xsd"> + <parent> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>sdnc-core</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + + <modelVersion>4.0.0</modelVersion> + <packaging>pom</packaging> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>dblib</artifactId> + + + <name>DBLIB Adaptor</name> + <description>The DBLIB adaptor allows service logic to access persistent data in a local sql database</description> + + <version>0.0.1-SNAPSHOT</version> + + <build> + <plugins> + <plugin> + + <groupId>org.codehaus.mojo</groupId> + + <artifactId>license-maven-plugin</artifactId> + + <version>1.9</version> + + <configuration> + + <licenseName>apache_v2</licenseName> + + <inceptionYear>2016</inceptionYear> + + <organizationName>AT&T</organizationName> + + <projectName>openecomp</projectName> + + <roots> + + <root>src/main/java</root> + + </roots> + + <excludes> + + <exclude>*.png</exclude> + + </excludes> + + </configuration> + + </plugin> + </plugins> + + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven.compile.plugin.version}</version> + <configuration> + <source>${java.version.source}</source> + <target>${java.version.target}</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.10</version> + + <executions> + <execution> + <id>aggregate</id> + <goals> + <goal>aggregate</goal> + </goals> + <phase>site</phase> + + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-source-plugin</artifactId> + <version>2.1.1</version> + <executions> + <execution> + <id>bundle-sources</id> + <phase>package</phase> + <goals> + <!-- produce source artifact for main project sources --> + <goal>jar-no-fork</goal> + + <!-- produce source artifact for project test sources --> + <goal>test-jar-no-fork</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + + </pluginManagement> + </build> + <organization> + <name>AT&T</name> + </organization> + <modules> + <module>provider</module> + <module>features</module> + <module>installer</module> + </modules> +</project> diff --git a/dblib/provider/pom.xml b/dblib/provider/pom.xml new file mode 100755 index 000000000..b5acc7e14 --- /dev/null +++ b/dblib/provider/pom.xml @@ -0,0 +1,82 @@ +<?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>0.0.1-SNAPSHOT</version> + </parent> + <artifactId>dblib-provider</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>bundle</packaging> + <name>DBLIB Adaptor - Provider</name> + <url>http://maven.apache.org</url> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>equinoxSDK381</groupId> + <artifactId>org.eclipse.osgi</artifactId> + <version>${equinox.osgi.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>${slf4j.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + <version>${mysql.connector.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jdbc</artifactId> + <version>${tomcat-jdbc.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>${bundle.plugin.version}</version> + <extensions>true</extensions> + <configuration> + <instructions> + <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.*,org.apache.tomcat.*</Import-Package> + --> + <Import-Package>*</Import-Package> + <Embed-Transitive>true</Embed-Transitive> + </instructions> + </configuration> + + </plugin> + + + </plugins> + </build> +</project> diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/CachedDataSource.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/CachedDataSource.java new file mode 100644 index 000000000..58a0aeb11 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/CachedDataSource.java @@ -0,0 +1,616 @@ +/*- + * ============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; + +import java.io.Closeable; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.sql.Blob; +import java.sql.Connection; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Observer; + +import javax.sql.DataSource; +import javax.sql.rowset.CachedRowSet; +import javax.sql.rowset.RowSetProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.tomcat.jdbc.pool.PoolExhaustedException; +import org.openecomp.sdnc.sli.resource.dblib.config.BaseDBConfiguration; +import org.openecomp.sdnc.sli.resource.dblib.pm.SQLExecutionMonitor; +import org.openecomp.sdnc.sli.resource.dblib.pm.SQLExecutionMonitorObserver; +import org.openecomp.sdnc.sli.resource.dblib.pm.SQLExecutionMonitor.TestObject; +import com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException; + + +/** + * @version $Revision: 1.13 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ + +public abstract class CachedDataSource implements DataSource, SQLExecutionMonitorObserver +{ + private static Logger LOGGER = LoggerFactory.getLogger(CachedDataSource.class); + + protected static final String AS_CONF_ERROR = "AS_CONF_ERROR: "; + + protected long CONN_REQ_TIMEOUT = 30L; + protected long DATA_REQ_TIMEOUT = 100L; + + private final SQLExecutionMonitor monitor; + protected DataSource ds = null; + protected String connectionName = null; + protected boolean initialized = false; + + private long interval = 1000; + private long initialDelay = 5000; + private long expectedCompletionTime = 50L; + private boolean canTakeOffLine = true; + private long unprocessedFailoverThreshold = 3L; + + private long nextErrorReportTime = 0L; + + private String globalHostName = null; + + + public CachedDataSource(BaseDBConfiguration jdbcElem) throws DBConfigException + { + configure(jdbcElem); + monitor = new SQLExecutionMonitor(this); + } + + protected abstract void configure(BaseDBConfiguration jdbcElem) throws DBConfigException; + /* (non-Javadoc) + * @see javax.sql.DataSource#getConnection() + */ + public Connection getConnection() throws SQLException + { + return ds.getConnection(); + } + + public CachedRowSet getData(String statement, ArrayList<Object> arguments) throws SQLException, Throwable + { + TestObject testObject = null; + testObject = monitor.registerRequest(); + + Connection connection = null; + try { + connection = this.getConnection(); + if(connection == null ) { + throw new SQLException("Connection invalid"); + } + if(LOGGER.isDebugEnabled()) + LOGGER.debug("Obtained connection <" + connectionName + ">: "+connection.toString()); + return executePreparedStatement(connection, statement, arguments, true); + } finally { + try { + if(connection != null && !connection.isClosed()) { + connection.close(); + } + } catch(Throwable exc) { + // the exception not monitored + } finally { + connection = null; + } + + monitor.deregisterReguest(testObject); + } + } + + public boolean writeData(String statement, ArrayList<Object> arguments) throws SQLException, Throwable + { + TestObject testObject = null; + testObject = monitor.registerRequest(); + + Connection connection = null; + try { + connection = this.getConnection(); + if(connection == null ) { + throw new SQLException("Connection invalid"); + } + if(LOGGER.isDebugEnabled()) + LOGGER.debug("Obtained connection <" + connectionName + ">: "+connection.toString()); + return executeUpdatePreparedStatement(connection, statement, arguments, true); + } finally { + try { + if(connection != null && !connection.isClosed()) { + connection.close(); + } + } catch(Throwable exc) { + // the exception not monitored + } finally { + connection = null; + } + + monitor.deregisterReguest(testObject); + } + } + + CachedRowSet executePreparedStatement(Connection conn, String statement, ArrayList<Object> arguments, boolean close) throws SQLException, Throwable + { + long time = System.currentTimeMillis(); + + CachedRowSet data = null; + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL Statement: "+ statement); + if(arguments != null && !arguments.isEmpty()) { + LOGGER.debug("Argunments: "+ Arrays.toString(arguments.toArray())); + } + } + + ResultSet rs = null; + try { + data = RowSetProvider.newFactory().createCachedRowSet(); + PreparedStatement ps = conn.prepareStatement(statement); + if(arguments != null) + { + for(int i = 0, max = arguments.size(); i < max; i++){ + ps.setObject(i+1, arguments.get(i)); + } + } + rs = ps.executeQuery(); + data.populate(rs); + // Point the rowset Cursor to the start + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL SUCCESS. rows returned: " + data.size()+ ", time(ms): "+ (System.currentTimeMillis() - time)); } + } catch(SQLException exc){ + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL FAILURE. time(ms): "+ (System.currentTimeMillis() - time)); + } + try { conn.rollback(); } catch(Throwable thr){} + if(arguments != null && !arguments.isEmpty()) { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with arguments: "+arguments.toString(), exc); + } else { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with no arguments. ", exc); + } + throw exc; + } catch(Throwable exc){ + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL FAILURE. time(ms): "+ (System.currentTimeMillis() - time)); + } + if(arguments != null && !arguments.isEmpty()) { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with arguments: "+arguments.toString(), exc); + } else { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with no arguments. ", exc); + } + throw exc; // new SQLException(exc); + } finally { + + try { + if(rs != null){ + rs.close(); + rs = null; + } + } catch(Exception exc){ + + } + try { + if(conn != null && close){ + conn.close(); + conn = null; + } + } catch(Exception exc){ + + } + } + + return data; + } + + boolean executeUpdatePreparedStatement(Connection conn, String statement, ArrayList<Object> arguments, boolean close) throws SQLException, Throwable { + long time = System.currentTimeMillis(); + + CachedRowSet data = null; + + int rs = -1; + try { + data = RowSetProvider.newFactory().createCachedRowSet(); + PreparedStatement ps = conn.prepareStatement(statement); + if(arguments != null) + { + for(int i = 0, max = arguments.size(); i < max; i++){ + if(arguments.get(i) instanceof Blob) { + ps.setBlob(i+1, (Blob)arguments.get(i)); + } else if(arguments.get(i) instanceof Timestamp) { + ps.setTimestamp(i+1, (Timestamp)arguments.get(i)); + } else if(arguments.get(i) instanceof Integer) { + ps.setInt(i+1, (Integer)arguments.get(i)); + } else if(arguments.get(i) instanceof Long) { + ps.setLong(i+1, (Long)arguments.get(i)); + } else if(arguments.get(i) instanceof Date) { + ps.setDate(i+1, (Date)arguments.get(i)); + } else { + ps.setObject(i+1, arguments.get(i)); + } + } + } + rs = ps.executeUpdate(); + // Point the rowset Cursor to the start + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL SUCCESS. rows returned: " + data.size()+ ", time(ms): "+ (System.currentTimeMillis() - time)); + } + } catch(SQLException exc){ + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL FAILURE. time(ms): "+ (System.currentTimeMillis() - time)); + } + try { conn.rollback(); } catch(Throwable thr){} + if(arguments != null && !arguments.isEmpty()) { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with arguments: "+arguments.toString(), exc); + } else { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with no arguments. ", exc); + } + throw exc; + } catch(Throwable exc){ + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL FAILURE. time(ms): "+ (System.currentTimeMillis() - time)); + } + if(arguments != null && !arguments.isEmpty()) { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with arguments: "+arguments.toString(), exc); + } else { + LOGGER.error("<"+connectionName+"> Failed to execute: "+ statement + " with no arguments. ", exc); + } + throw exc; // new SQLException(exc); + } finally { + try { + if(conn != null && close){ + conn.close(); + conn = null; + } + } catch(Exception exc){ + + } + } + + return true; + } + + /* (non-Javadoc) + * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String) + */ + public Connection getConnection(String username, String password) + throws SQLException + { + return ds.getConnection(username, password); + } + + /* (non-Javadoc) + * @see javax.sql.DataSource#getLogWriter() + */ + public PrintWriter getLogWriter() throws SQLException + { + return ds.getLogWriter(); + } + + /* (non-Javadoc) + * @see javax.sql.DataSource#getLoginTimeout() + */ + public int getLoginTimeout() throws SQLException + { + return ds.getLoginTimeout(); + } + + /* (non-Javadoc) + * @see javax.sql.DataSource#setLogWriter(java.io.PrintWriter) + */ + public void setLogWriter(PrintWriter out) throws SQLException + { + ds.setLogWriter(out); + } + + /* (non-Javadoc) + * @see javax.sql.DataSource#setLoginTimeout(int) + */ + public void setLoginTimeout(int seconds) throws SQLException + { + ds.setLoginTimeout(seconds); + } + + + public final String getDbConnectionName(){ + return connectionName; + } + + protected final void setDbConnectionName(String name) { + this.connectionName = name; + } + + public void cleanUp(){ + if(ds != null && ds instanceof Closeable) { + try { + ((Closeable)ds).close(); + } catch (IOException e) { + LOGGER.warn(e.getMessage()); + } + } + ds = null; + monitor.deleteObservers(); + monitor.cleanup(); + } + + public boolean isInitialized() { + return initialized; + } + + protected boolean testConnection(){ + return testConnection(false); + } + + protected boolean testConnection(boolean error_level){ + Connection conn = null; + ResultSet rs = null; + Statement stmt = null; + try + { + Boolean readOnly = null; + String hostname = null; + conn = this.getConnection(); + stmt = conn.createStatement(); + rs = stmt.executeQuery("SELECT @@global.read_only, @@global.hostname"); //("SELECT 1 FROM DUAL"); //"select BANNER from SYS.V_$VERSION" + while(rs.next()) + { + readOnly = rs.getBoolean(1); + hostname = rs.getString(2); + + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("SQL DataSource <"+getDbConnectionName() + "> connected to " + hostname + ", read-only is " + readOnly + ", tested successfully "); + } + } + + } catch (Throwable exc) { + if(error_level) { + LOGGER.error("SQL DataSource <" + this.getDbConnectionName() + "> test failed. Cause : " + exc.getMessage()); + } else { + LOGGER.info("SQL DataSource <" + this.getDbConnectionName() + "> test failed. Cause : " + exc.getMessage()); + } + return false; + } finally { + if(rs != null) { + try { + rs.close(); + rs = null; + } catch (SQLException e) { + } + } + if(stmt != null) { + try { + stmt.close(); + stmt = null; + } catch (SQLException e) { + } + } + if(conn !=null){ + try { + conn.close(); + conn = null; + } catch (SQLException e) { + } + } + } + return true; + } + + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return false; + } + + public <T> T unwrap(Class<T> iface) throws SQLException { + return null; + } + + @SuppressWarnings("deprecation") + public void setConnectionCachingEnabled(boolean state) + { +// if(ds != null && ds instanceof OracleDataSource) +// try { +// ((OracleDataSource)ds).setConnectionCachingEnabled(true); +// } catch (SQLException exc) { +// LOGGER.warn("", exc); +// } + } + + public void addObserver(Observer observer) { + monitor.addObserver(observer); + } + + public void deleteObserver(Observer observer) { + monitor.deleteObserver(observer); + } + + public long getInterval() { + return interval; + } + + public long getInitialDelay() { + return initialDelay; + } + + public void setInterval(long value) { + interval = value; + } + + public void setInitialDelay(long value) { + initialDelay = value; + } + + public long getExpectedCompletionTime() { + return expectedCompletionTime; + } + + public void setExpectedCompletionTime(long value) { + expectedCompletionTime = value; + } + + public long getUnprocessedFailoverThreshold() { + return unprocessedFailoverThreshold; + } + + public void setUnprocessedFailoverThreshold(long value) { + this.unprocessedFailoverThreshold = value; + } + + public boolean canTakeOffLine() { + return canTakeOffLine; + } + + public void blockImmediateOffLine() { + canTakeOffLine = false; + final Thread offLineTimer = new Thread() + { + public void run(){ + try { + Thread.sleep(30000L); + }catch(Throwable exc){ + + }finally{ + canTakeOffLine = true; + } + } + }; + offLineTimer.setDaemon(true); + offLineTimer.start(); + } + + /** + * @return the monitor + */ + final SQLExecutionMonitor getMonitor() { + return monitor; + } + + protected boolean isSlave() throws PoolExhaustedException, MySQLNonTransientConnectionException { + CachedRowSet rs = null; + boolean isSlave = true; + String hostname = "UNDETERMINED"; + try { + boolean localSlave = true; + rs = this.getData("SELECT @@global.read_only, @@global.hostname", new ArrayList<Object>()); + while(rs.next()) { + localSlave = rs.getBoolean(1); + hostname = rs.getString(2); + } + isSlave = localSlave; + } catch(PoolExhaustedException | MySQLNonTransientConnectionException peexc){ + throw peexc; + } catch (SQLException e) { + LOGGER.error("", e); + isSlave = true; + } catch (Throwable e) { + LOGGER.error("", e); + isSlave = true; + } + if(isSlave){ + LOGGER.debug("SQL SLAVE : "+connectionName + " on server " + hostname); + } else { + LOGGER.debug("SQL MASTER : "+connectionName + " on server " + hostname); + } + return isSlave; + } + + public boolean isFabric() { + return false; + } + + protected boolean lockTable(Connection conn, String tableName) { + boolean retValue = false; + Statement lock = null; + try { + if(tableName != null) { + if(LOGGER.isDebugEnabled()) { + LOGGER.debug("Executing 'LOCK TABLES " + tableName + " WRITE' on connection " + conn.toString()); + if("SVC_LOGIC".equals(tableName)) { + Exception e = new Exception(); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + LOGGER.debug(sw.toString()); + } + } + lock = conn.createStatement(); + lock.execute("LOCK TABLES " + tableName + " WRITE"); + retValue = true; + } + } catch(Exception exc){ + LOGGER.error("", exc); + retValue = false; + } finally { + try { + lock.close(); + } catch(Exception exc) { + + } + } + return retValue; + } + + protected boolean unlockTable(Connection conn) { + boolean retValue = false; + Statement lock = null; + try { + if(LOGGER.isDebugEnabled()) { + LOGGER.debug("Executing 'UNLOCK TABLES' on connection " + conn.toString()); + } + lock = conn.createStatement(); + retValue = lock.execute("UNLOCK TABLES"); + } catch(Exception exc){ + LOGGER.error("", exc); + retValue = false; + } finally { + try { + lock.close(); + } catch(Exception exc) { + + } + } + return retValue; + } + + public void getPoolInfo(boolean allocation) { + + } + + public long getNextErrorReportTime() { + return nextErrorReportTime; + } + + public void setNextErrorReportTime(long nextTime) { + this.nextErrorReportTime = nextTime; + } + + public void setGlobalHostName(String hostname) { + this.globalHostName = hostname; + } + + public String getGlobalHostName() { + return globalHostName; + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/CachedDataSourceFactory.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/CachedDataSourceFactory.java new file mode 100644 index 000000000..3e51ed942 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/CachedDataSourceFactory.java @@ -0,0 +1,45 @@ +/*- + * ============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; + + +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.jdbc.JdbcDBCachedDataSource; +import org.openecomp.sdnc.sli.resource.dblib.jdbc.MySQLCachedDataSource; + +/** + * @version $Revision: 1.1 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ +public class CachedDataSourceFactory { + + public static CachedDataSource createDataSource(BaseDBConfiguration config) { + if(config instanceof JDBCConfiguration) + return JdbcDBCachedDataSource.createInstance(config); + + return (CachedDataSource)null; + } + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBConfigException.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBConfigException.java new file mode 100644 index 000000000..b324e6a2c --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBConfigException.java @@ -0,0 +1,47 @@ +/*- + * ============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; + + +/** + * @version $Revision: 1.1 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ +public class DBConfigException extends RuntimeException +{ + /** + * + */ + private static final long serialVersionUID = 4752405152537680257L; + + public DBConfigException(Exception e) + { + super(e.toString()); + } + + public DBConfigException(String msg) + { + super(msg); + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLIBResourceActivator.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLIBResourceActivator.java new file mode 100644 index 000000000..150a9a82f --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLIBResourceActivator.java @@ -0,0 +1,130 @@ +/*- + * ============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; + +import java.io.File; +import java.net.URL; +import java.util.Properties; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DBLIBResourceActivator implements BundleActivator { + + private static final String SDNC_CONFIG_DIR = "SDNC_CONFIG_DIR"; + + private static final String DBLIB_PROP_PATH = "/dblib.properties"; + + private ServiceRegistration registration = null; + + private static final Logger LOG = LoggerFactory.getLogger(DBLIBResourceActivator.class); + + @Override + public void start(BundleContext ctx) throws Exception { + LOG.info("entering DBLIBResourceActivator.start"); + + DbLibService jdbcDataSource = null; + // Read properties + Properties props = new Properties(); + + File file = null; + URL propURL = null; + String propDir = System.getenv(SDNC_CONFIG_DIR); + if ((propDir == null) || (propDir.length() == 0)) { + propDir = "/opt/sdnc/data/properties"; + } + file = new File(propDir + DBLIB_PROP_PATH); + if(file.exists()) { + propURL = file.toURI().toURL(); + LOG.info("Using property file (1): " + file.toString()); + } else { + propURL = ctx.getBundle().getResource("dblib.properties"); + URL tmp = null; + if (propURL == null) { + file = new File(DBLIB_PROP_PATH); + tmp = this.getClass().getResource(DBLIB_PROP_PATH); +// if(!file.exists()) { + if(tmp == null) { + throw new DblibConfigurationException("Missing configuration properties resource(3) : " + DBLIB_PROP_PATH); + } else { + propURL = tmp; //file.toURI().toURL(); + LOG.info("Using property file (4): " + file.toString()); + } + } else { + LOG.info("Using property file (2): " + propURL.toString()); + } + } + + + try { + props.load(propURL.openStream()); + } catch (Exception e) { + throw new DblibConfigurationException("Could not load properties at URL " + propURL.toString(), e); + + } + + + + try { + jdbcDataSource = DBResourceManager.create(props); + } catch (Exception exc) { + throw new DblibConfigurationException("Could not get initialize database", exc); + } + + String regName = jdbcDataSource.getClass().getName(); + + LOG.info("Registering DBResourceManager service "+regName); + registration = ctx.registerService(new String[] { regName, DbLibService.class.getName(), "javax.sql.DataSource" }, jdbcDataSource, null); + } + + @Override + public void stop(BundleContext ctx) throws Exception { + LOG.info("entering DBLIBResourceActivator.stop"); + if (registration != null) + { + try { + ServiceReference sref = ctx.getServiceReference(DbLibService.class.getName()); + + if (sref == null) { + LOG.warn("Could not find service reference for DBLIB service (" + DbLibService.class.getName() + ")"); + } else { + DBResourceManager dblibSvc = (DBResourceManager) ctx.getService(sref); + if (dblibSvc == null) { + LOG.warn("Could not find service reference for DBLIB service (" + DbLibService.class.getName() + ")"); + } else { + dblibSvc.cleanUp(); + } + } + } catch(Throwable exc) { + LOG.warn("Cleanup", exc); + } + + registration.unregister(); + registration = null; + LOG.debug("Deregistering DBResourceManager service"); + } + } + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLibConnection.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLibConnection.java new file mode 100644 index 000000000..5c1f51040 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLibConnection.java @@ -0,0 +1,390 @@ +/*- + * ============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; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.ArrayList; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +import javax.sql.rowset.CachedRowSet; + +import org.apache.tomcat.jdbc.pool.PooledConnection; +import org.apache.tomcat.jdbc.pool.ProxyConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DBLibConnection implements Connection { + + private static Logger LOGGER = LoggerFactory.getLogger(DBLibConnection.class); + + private final Connection connection; + private final CachedDataSource dataSource; + private boolean locked = false; + private String tableName = null; + + public DBLibConnection(Connection con, CachedDataSource dataSource){ + this.connection = con; + this.dataSource = dataSource; + locked = false; + dataSource.getPoolInfo(true); + } + + public boolean lockTable(String tablename) { + this.tableName = tablename; + return locked = dataSource.lockTable(connection, tableName); + } + + public void resetInactivityTimer() { + Class<org.apache.tomcat.jdbc.pool.PooledConnection> iface = PooledConnection.class; + try { + PooledConnection pc = connection.unwrap(iface); + pc.setTimestamp(System.currentTimeMillis()); + } catch (SQLException e) { + LOGGER.warn("Failed resetting timeout timer", e); + } + } + + public boolean unlock() { + dataSource.unlockTable(connection); + return locked = false; + } + + public boolean writeData(String statement, ArrayList<String> arguments) throws SQLException, Throwable + { + ArrayList<Object> newList=new ArrayList<Object>(); + if(arguments != null && !arguments.isEmpty()) { + newList.addAll(arguments); + } + resetInactivityTimer(); + return dataSource.executeUpdatePreparedStatement(connection, statement, newList, false); + } + + public CachedRowSet getData(String statement, ArrayList<String> arguments) throws SQLException, Throwable + { + ArrayList<Object> newList=new ArrayList<Object>(); + if(arguments != null && !arguments.isEmpty()) { + newList.addAll(arguments); + } + resetInactivityTimer(); + return dataSource.executePreparedStatement(connection, statement, newList, false); + } + + @Override + public <T> T unwrap(Class<T> iface) throws SQLException { + return connection.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return connection.isWrapperFor(iface); + } + + @Override + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + return connection.prepareStatement(sql); + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + return connection.prepareCall(sql); + } + + @Override + public String nativeSQL(String sql) throws SQLException { + return connection.nativeSQL(sql); + } + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + @Override + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + @Override + public void commit() throws SQLException { + connection.commit(); + } + + @Override + public void rollback() throws SQLException { + connection.rollback(); + } + + @Override + public void close() throws SQLException { + if(this.locked) { + try { + this.unlock(); + } catch(Throwable th) { + LOGGER.error("Failed unlocking",th); + } + } + if(connection != null && !connection.isClosed()) { + connection.close(); + } + dataSource.getPoolInfo(false); + } + + @Override + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + @Override + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + @Override + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + @Override + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + @Override + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + @Override + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + @Override + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + @Override + public Map<String, Class<?>> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + @Override + public void setTypeMap(Map<String, Class<?>> map) throws SQLException { + connection.setTypeMap(map); + } + + @Override + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + @Override + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(savepoint); + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) + throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + return connection.prepareStatement(sql, autoGeneratedKeys); + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + return connection.prepareStatement(sql, columnIndexes); + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + return connection.prepareStatement(sql, columnNames); + } + + @Override + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + @Override + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + @Override + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + @Override + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + @Override + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + @Override + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLibException.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLibException.java new file mode 100644 index 000000000..cc80741dc --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBLibException.java @@ -0,0 +1,39 @@ +/*- + * ============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; + +import java.sql.SQLException; + +/** + * An exception time for handling DBLIB specific error handling. + */ +public class DBLibException extends SQLException { + + /** + * + */ + private static final long serialVersionUID = -5345059355083984696L; + + public DBLibException(String message){ + super(message); + } + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBResourceManager.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBResourceManager.java new file mode 100644 index 000000000..5cf2953b7 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBResourceManager.java @@ -0,0 +1,862 @@ +/*- + * ============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; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLDataException; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLIntegrityConstraintViolationException; +import java.sql.SQLSyntaxErrorException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Observable; +import java.util.PriorityQueue; +import java.util.Properties; +import java.util.Queue; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.sql.DataSource; +import javax.sql.rowset.CachedRowSet; + +import org.apache.tomcat.jdbc.pool.PoolExhaustedException; +import org.openecomp.sdnc.sli.resource.dblib.config.DbConfigPool; +import org.openecomp.sdnc.sli.resource.dblib.factory.AbstractDBResourceManagerFactory; +import org.openecomp.sdnc.sli.resource.dblib.factory.AbstractResourceManagerFactory; +import org.openecomp.sdnc.sli.resource.dblib.factory.DBConfigFactory; +import org.openecomp.sdnc.sli.resource.dblib.pm.PollingWorker; +import org.openecomp.sdnc.sli.resource.dblib.pm.SQLExecutionMonitor; +import com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @version $Revision: 1.15 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ +public class DBResourceManager implements DataSource, DataAccessor, DBResourceObserver, DbLibService { + private static Logger LOGGER = LoggerFactory.getLogger(DBResourceManager.class); + + transient boolean terminating = false; + transient protected long retryInterval = 10000L; + transient boolean recoveryMode = true; + + protected final AtomicBoolean dsSelector = new AtomicBoolean(); + +// Queue<CachedDataSource> dsQueue = new ConcurrentLinkedQueue<CachedDataSource>(); + Queue<CachedDataSource> dsQueue = new PriorityQueue<CachedDataSource>(4, new Comparator<CachedDataSource>(){ + + @Override + public int compare(CachedDataSource left, CachedDataSource right) { + try { + if(!left.isSlave()) + return -1; + if(!right.isSlave()) + return 1; + + } catch (Throwable e) { + LOGGER.warn("", e); + } + return 0; + } + + }); + protected final Set<CachedDataSource> broken = Collections.synchronizedSet(new HashSet<CachedDataSource>()); + protected final Object monitor = new Object(); + protected final Properties configProps; + protected final Thread worker; + + protected final long terminationTimeOut; + protected final boolean monitorDbResponse; + protected final long monitoringInterval; + protected final long monitoringInitialDelay; + protected final long expectedCompletionTime; + protected final long unprocessedFailoverThreshold; + + public DBResourceManager(Properties props){ + this.configProps = props; + + // get retry interval value + retryInterval = getLongFromProperties(props, "org.openecomp.dblib.connection.retry", 10000L); + + // get recovery mode flag + recoveryMode = getBooleanFromProperties(props, "org.openecomp.dblib.connection.recovery", true); + if(!recoveryMode) + { + recoveryMode = false; + LOGGER.info("Recovery Mode disabled"); + } + // get time out value for thread cleanup + terminationTimeOut = getLongFromProperties(props, "org.openecomp.dblib.termination.timeout", 300000L); + // get properties for monitoring + monitorDbResponse = getBooleanFromProperties(props, "org.openecomp.dblib.connection.monitor", false); + monitoringInterval = getLongFromProperties(props, "org.openecomp.dblib.connection.monitor.interval", 1000L); + monitoringInitialDelay = getLongFromProperties(props, "org.openecomp.dblib.connection.monitor.startdelay", 5000L); + expectedCompletionTime = getLongFromProperties(props, "org.openecomp.dblib.connection.monitor.expectedcompletiontime", 5000L); + unprocessedFailoverThreshold = getLongFromProperties(props, "org.openecomp.dblib.connection.monitor.unprocessedfailoverthreshold", 3L); + + // initialize performance monitor + PollingWorker.createInistance(props); + + // initialize recovery thread + worker = new RecoveryMgr(); + worker.setName("DBResourcemanagerWatchThread"); + worker.setDaemon(true); + worker.start(); + } + + private void config(Properties ctx) throws Exception { + + DbConfigPool dbConfig = DBConfigFactory.createConfig(this.configProps); + + try { + AbstractResourceManagerFactory factory = AbstractDBResourceManagerFactory.getFactory(dbConfig.getType()); + if(LOGGER.isInfoEnabled()){ + LOGGER.info("Default DB config is : " + dbConfig.getType()); + LOGGER.info("Using factory : " + factory.getClass().getName()); + } + CachedDataSource[] cachedDS = factory.initDBResourceManager(dbConfig, this); + if(cachedDS == null || cachedDS.length == 0) { + LOGGER.error("Initialization of CachedDataSources failed. No instance was created."); + throw new Exception("Failed to initialize DB Library. No data source was created."); + } + + for(int i=0; i<cachedDS.length; i++){ + if(cachedDS[i] != null && cachedDS[i].isInitialized()){ + setDataSource(cachedDS[i]); + cachedDS[i].setInterval(monitoringInterval); + cachedDS[i].setInitialDelay(monitoringInitialDelay); + cachedDS[i].setExpectedCompletionTime(expectedCompletionTime); + cachedDS[i].setUnprocessedFailoverThreshold(unprocessedFailoverThreshold); + cachedDS[i].addObserver(this); + } + } + + } catch(Exception exc){ + throw exc; + } + } + + private long getLongFromProperties(Properties props, String property, long defaultValue) + { + String value = null; + long tmpLongValue = defaultValue; + try { + value = (String)props.getProperty(property); + if(value != null) + tmpLongValue = Long.parseLong(value); + + } catch(NumberFormatException exc) { + if(LOGGER.isWarnEnabled()){ + LOGGER.warn("'"+property+"'=" + value+" is invalid. It should be a numeric value"); + } + } catch(Exception exc) { + } + return tmpLongValue; + + } + + private boolean getBooleanFromProperties(Properties props, String property, boolean defaultValue) + { + boolean tmpValue = defaultValue; + String value = null; + + try { + value = (String)props.getProperty(property); + if(value != null) + tmpValue = Boolean.parseBoolean(value); + + } catch(NumberFormatException exc) { + if(LOGGER.isWarnEnabled()){ + LOGGER.warn("'"+property+"'=" + value+" is invalid. It should be a boolean value"); + } + } catch(Exception exc) { + } + return tmpValue; + + } + + + public void update(Observable observable, Object data) { + // if observable is active and there is a standby available, switch + if(observable instanceof SQLExecutionMonitor) + { + SQLExecutionMonitor monitor = (SQLExecutionMonitor)observable; + if(monitor.getParent() instanceof CachedDataSource) + { + CachedDataSource dataSource = (CachedDataSource)monitor.getParent(); + if(dataSource == dsQueue.peek()) + { + if(recoveryMode && dsQueue.size() > 1){ + handleGetConnectionException(dataSource, new Exception(data.toString())); + } + } + } + } + } + + public void testForceRecovery() + { + CachedDataSource active = (CachedDataSource) this.dsQueue.peek(); + handleGetConnectionException(active, new Exception("test")); + } + + class RecoveryMgr extends Thread { + + public void run() { + while(!terminating) + { + try { + Thread.sleep(retryInterval); + } catch (InterruptedException e1) { } + CachedDataSource brokenSource = null; + try { + if (!broken.isEmpty()) { + CachedDataSource[] sourceArray = broken.toArray(new CachedDataSource[0]); + for (int i = 0; i < sourceArray.length; i++) + { + brokenSource = sourceArray[i]; + if (brokenSource instanceof TerminatingCachedDataSource) + break; + if (resetConnectionPool(brokenSource)) { + broken.remove(brokenSource); + brokenSource.blockImmediateOffLine(); + dsQueue.add(brokenSource); + LOGGER.info("DataSource <" + + brokenSource.getDbConnectionName() + + "> recovered."); + } + brokenSource = null; + } + } + } catch (Exception exc) { + LOGGER.warn(exc.getMessage()); + if(brokenSource != null){ + try { + if(!broken.contains(brokenSource)) + broken.add(brokenSource); + brokenSource = null; + } catch (Exception e1) { } + } + } + } + LOGGER.info("DBResourceManager.RecoveryMgr <"+this.toString() +"> terminated." ); + } + + private boolean resetConnectionPool(CachedDataSource dataSource){ + try { + return dataSource.testConnection(); + } catch (Exception exc) { + LOGGER.info("DataSource <" + dataSource.getDbConnectionName() + "> resetCache failed with error: "+ exc.getMessage()); + return false; + } + } + } + + /* (non-Javadoc) + * @see org.openecomp.sdnc.sli.resource.dblib.DbLibService#getData(java.lang.String, java.util.ArrayList, java.lang.String) + */ + @Override + public CachedRowSet getData(String statement, ArrayList<String> arguments, String preferredDS) throws SQLException { + ArrayList<Object> newList=new ArrayList<Object>(); + if(arguments != null && !arguments.isEmpty()) { + newList.addAll(arguments); + } + if(recoveryMode) + return requestDataWithRecovery(statement, newList, preferredDS); + else + return requestDataNoRecovery(statement, newList, preferredDS); + } + + private CachedRowSet requestDataWithRecovery(String statement, ArrayList<Object> arguments, String preferredDS) throws SQLException { + Throwable lastException = null; + CachedDataSource active = null; + + // test if there are any connection pools available + LinkedList<CachedDataSource> sources = new LinkedList<CachedDataSource>(this.dsQueue); + if(sources.isEmpty()){ + LOGGER.error("Generated alarm: DBResourceManager.getData - No active DB connection pools are available."); + throw new DBLibException("No active DB connection pools are available in RequestDataWithRecovery call."); + } + if(preferredDS != null && !sources.peek().getDbConnectionName().equals(preferredDS)) { + Collections.reverse(sources); + } + + + // loop through available data sources to retrieve data. + while(!sources.isEmpty()) + { + active = sources.peek(); + + long time = System.currentTimeMillis(); + try { + if(!active.isFabric()) { + CachedDataSource master = findMaster(); + if(master != null) { + active = master; + master = null; + } + } + sources.remove(active); + return active.getData(statement, arguments); + } catch(SQLDataException exc){ + throw exc; + } catch(SQLSyntaxErrorException exc){ + throw exc; + } catch(SQLIntegrityConstraintViolationException exc){ + throw exc; + } catch(Throwable exc){ + lastException = exc; + String message = exc.getMessage(); + if(message == null) { + if(exc.getCause() != null) { + message = exc.getCause().getMessage(); + } + if(message == null) + message = exc.getClass().getName(); + } + LOGGER.error("Generated alarm: "+active.getDbConnectionName()+" - "+message); + handleGetConnectionException(active, exc); + } finally { + if(LOGGER.isDebugEnabled()){ + time = (System.currentTimeMillis() - time); + LOGGER.debug("getData processing time : "+ active.getDbConnectionName()+" "+time+" miliseconds."); + } + } + } + if(lastException instanceof SQLException){ + throw (SQLException)lastException; + } + // repackage the exception + // you are here because either you run out of available data sources + // or the last exception was not of SQLException type. + // repackage the exception + if(lastException == null) { + throw new DBLibException("The operation timed out while waiting to acquire a new connection." ); + } else { + SQLException exception = new DBLibException(lastException.getMessage()); + exception.setStackTrace(lastException.getStackTrace()); + if(lastException.getCause() instanceof SQLException) { + throw (SQLException)lastException.getCause(); + } + throw exception; + } + } + + private CachedRowSet requestDataNoRecovery(String statement, ArrayList<Object> arguments, String preferredDS) throws SQLException { + if(dsQueue.isEmpty()){ + LOGGER.error("Generated alarm: DBResourceManager.getData - No active DB connection pools are available."); + throw new DBLibException("No active DB connection pools are available in RequestDataNoRecovery call."); + } + CachedDataSource active = (CachedDataSource) this.dsQueue.peek(); + long time = System.currentTimeMillis(); + try { + if(!active.isFabric()) { + CachedDataSource master = findMaster(); + if(master != null) + active = master; + } + return active.getData(statement, arguments); +// } catch(SQLDataException exc){ +// throw exc; + } catch(Throwable exc){ + String message = exc.getMessage(); + if(message == null) + message = exc.getClass().getName(); + LOGGER.error("Generated alarm: "+active.getDbConnectionName()+" - "+message); + if(exc instanceof SQLException) + throw (SQLException)exc; + else { + DBLibException excptn = new DBLibException(exc.getMessage()); + excptn.setStackTrace(exc.getStackTrace()); + throw excptn; + } + } finally { + if(LOGGER.isDebugEnabled()){ + time = (System.currentTimeMillis() - time); + LOGGER.debug(">> getData : "+ active.getDbConnectionName()+" "+time+" miliseconds."); + } + } + } + + + /* (non-Javadoc) + * @see org.openecomp.sdnc.sli.resource.dblib.DbLibService#writeData(java.lang.String, java.util.ArrayList, java.lang.String) + */ + @Override + public boolean writeData(String statement, ArrayList<String> arguments, String preferredDS) throws SQLException + { + ArrayList<Object> newList=new ArrayList<Object>(); + if(arguments != null && !arguments.isEmpty()) { + newList.addAll(arguments); + } + + return writeDataNoRecovery(statement, newList, preferredDS); + } + + CachedDataSource findMaster() throws PoolExhaustedException, MySQLNonTransientConnectionException { + CachedDataSource master = null; + CachedDataSource[] dss = this.dsQueue.toArray(new CachedDataSource[0]); + for(int i=0; i<dss.length; i++) { + if(!dss[i].isSlave()) { + master = dss[i]; + if(i != 0) { + dsQueue.remove(master); + dsQueue.add(master); + } + return master; + } + } + if(master == null) { + LOGGER.warn("MASTER not found."); + } + return master; + } + + + private boolean writeDataNoRecovery(String statement, ArrayList<Object> arguments, String preferredDS) throws SQLException { + if(dsQueue.isEmpty()){ + LOGGER.error("Generated alarm: DBResourceManager.getData - No active DB connection pools are available."); + throw new DBLibException("No active DB connection pools are available in RequestDataNoRecovery call."); + } + + boolean initialRequest = true; + boolean retryAllowed = true; + CachedDataSource active = (CachedDataSource) this.dsQueue.peek(); + long time = System.currentTimeMillis(); + while(initialRequest) { + initialRequest = false; + try { + if(!active.isFabric()) { + CachedDataSource master = findMaster(); + if(master != null) { + active = master; + } + } + + return active.writeData(statement, arguments); + } catch(Throwable exc){ + String message = exc.getMessage(); + if(message == null) + message = exc.getClass().getName(); + LOGGER.error("Generated alarm: "+active.getDbConnectionName()+" - "+message); + if(exc instanceof SQLException) { + SQLException sqlExc = SQLException.class.cast(exc); + // handle read-only exception + if(sqlExc.getErrorCode() == 1290 && "HY000".equals(sqlExc.getSQLState())) { + LOGGER.warn("retrying due to: " + sqlExc.getMessage()); + dsQueue.remove(active); + dsQueue.add(active); + if(retryAllowed){ + retryAllowed = false; + initialRequest = true; + continue; + } + } + throw (SQLException)exc; + } else { + DBLibException excptn = new DBLibException(exc.getMessage()); + excptn.setStackTrace(exc.getStackTrace()); + throw excptn; + } + } finally { + if(LOGGER.isDebugEnabled()){ + time = (System.currentTimeMillis() - time); + LOGGER.debug("writeData processing time : "+ active.getDbConnectionName()+" "+time+" miliseconds."); + } + } + } + return true; + } + + private void setDataSource(CachedDataSource dataSource) { + if(dataSource.testConnection(true)){ + this.dsQueue.add(dataSource); + } else { + this.broken.add(dataSource); + } + } + + public Connection getConnection() throws SQLException { + Throwable lastException = null; + CachedDataSource active = null; + + if(dsQueue.isEmpty()){ + throw new DBLibException("No active DB connection pools are available in GetConnection call."); + } + + try { + active = dsQueue.peek(); + CachedDataSource tmpActive = findMaster(); + if(tmpActive != null) { + active = tmpActive; + } + return new DBLibConnection(active.getConnection(), active); + } catch(javax.sql.rowset.spi.SyncFactoryException exc){ + LOGGER.debug("Free memory (bytes): " + Runtime.getRuntime().freeMemory()); + LOGGER.warn("CLASSPATH issue. Allowing retry", exc); + lastException = exc; + } catch(PoolExhaustedException exc) { + throw new NoAvailableConnectionsException(exc); + } catch(MySQLNonTransientConnectionException exc){ + throw new NoAvailableConnectionsException(exc); + } catch(Exception exc){ + lastException = exc; + if(recoveryMode){ + handleGetConnectionException(active, exc); + } else { + if(exc instanceof MySQLNonTransientConnectionException) { + throw new NoAvailableConnectionsException(exc); + } if(exc instanceof SQLException) { + throw (SQLException)exc; + } else { + DBLibException excptn = new DBLibException(exc.getMessage()); + excptn.setStackTrace(exc.getStackTrace()); + throw excptn; + } + } + } catch (Throwable trwb) { + DBLibException excptn = new DBLibException(trwb.getMessage()); + excptn.setStackTrace(trwb.getStackTrace()); + throw excptn; + } finally { + if(LOGGER.isDebugEnabled()){ + displayState(); + } + } + + if(lastException instanceof SQLException){ + throw (SQLException)lastException; + } + // repackage the exception + if(lastException == null) { + throw new DBLibException("The operation timed out while waiting to acquire a new connection." ); + } else { + SQLException exception = new DBLibException(lastException.getMessage()); + exception.setStackTrace(lastException.getStackTrace()); + if(lastException.getCause() instanceof SQLException) { +// exception.setNextException((SQLException)lastException.getCause()); + throw (SQLException)lastException.getCause(); + } + throw exception; + } + } + + public Connection getConnection(String username, String password) + throws SQLException { + CachedDataSource active = null; + + if(dsQueue.isEmpty()){ + throw new DBLibException("No active DB connection pools are available in GetConnection call."); + } + + + try { + active = dsQueue.peek(); + CachedDataSource tmpActive = findMaster(); + if(tmpActive != null) { + active = tmpActive; + } + return active.getConnection(username, password); + } catch(Throwable exc){ + if(recoveryMode){ + handleGetConnectionException(active, exc); + } else { + if(exc instanceof SQLException) + throw (SQLException)exc; + else { + DBLibException excptn = new DBLibException(exc.getMessage()); + excptn.setStackTrace(exc.getStackTrace()); + throw excptn; + } + } + + } + + throw new DBLibException("No connections available in DBResourceManager in GetConnection call."); + } + + private void handleGetConnectionException(CachedDataSource source, Throwable exc) { + try { + if(!source.canTakeOffLine()) + { + LOGGER.error("Could not switch due to blocking"); + return; + } + + boolean removed = dsQueue.remove(source); + if(!broken.contains(source)) + { + if(broken.add(source)) + { + LOGGER.warn("DB Recovery: DataSource <" + source.getDbConnectionName() + "> put in the recovery mode. Reason : " + exc.getMessage()); + } else { + LOGGER.warn("Error putting DataSource <" +source.getDbConnectionName()+ "> in recovery mode."); + } + } else { + LOGGER.info("DB Recovery: DataSource <" + source.getDbConnectionName() + "> already in recovery queue"); + } + if(removed) + { + if(!dsQueue.isEmpty()) + { + LOGGER.warn("DB DataSource <" + dsQueue.peek().getDbConnectionName() + "> became active"); + } + } + } catch (Exception e) { + LOGGER.error("", e); + } + } + + public void cleanUp() { + for(Iterator<CachedDataSource> it=dsQueue.iterator();it.hasNext();){ + CachedDataSource cds = (CachedDataSource)it.next(); + it.remove(); + cds.cleanUp(); + } + + try { + this.terminating = true; + if(broken != null) + { + try { + broken.add( new TerminatingCachedDataSource(null)); + } catch(Exception exc){ + LOGGER.error("Waiting for Worker to stop", exc); + } + } + worker.join(terminationTimeOut); + LOGGER.info("DBResourceManager.RecoveryMgr <"+worker.toString() +"> termination was successful: " + worker.getState()); + } catch(Exception exc){ + LOGGER.error("Waiting for Worker thread to terminate ", exc); + } + } + + public static DBResourceManager create(Properties props) throws Exception { + DBResourceManager dbmanager = new DBResourceManager(props); + dbmanager.config(props); + return dbmanager; + } + + public PrintWriter getLogWriter() throws SQLException { + return ((CachedDataSource)this.dsQueue.peek()).getLogWriter(); + } + + public int getLoginTimeout() throws SQLException { + return ((CachedDataSource)this.dsQueue.peek()).getLoginTimeout(); + } + + public void setLogWriter(PrintWriter out) throws SQLException { + ((CachedDataSource)this.dsQueue.peek()).setLogWriter(out); + } + + public void setLoginTimeout(int seconds) throws SQLException { + ((CachedDataSource)this.dsQueue.peek()).setLoginTimeout(seconds); + } + + public void displayState(){ + if(LOGGER.isDebugEnabled()){ + LOGGER.debug("POOLS : Active = "+dsQueue.size() + ";\t Broken = "+broken.size()); + CachedDataSource current = (CachedDataSource)dsQueue.peek(); + if(current != null) { + LOGGER.debug("POOL : Active name = \'"+current.getDbConnectionName()+ "\'"); + } + } + } + + /* (non-Javadoc) + * @see org.openecomp.sdnc.sli.resource.dblib.DbLibService#isActive() + */ + @Override + public boolean isActive() { + return this.dsQueue.size()>0; + } + + public String getActiveStatus(){ + return "Connected: " + dsQueue.size()+"\tIn-recovery: "+broken.size(); + } + + public String getDBStatus(boolean htmlFormat) { + StringBuilder buffer = new StringBuilder(); + + ArrayList<CachedDataSource> list = new ArrayList<CachedDataSource>(); + list.addAll(dsQueue); + list.addAll(broken); + if (htmlFormat) + { + buffer.append("<tr class=\"headerRow\"><th id=\"header1\">") + .append("Name:").append("</th>"); + for (int i = 0; i < list.size(); i++) { + buffer.append("<th id=\"header").append(2 + i).append("\">"); + buffer.append(((CachedDataSource) list.get(i)).getDbConnectionName()).append("</th>"); + } + buffer.append("</tr>"); + + buffer.append("<tr><td>State:</td>"); + for (int i = 0; i < list.size(); i++) { + if (broken.contains(list.get(i))) { + buffer.append("<td>in recovery</td>"); + } + if (dsQueue.contains(list.get(i))) { + if (dsQueue.peek() == list.get(i)) + buffer.append("<td>active</td>"); + else + buffer.append("<td>standby</td>"); + } + } + buffer.append("</tr>"); + + } else { + for (int i = 0; i < list.size(); i++) { + buffer.append("Name: ").append(((CachedDataSource) list.get(i)).getDbConnectionName()); + buffer.append("\tState: "); + if (broken.contains(list.get(i))) { + buffer.append("in recovery"); + } else + if (dsQueue.contains(list.get(i))) { + if (dsQueue.peek() == list.get(i)) + buffer.append("active"); + else + buffer.append("standby"); + } + + buffer.append("\n"); + + } + } + return buffer.toString(); + } + + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return false; + } + + public <T> T unwrap(Class<T> iface) throws SQLException { + return null; + } + + /** + * @return the monitorDbResponse + */ + public final boolean isMonitorDbResponse() { + return recoveryMode && monitorDbResponse; + } + + public void test(){ + CachedDataSource obj = dsQueue.peek(); + Exception ption = new Exception(); + try { + for(int i=0; i<5; i++) + { + handleGetConnectionException(obj, ption); + } + } catch(Throwable exc){ + LOGGER.warn("", exc); + } + } + + public String getPreferredDSName(){ + if(isActive()){ + return getPreferredDataSourceName(dsSelector); + } + return ""; + } + + public String getPreferredDataSourceName(AtomicBoolean flipper) { + + LinkedList<CachedDataSource> snapshot = new LinkedList<CachedDataSource>(dsQueue); + if(snapshot.size() > 1){ + CachedDataSource first = snapshot.getFirst(); + CachedDataSource last = snapshot.getLast(); + + int delta = first.getMonitor().getPorcessedConnectionsCount() - last.getMonitor().getPorcessedConnectionsCount(); + if(delta < 0) { + flipper.set(false); + } else if(delta > 0) { + flipper.set(true); + } else { + // check the last value and return !last + flipper.getAndSet(!flipper.get()); + } + + if (flipper.get()) + Collections.reverse(snapshot); + } + return snapshot.peek().getDbConnectionName(); + } + + public java.util.logging.Logger getParentLogger() + throws SQLFeatureNotSupportedException { + return null; + } + + public String getMasterName() { + if(isActive()){ + return getMasterDataSourceName(dsSelector); + } + return ""; + } + + + private String getMasterDataSourceName(AtomicBoolean flipper) { + + LinkedList<CachedDataSource> snapshot = new LinkedList<CachedDataSource>(dsQueue); + if(snapshot.size() > 1){ + CachedDataSource first = snapshot.getFirst(); + CachedDataSource last = snapshot.getLast(); + + int delta = first.getMonitor().getPorcessedConnectionsCount() - last.getMonitor().getPorcessedConnectionsCount(); + if(delta < 0) { + flipper.set(false); + } else if(delta > 0) { + flipper.set(true); + } else { + // check the last value and return !last + flipper.getAndSet(!flipper.get()); + } + + if (flipper.get()) + Collections.reverse(snapshot); + } + return snapshot.peek().getDbConnectionName(); + } + + class RemindTask extends TimerTask { + public void run() { + CachedDataSource ds = dsQueue.peek(); + if(ds != null) + ds.getPoolInfo(false); + } + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBResourceObserver.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBResourceObserver.java new file mode 100644 index 000000000..e06779f35 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DBResourceObserver.java @@ -0,0 +1,27 @@ +/*- + * ============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; + +import java.util.Observer; + +public interface DBResourceObserver extends Observer { + public boolean isMonitorDbResponse(); +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DataAccessor.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DataAccessor.java new file mode 100644 index 000000000..cd054a51d --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DataAccessor.java @@ -0,0 +1,33 @@ +/*- + * ============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; + +import java.sql.SQLException; +import java.util.ArrayList; + +import javax.sql.rowset.CachedRowSet; + +public interface DataAccessor { + + public abstract CachedRowSet getData(String statement, ArrayList<String> arguments, String preferredDS) + throws SQLException; + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DataSourceComparator.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DataSourceComparator.java new file mode 100644 index 000000000..37d625136 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DataSourceComparator.java @@ -0,0 +1,33 @@ +/*- + * ============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; + +import java.util.Comparator; + +public interface DataSourceComparator extends Comparator <CachedDataSource>{ + + public abstract CachedDataSource getLastUsed(); + + public abstract void setLastUsed(CachedDataSource lastUsed); + + public abstract int compare(CachedDataSource ds1, CachedDataSource ds2); + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DbLibService.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DbLibService.java new file mode 100644 index 000000000..25edd1f07 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DbLibService.java @@ -0,0 +1,46 @@ +/*- + * ============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; + +import java.sql.SQLException; +import java.util.ArrayList; + +import javax.sql.rowset.CachedRowSet; + +public interface DbLibService { + + /* (non-Javadoc) + * @see DataAccessor#getData(java.lang.String, java.util.ArrayList) + */ + public abstract CachedRowSet getData(String statement, + ArrayList<String> arguments, String preferredDS) + throws SQLException; + + /* (non-Javadoc) + * @see DataAccessor#writeData(java.lang.String, java.util.ArrayList) + */ + public abstract boolean writeData(String statement, + ArrayList<String> arguments, String preferredDS) + throws SQLException; + + public abstract boolean isActive(); + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DblibConfigurationException.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DblibConfigurationException.java new file mode 100644 index 000000000..17700a5ee --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/DblibConfigurationException.java @@ -0,0 +1,45 @@ +/*- + * ============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; + + +public class DblibConfigurationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public DblibConfigurationException() + { + super(); + } + + public DblibConfigurationException(String msg) + { + super(msg); + } + + public DblibConfigurationException(String msg, Throwable t) + { + super(msg, t); + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/NoAvailableConnectionsException.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/NoAvailableConnectionsException.java new file mode 100644 index 000000000..16895b4d5 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/NoAvailableConnectionsException.java @@ -0,0 +1,36 @@ +/*- + * ============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; + +import java.sql.SQLException; + +public class NoAvailableConnectionsException extends SQLException { + + /** + * + */ + private static final long serialVersionUID = -6259205931674413018L; + + public NoAvailableConnectionsException(Exception exc) { + super(exc); + } + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/TerminatingCachedDataSource.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/TerminatingCachedDataSource.java new file mode 100644 index 000000000..234bbed0c --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/TerminatingCachedDataSource.java @@ -0,0 +1,82 @@ +/*- + * ============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; + +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +import org.openecomp.sdnc.sli.resource.dblib.config.BaseDBConfiguration; +import org.openecomp.sdnc.sli.resource.dblib.pm.SQLExecutionMonitorObserver; + + +public class TerminatingCachedDataSource extends CachedDataSource implements SQLExecutionMonitorObserver { + + public TerminatingCachedDataSource(BaseDBConfiguration jdbcElem) throws DBConfigException { + super(jdbcElem); + } + + protected void configure(BaseDBConfiguration jdbcElem) throws DBConfigException { + // no action + } + + public long getInterval() { + return 1000; + } + + public long getInitialDelay() { + return 1000; + } + + public long getExpectedCompletionTime() { + return 50; + } + + public void setExpectedCompletionTime(long value) { + + } + + public void setInterval(long value) { + + } + + public void setInitialDelay(long value) { + + } + + public long getUnprocessedFailoverThreshold() { + return 3; + } + + public void setUnprocessedFailoverThreshold(long value) { + + } + + public int compareTo(CachedDataSource ods) + { + return 0; + } + + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/BaseDBConfiguration.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/BaseDBConfiguration.java new file mode 100644 index 000000000..976b1cf2d --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/BaseDBConfiguration.java @@ -0,0 +1,104 @@ +/*- + * ============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.config; + +import java.util.Properties; + +public abstract class BaseDBConfiguration { + public static final String DATABASE_TYPE = "org.openecomp.sdnc.sli.dbtype"; + public static final String DATABASE_URL = "org.openecomp.sdnc.sli.jdbc.url"; + public static final String DATABASE_NAME = "org.openecomp.sdnc.sli.jdbc.database"; + public static final String CONNECTION_NAME = "org.openecomp.sdnc.sli.jdbc.connection.name"; + public static final String DATABASE_USER = "org.openecomp.sdnc.sli.jdbc.user"; + public static final String DATABASE_PSSWD = "org.openecomp.sdnc.sli.jdbc.password"; + public static final String CONNECTION_TIMEOUT="org.openecomp.sdnc.sli.jdbc.connection.timeout"; + public static final String REQUEST_TIMEOUT = "org.openecomp.sdnc.sli.jdbc.request.timeout"; + public static final String MIN_LIMIT = "org.openecomp.sdnc.sli.jdbc.limit.min"; + public static final String MAX_LIMIT = "org.openecomp.sdnc.sli.jdbc.limit.max"; + public static final String INIT_LIMIT = "org.openecomp.sdnc.sli.jdbc.limit.init"; + public static final String DATABASE_HOSTS = "org.openecomp.sdnc.sli.jdbc.hosts"; + + + protected final Properties props; + + public BaseDBConfiguration(Properties properties) { + this.props = properties; + } + + public int getConnTimeout() { + try { + String value = props.getProperty(CONNECTION_TIMEOUT); + return Integer.parseInt(value); + } catch(Exception exc) { + return -1; + } + } + + public int getRequestTimeout() { + try { + String value = props.getProperty(REQUEST_TIMEOUT); + if(value == null) + return -1; + return Integer.parseInt(value); + } catch(Exception exc) { + return -1; + } + } + + public String getDbConnectionName() { + return props.getProperty(CONNECTION_NAME); + } + + public String getDatabaseName() { + return props.getProperty(DATABASE_NAME); + } + + public String getDbUserId() { + return props.getProperty(DATABASE_USER); + } + + public String getDbPasswd() { + return props.getProperty(DATABASE_PSSWD); + } + + public int getDbMinLimit() { + String value = props.getProperty(MIN_LIMIT); + return Integer.parseInt(value); + } + + public int getDbMaxLimit() { + String value = props.getProperty(MAX_LIMIT); + return Integer.parseInt(value); + } + + public int getDbInitialLimit() { + String value = props.getProperty(INIT_LIMIT); + return Integer.parseInt(value); + } + + public String getDbUrl() { + return props.getProperty(DATABASE_URL); + } + + public String getServerGroup() { + return null; + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/DbConfigPool.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/DbConfigPool.java new file mode 100644 index 000000000..117f9321d --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/DbConfigPool.java @@ -0,0 +1,56 @@ +/*- + * ============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.config; + +import java.util.ArrayList; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbConfigPool { + private static Logger LOGGER = LoggerFactory.getLogger(DbConfigPool.class); + + private final String type; + + private ArrayList<BaseDBConfiguration> configurations = new ArrayList<BaseDBConfiguration>(); + + public DbConfigPool(Properties properties) { + LOGGER.debug("Initializing DbConfigType"); + type = properties.getProperty(BaseDBConfiguration.DATABASE_TYPE, "JDBC").toUpperCase(); + } + + public int getTimeout() { + // TODO Auto-generated method stub + return 0; + } + + public String getType() { + return type; + } + + public JDBCConfiguration[] getJDBCbSourceArray() { + return configurations.toArray(new JDBCConfiguration[configurations.size()]); + } + + public void addConfiguration(BaseDBConfiguration config) { + configurations.add(config); + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/JDBCConfiguration.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/JDBCConfiguration.java new file mode 100644 index 000000000..cb6ea3e5c --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/config/JDBCConfiguration.java @@ -0,0 +1,31 @@ +/*- + * ============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.config; + +import java.util.Properties; + +public class JDBCConfiguration extends BaseDBConfiguration { + + public JDBCConfiguration(Properties xmlElem) { + super(xmlElem); + } + +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractDBResourceManagerFactory.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractDBResourceManagerFactory.java new file mode 100644 index 000000000..f4291a7dd --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractDBResourceManagerFactory.java @@ -0,0 +1,39 @@ +/*- + * ============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.factory; + +import org.openecomp.sdnc.sli.resource.dblib.jdbc.JdbcDbResourceManagerFactory; + +/** + * @version $Revision: 1.1 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ +public class AbstractDBResourceManagerFactory { + + public static AbstractResourceManagerFactory getFactory(String type) throws FactoryNotDefinedException { + + // JDBC + return JdbcDbResourceManagerFactory.createIntstance(); + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractResourceManagerFactory.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractResourceManagerFactory.java new file mode 100644 index 000000000..0f58a3f03 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/AbstractResourceManagerFactory.java @@ -0,0 +1,104 @@ +/*- + * ============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.factory; + + +import java.sql.SQLException; +import java.util.Set; +import java.util.concurrent.Callable; + +import org.openecomp.sdnc.sli.resource.dblib.CachedDataSource; +import org.openecomp.sdnc.sli.resource.dblib.CachedDataSourceFactory; +import org.openecomp.sdnc.sli.resource.dblib.DBConfigException; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @version $Revision: 1.6 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ +public abstract class AbstractResourceManagerFactory { + private static Logger LOGGER = LoggerFactory.getLogger(AbstractResourceManagerFactory.class); + + 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> + { + private BaseDBConfiguration config = null; + private Set<DBInitTask> activeTasks; + + public DBInitTask(JDBCConfiguration jdbcconfig, Set<DBInitTask> tasks) { + this.config = jdbcconfig; + this.activeTasks = tasks; + } + + public CachedDataSource call() throws Exception { + CachedDataSource ds = null; + try { + ds = CachedDataSourceFactory.createDataSource(config); + return ds; + } finally { + synchronized(activeTasks) { + activeTasks.remove(this); + if (activeTasks.isEmpty()) { + final Runnable closure = new Runnable() { + + public void run() { + try { + Thread.sleep(300); + } catch (Exception e) { + } + synchronized(activeTasks) { + activeTasks.notifyAll(); + } + } + }; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Completed CachedDataSource.Call and notifyAll from " + ds.getDbConnectionName()); + } + Thread worker = new Thread(closure); + worker.setDaemon(true); + worker.start(); + } else { + if (LOGGER.isDebugEnabled()) { + if (ds != null) { + LOGGER.debug("Completed CachedDataSource.Call from " + ds.getDbConnectionName()); + } + } + } + } + } + } + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/DBConfigFactory.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/DBConfigFactory.java new file mode 100644 index 000000000..8aadcae6b --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/DBConfigFactory.java @@ -0,0 +1,100 @@ +/*- + * ============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.factory; + + +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; + +/** + * @version $Revision: 1.1 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki 01/17/08 Initial version + */ +public class DBConfigFactory { + + public static DbConfigPool createConfig(Properties resource) { + return getConfigparams(resource); + } + + static DbConfigPool getConfigparams(Properties properties){ + DbConfigPool xmlConfig = new DbConfigPool(properties); + ArrayList<Properties> propertySets = new ArrayList<Properties>(); + + if("JDBC".equalsIgnoreCase(xmlConfig.getType())) { + String hosts = properties.getProperty(BaseDBConfiguration.DATABASE_HOSTS); + if(hosts == null || hosts.isEmpty()) { + propertySets.add(properties); + } else { + String[] newhost = hosts.split(","); + for(int i=0; i< newhost.length; i++) { + Properties localset = new Properties(); + localset.putAll(properties); + String url = localset.getProperty(BaseDBConfiguration.DATABASE_URL); + if(url.contains("DBHOST")) + url = url.replace("DBHOST", newhost[i]); + if(url.contains("dbhost")) + url = url.replace("dbhost", newhost[i]); + localset.setProperty(BaseDBConfiguration.DATABASE_URL, url); + localset.setProperty(BaseDBConfiguration.CONNECTION_NAME, newhost[i]); + propertySets.add(localset); + } + } + } else { + propertySets.add(properties); + } + try { + Iterator<Properties> it = propertySets.iterator(); + while(it.hasNext()) { + BaseDBConfiguration config = parse(it.next()); + xmlConfig.addConfiguration(config); + } + + } catch (Exception e) { + LoggerFactory.getLogger(DBConfigFactory.class).warn("",e); + } + + return xmlConfig; + } + + public static BaseDBConfiguration parse(Properties props) throws Exception { + + String type = props.getProperty(BaseDBConfiguration.DATABASE_TYPE); + + BaseDBConfiguration config = null; + + if("JDBC".equalsIgnoreCase(type)) { + config = new JDBCConfiguration(props); + } + + return config; + + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/FactoryNotDefinedException.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/FactoryNotDefinedException.java new file mode 100644 index 000000000..e38cd3519 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/factory/FactoryNotDefinedException.java @@ -0,0 +1,37 @@ +/*- + * ============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.factory; + + +/** + * @version 1.3 + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki 01/16/08 Initial version + */ +public class FactoryNotDefinedException extends Exception { + + public FactoryNotDefinedException(String message) { + super(message); + } + +} 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 index 000000000..90c76f637 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/JdbcDBCachedDataSource.java @@ -0,0 +1,249 @@ +/*- + * ============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 + */ + 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/jdbc/JdbcDbResourceManagerFactory.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/JdbcDbResourceManagerFactory.java new file mode 100644 index 000000000..84399dfd9 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/JdbcDbResourceManagerFactory.java @@ -0,0 +1,186 @@ +/*- + * ============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.SQLException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +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.DataSourceComparator; +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.factory.AbstractResourceManagerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @version $Revision: 1.6 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ +public class JdbcDbResourceManagerFactory extends AbstractResourceManagerFactory { + private static Logger LOGGER = LoggerFactory.getLogger(JdbcDbResourceManagerFactory.class ); + private JdbcDbResourceManagerFactory(){ + + } + + class MyFutureTask extends FutureTask<CachedDataSource> + { + + public MyFutureTask(Callable<CachedDataSource> result) { + super(result); + } + + } + + public CachedDataSource[] initDBResourceManager(DbConfigPool dbConfig, DBResourceManager manager, String sourceName) throws SQLException + { + // here create the data sources objects + JDBCConfiguration[] list = dbConfig.getJDBCbSourceArray(); + CachedDataSource[] cachedDS = new CachedDataSource[1]; + + for(int i=0, max=list.length; i<max; i++){ + if(!sourceName.equals(list[i].getDbConnectionName())) + continue; + + JDBCConfiguration config = list[i]; + CachedDataSource dataSource = CachedDataSourceFactory.createDataSource(config); + cachedDS[0] = dataSource; + } + return cachedDS; + } + + public CachedDataSource[] initDBResourceManager(DbConfigPool dbConfig, DBResourceManager manager) /* throws Exception */ { + + ExecutorService threadExecutor = Executors.newFixedThreadPool(2); + // here create the data sources objects + JDBCConfiguration[] list = dbConfig.getJDBCbSourceArray(); + + MyFutureTask[] futures = new MyFutureTask[list.length]; + final Set<DBInitTask> tasks = new HashSet<DBInitTask>(); + if(LOGGER.isDebugEnabled()) { + LOGGER.debug("Creating " + list.length + " datasources."); + } + + for(int i=0, max=list.length; i<max; i++){ + JDBCConfiguration config = list[i]; + + 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++){ + if(LOGGER.isDebugEnabled()) + LOGGER.debug("Starting executor tasks."); + threadExecutor.execute(futures[i]); + } + // the timeout param is set is seconds. + long timeout = ((dbConfig.getTimeout() <= 0) ? 60L : dbConfig.getTimeout()); + LOGGER.debug("Timeout set to " +timeout+" seconds"); + 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 |= cachedDS[i].isInitialized(); + if(cachedDS[i].isInitialized()) + LOGGER.info("DataSource "+list[i].getDbConnectionName()+" initialized successfully"); + else + LOGGER.error("DataSource "+list[i].getDbConnectionName()+" initialization failed"); + } else { + if(obj == null) { + LOGGER.warn("DataSource " + i + " initialization failed. Returned object is null"); + } else { + LOGGER.warn("DataSource " + i + " initialization failed. Returned object is " + obj.getClass().getName()); + } + } + } catch (InterruptedException exc) { + LOGGER.error("DataSource "+list[i].getDbConnectionName()+" initialization failed", exc); + } catch (ExecutionException exc) { + LOGGER.error("DataSource "+list[i].getDbConnectionName()+" initialization failed", exc); + } catch (Exception exc) { + LOGGER.error("DataSource "+list[i].getDbConnectionName()+" initialization failed", exc); + } + } else { + try { + obj = futures[i].get(); + if(obj instanceof CachedDataSource){ + LOGGER.warn("DataSource "+((CachedDataSource)obj).getDbConnectionName()+" failed"); + } else { + if(obj == null) { + LOGGER.warn("DataSource " + i + " initialization failed. Returned object is null"); + } else { + LOGGER.warn("DataSource " + i + " initialization failed. Returned object is " + obj.getClass().getName()); + } + } + } catch (Exception exc) { + LOGGER.error("DataSource "+list[i].getDbConnectionName()+" initialization failed", exc); + } + } + } + + if(!initialized){ + new Error("Failed to initialize DB Library."); + } + return cachedDS; + } + + public static AbstractResourceManagerFactory createIntstance() { + return new JdbcDbResourceManagerFactory(); + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/MySQLCachedDataSource.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/MySQLCachedDataSource.java new file mode 100644 index 000000000..a5482d084 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/jdbc/MySQLCachedDataSource.java @@ -0,0 +1,217 @@ +/*- + * ============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.SQLFeatureNotSupportedException; +import java.util.Properties; + +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; + + + + +/** + * @version $Revision: 1.7 $ + * Change Log + * Author Date Comments + * ============== ======== ==================================================== + * Rich Tabedzki + */ + +public class MySQLCachedDataSource extends CachedDataSource +{ + private String dbUserId; + private String dbPasswd; + private String dbUrl; + + private String minLimit; + private String maxLimit; + private String initialLimit; + + private static final String AS_CONF_ERROR = "AS_CONF_ERROR: "; + + private static Logger LOGGER = LoggerFactory.getLogger(MySQLCachedDataSource.class); + + /** + * @param jdbcElem + */ + public MySQLCachedDataSource(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 = Integer.toString(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 = Integer.toString(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 = Integer.toString(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 { + + MysqlDataSource dataSource = new MysqlDataSource(); + dataSource.setUser(dbUserId); + dataSource.setPassword(dbPasswd); + dataSource.setURL(dbUrl); +// dataSource.setInitialSize(5); +// dataSource.setMaxTotal(60); +// dataSource.setMaxActive(100); +// dataSource.setMaxWait(10000); +// dataSource.setMaxIdle(10); + + Properties connAttr = new Properties(); + + connAttr.setProperty("MinLimit", minLimit); + connAttr.setProperty("MaxLimit", maxLimit); + connAttr.setProperty("InitialLimit", initialLimit); + connAttr.setProperty("TRANSACTION_ISOLATION","SERIALIZABLE"); + connAttr.setProperty("CONNECTION_TAG", dbConnectionName.toUpperCase()+"_CONNECTION"); + connAttr.setProperty("InactivityTimeout", "900"); + connAttr.setProperty("AbandonedConnectionTimeout", "600"); + connAttr.setProperty("PropertyCheckInterval", "60"); + connAttr.setProperty("ValidateConnection", "true"); + + + synchronized(this) + { + this.ds = dataSource; + + 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 MySQLCachedDataSource createInstance(BaseDBConfiguration config) /*throws Exception*/ { + return new MySQLCachedDataSource(config); + } + + public String toString(){ + return getDbConnectionName(); + } + + public java.util.logging.Logger getParentLogger() + throws SQLFeatureNotSupportedException { + // TODO Auto-generated method stub + return null; + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/PollingWorker.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/PollingWorker.java new file mode 100644 index 000000000..de87fa7e8 --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/PollingWorker.java @@ -0,0 +1,217 @@ +/*- + * ============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.pm; + +import java.util.Iterator; +import java.util.Properties; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicLong; + +public class PollingWorker implements Runnable { + + private Logger LOGGER = LoggerFactory.getLogger(PollingWorker.class); + + private static PollingWorker self = null; + + private LinkedBlockingQueue tasks = new LinkedBlockingQueue(100); + private long interval = 1000L; + private Thread worker = null; + private AtomicLong[] counters = null; + private int[] bucketUnit = null; + private static boolean enabled = false; + private Timer timer = null; + + public static void post(long starttime){ + PollingWorker temp = self; + if(temp != null && enabled) { + temp.register(new TestSample(starttime)); + } + } + + public static void createInistance(Properties props){ + self = new PollingWorker(props); + } + + private PollingWorker(Properties ctxprops){ + if(ctxprops==null || ctxprops.getProperty("org.openecomp.sdnc.dblib.pm") == null){ + enabled = false; + } else { + if("true".equalsIgnoreCase((String)ctxprops.getProperty("org.openecomp.sdnc.dblib.pm"))){ + enabled = true; + } else { + enabled = false; + } + } + + interval = Long.parseLong(( ctxprops == null || ctxprops.getProperty("org.openecomp.sdnc.dblib.pm.interval") == null) ? "60" : (String)ctxprops.getProperty("org.openecomp.sdnc.dblib.pm.interval")); + // '0' bucket is to count exceptions + String sampling[] = ((ctxprops == null || ctxprops.getProperty("org.openecomp.sdnc.dblib.pm.sampling")==null) ? "0,2,5,10,20,50,100" : (String)ctxprops.getProperty("org.openecomp.sdnc.dblib.pm.sampling")).split(","); + + if(enabled){ + bucketUnit = new int[sampling.length]; + for(int i=0, max = bucketUnit.length; i<max; i++){ + bucketUnit[i] = Integer.parseInt(sampling[i].trim()); + } + counters = new AtomicLong[bucketUnit.length+1]; + for(int i=0, max = counters.length; i<max; i++){ + counters[i] = new AtomicLong(); + } + worker = new Thread(this); + worker.setDaemon(true); + worker.start(); + timer = new Timer(true); + timer.schedule(new MyTimerTask(), interval*1000L, interval*1000L); + } + } + + private void register(TestSample object){ + try { + tasks.add(object); + } catch(Throwable exc) { + // if cannot add an object to the queue, do nothing + } + } + + private void deRegister(TestSample object){ + tasks.remove(object); + } + + public void run() { + for(;;){ + Set data = new TreeSet(); + tasks.drainTo(data); + for(Iterator it = data.iterator(); it.hasNext(); ){ + Object next = it.next(); + if(next instanceof TestSample){ + consume((TestSample)next); + } else { + System.out.println(next.getClass().getName()); + } + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + public void clearReqister(){ + AtomicLong[] tmp = new AtomicLong[counters.length]; + for(int i=0, max = tmp.length; i<max; i++){ + tmp[i] = new AtomicLong(); + } + AtomicLong[] tmp2 = counters; + synchronized(tmp2){ + counters = tmp; + } + StringBuffer sb = new StringBuffer("CPM: "); + for(int i=0, max = tmp2.length; i < max; i++){ + if(i==0 && bucketUnit[0]==0){ + sb.append("[Exc]="); + } else { + sb.append("["); + if(i==bucketUnit.length){ + sb.append("Other]="); + } else { + sb.append(bucketUnit[i]).append(" ms]="); + } + } + sb.append(tmp2[i].get()).append("\t"); + } + LOGGER.info(sb.toString()); + } + + class MyTimerTask extends TimerTask{ + + public void run() { + + clearReqister(); + } + + } + + private void consume(TestSample probe) { + AtomicLong[] tmp = counters; + synchronized(tmp){ + counters[getBucket(probe.getDuration())].incrementAndGet(); + } + } + + /* + * This method is used to find the offset of the bucket in + * counters. 'counters' array is 1 size longer than bucketUnit, + * hence by default it returns 'bucketUnit.length' + */ + private int getBucket(long difftime){ + for(int i=0; i<bucketUnit.length; i++){ + if(difftime < bucketUnit[i]){ + return i; + } + } + return bucketUnit.length; + } + + private static boolean isEnabled() { + return enabled; + } + /** + * @author Rich Tabedzki + * A helper class to pass measured parameter to the counter. + */ + static class TestSample implements Comparable{ + private long starttime; + private long endtime; + + public TestSample(long starttime) { + this.endtime = System.currentTimeMillis(); + this.starttime = starttime; + } + + public long getDuration(){ + return endtime - starttime; + } + + public int compareTo(Object o) { + if(o instanceof TestSample){ + TestSample x = (TestSample)o; + if(starttime < x.starttime) + return 1; + if(endtime < x.endtime) + return 1; + if(starttime > x.starttime) + return -1; + if(endtime > x.endtime) + return -1; + return 0; + } + return 1; + } + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/SQLExecutionMonitor.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/SQLExecutionMonitor.java new file mode 100644 index 000000000..c58c9db7d --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/SQLExecutionMonitor.java @@ -0,0 +1,237 @@ +/*- + * ============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.pm; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; +import java.util.Observable; +import java.util.Observer; +import java.util.SortedSet; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicLong; + +import org.openecomp.sdnc.sli.resource.dblib.DBResourceObserver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SQLExecutionMonitor extends Observable +{ + private static Logger LOGGER = LoggerFactory.getLogger(SQLExecutionMonitor.class); + + final static long MILISECOND = 1000000L; + final static long SECOND = 1000L*MILISECOND; + + private final Timer timer; + // collection + private final SortedSet<TestObject> innerSet; + private SQLExecutionMonitorObserver parent = null; + private final AtomicLong completionCounter; + private boolean activeState = false; + private final long interval; + private final long initialDelay; + private final long EXPECTED_TIME_TO_COMPLETE; + private final long UNPROCESSED_FAILOVER_THRESHOLD; + + private final class MonitoringTask extends TimerTask + { + + public void run() + { + try { + TestObject testObj = new TestObject(); + testObj.setStartTime(testObj.getStartTime() - EXPECTED_TIME_TO_COMPLETE); + + // take a snapshot of the current task list + TestObject[] array = innerSet.toArray(new TestObject[0]); + SortedSet<TestObject> copyCurrent = new TreeSet<TestObject>(Arrays.asList(array)); + // get the list of the tasks that are older than the specified + // interval. + SortedSet<TestObject> unprocessed = copyCurrent.headSet(testObj); + + long succesfulCount = completionCounter.get(); + int unprocessedCount = unprocessed.size(); + + if (!unprocessed.isEmpty() && unprocessedCount > UNPROCESSED_FAILOVER_THRESHOLD && succesfulCount == 0) + { + // switch the Connection Pool to passive + setChanged(); + notifyObservers("Open JDBC requests=" + unprocessedCount+" in "+SQLExecutionMonitor.this.parent.getDbConnectionName()); + } + } catch (Exception exc) { + LOGGER.error("", exc); + } finally { + completionCounter.set(0L); + } + } + } + + public static class TestObject implements Comparable<TestObject>, Serializable + { + + private static final long serialVersionUID = 1L; + private long starttime; + private long randId; + + public TestObject() + { + starttime = System.nanoTime(); + } + + public long getStartTime() + { + return starttime; + } + + public void setStartTime(long newTime) + { + starttime = newTime; + } + + public int compareTo(TestObject o) + { + if( this == o) + return 0; + if(this.starttime > o.getStartTime()) + return 1; + if(this.starttime < o.getStartTime()) + return -1; + + if(this.hashCode() > o.hashCode()) + return 1; + if(this.hashCode() < o.hashCode()) + return -1; + + return 0; + } + + public String toString() + { + return Long.toString(starttime)+"#"+ this.hashCode(); + } + + public boolean equals(Object obj) + { + if (this == obj) + return true; + + return (obj instanceof TestObject + && starttime == ((TestObject) obj).getStartTime() + && hashCode() == ((TestObject) obj).hashCode()); + } + } + + public SQLExecutionMonitor(SQLExecutionMonitorObserver parent) + { + this.parent = parent; + completionCounter = new AtomicLong(0L); + interval = parent.getInterval(); + initialDelay = parent.getInitialDelay(); + this.UNPROCESSED_FAILOVER_THRESHOLD = parent.getUnprocessedFailoverThreshold(); + this.EXPECTED_TIME_TO_COMPLETE = parent.getExpectedCompletionTime()*MILISECOND; + + innerSet = Collections.synchronizedSortedSet(new TreeSet<TestObject>()); + timer = new Timer(); + } + + public void cleanup() + { + timer.cancel(); + } + + // registerRequest + public TestObject registerRequest() + { + if(activeState) + { + TestObject test = new TestObject(); + if(innerSet.add(test)) + return test; + } + return null; + } + + // deregisterSuccessfulReguest + public boolean deregisterReguest(TestObject test) + { + if(test == null) + return false; + // remove from the collection + if(innerSet.remove(test) && activeState) + { + completionCounter.incrementAndGet(); + return true; + } + return false; + } + + public void terminate() { + timer.cancel(); + } + + /** + * @return the parent + */ + public final Object getParent() { + return parent; + } + + public void addObserver(Observer observer) + { + if(observer instanceof DBResourceObserver) + { + DBResourceObserver dbObserver = (DBResourceObserver)observer; + if(dbObserver.isMonitorDbResponse()) + { + if(countObservers() == 0) + { + TimerTask remindTask = new MonitoringTask(); + timer.schedule(remindTask, initialDelay, interval); + activeState = true; + } + } + } + super.addObserver(observer); + } + + public void deleteObserver(Observer observer) + { + super.deleteObserver(observer); + if(observer instanceof DBResourceObserver) + { + DBResourceObserver dbObserver = (DBResourceObserver)observer; + if(dbObserver.isMonitorDbResponse()) + { + if(countObservers() == 0) + { + timer.cancel(); + activeState = false; + } + } + } + } + + public final int getPorcessedConnectionsCount() { + return innerSet.size(); + } +} diff --git a/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/SQLExecutionMonitorObserver.java b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/SQLExecutionMonitorObserver.java new file mode 100644 index 000000000..1f329750b --- /dev/null +++ b/dblib/provider/src/main/java/org/openecomp/sdnc/sli/resource/dblib/pm/SQLExecutionMonitorObserver.java @@ -0,0 +1,37 @@ +/*- + * ============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.pm; + +public interface SQLExecutionMonitorObserver { + public String getDbConnectionName(); + + public long getInterval(); + public void setInterval(long value); + + public long getInitialDelay(); + public void setInitialDelay(long value); + + public long getExpectedCompletionTime(); + public void setExpectedCompletionTime(long value); + + public long getUnprocessedFailoverThreshold(); + public void setUnprocessedFailoverThreshold(long value); +} diff --git a/dblib/provider/src/main/resources/dblib.properties b/dblib/provider/src/main/resources/dblib.properties new file mode 100755 index 000000000..ac295c78d --- /dev/null +++ b/dblib/provider/src/main/resources/dblib.properties @@ -0,0 +1,13 @@ +org.openecomp.sdnc.sli.dbtype=jdbc +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={user for sdnctl} +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 +org.openecomp.sdnc.sli.jdbc.request.timeout=100 +org.openecomp.sdnc.sli.jdbc.limit.init=10 +org.openecomp.sdnc.sli.jdbc.limit.min=10 +org.openecomp.sdnc.sli.jdbc.limit.max=20 |