diff options
author | Anand <ac204h@att.com> | 2018-01-04 19:35:51 -0500 |
---|---|---|
committer | Skip Wonnell <skip@att.com> | 2018-01-08 22:09:50 +0000 |
commit | 36bcd566167f2f91c0e8e7a304fce5f6bc150776 (patch) | |
tree | 7ba7acfee7e520da83a2b6286ea464285bc8cf67 /appc-dispatcher/appc-dispatcher-common | |
parent | 38d293d605b42f88c9c82319ba848b4b81e45b64 (diff) |
Include impacted changes for APPC-346,APPC-348
Issue-ID: APPC-347
Change-Id: I399bc2a1e0dfd481e103032a373bb80fce5baf41
Signed-off-by: Anand <ac204h@att.com>
Diffstat (limited to 'appc-dispatcher/appc-dispatcher-common')
69 files changed, 4226 insertions, 1766 deletions
diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/pom.xml b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/pom.xml index 749764bc7..60f244b9e 100644 --- a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/pom.xml @@ -1,62 +1,110 @@ -<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> +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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.onap.appc</groupId> <artifactId>appc-dispatcher-common</artifactId> <version>1.3.0-SNAPSHOT</version> </parent> - <artifactId>appc-data-access-lib</artifactId> - <packaging>bundle</packaging> - <name>appc-data-access-lib</name> - <url>http://maven.apache.org</url> + <artifactId>appc-data-access-lib</artifactId> + <packaging>bundle</packaging> + <name>APPC Dispatcher Common - Data Access lib</name> + <url>http://maven.apache.org</url> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <licenseDir>${project.parent.parent.parent.basedir}</licenseDir> + <apache.common.dbcp2.version>2.0.1</apache.common.dbcp2.version> + </properties> - <dependencies> - <dependency> + <dependencies> + <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> <scope>provided</scope> </dependency> - <dependency> - <groupId>org.onap.ccsdk.sli.core</groupId> - <artifactId>sli-common</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>org.onap.ccsdk.sli.core</groupId> - <artifactId>sli-provider</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>org.onap.appc</groupId> - <artifactId>appc-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.mariadb.jdbc</groupId> - <artifactId>mariadb-java-client</artifactId> - </dependency> - </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> - <Export-Package>org.onap.appc.dao.util</Export-Package> - <Import-Package>org.onap.appc.configuration,*;resolution:=optional</Import-Package> - <Embed-Dependency>mariadb-java-client</Embed-Dependency> - <Embed-Transitive>true</Embed-Transitive> - </instructions> - </configuration> - </plugin> - </plugins> - </build> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-common</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-provider</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>appc-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-dbcp2</artifactId> + <version>${apache.common.dbcp2.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.mariadb.jdbc</groupId> + <artifactId>mariadb-java-client</artifactId> + </dependency> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>appc-test-dependencies</artifactId> + <version>${project.version}</version> + <scope>test</scope> + <type>pom</type> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> + <Export-Package> + org.onap.appc.dao.util, + org.onap.appc.dao.util.api, + org.onap.appc.dao.util.exception, + org.onap.appc.dao.util.helper + </Export-Package> + <Import-Package>org.onap.appc.configuration,*;resolution:=optional</Import-Package> + <Embed-Dependency>mariadb-java-client,*;scope=compile|runtime</Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + </instructions> + </configuration> + </plugin> + </plugins> + </build> </project> diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/AppcDatabaseConnectionPool.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/AppcDatabaseConnectionPool.java new file mode 100644 index 000000000..219739755 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/AppcDatabaseConnectionPool.java @@ -0,0 +1,161 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.onap.appc.configuration.Configuration; +import org.onap.appc.configuration.ConfigurationFactory; +import org.onap.appc.dao.util.api.DBConnectionPoolService; +import org.onap.appc.dao.util.dbcp.DBConnectionPool; +import org.onap.appc.dao.util.exception.DBConnectionPoolException; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +/** + * This class implements + * + * @see org.onap.appc.dao.util.dbcp.DBConnectionPool + * that provides concrete implemenation of accessing appc database which basic setup + * data would be got from global configuration. + * @see org.onap.appc.configuration.Configuration + * <p> + * The singleton instance of this class has been instantiated by blueprint. + * An example is shown in the {@link DBConnectionPoolService} + */ +public class AppcDatabaseConnectionPool implements DBConnectionPoolService { + enum PropertyPattern { + DBURL("org.onap.appc.db.url.%s"), + USERNAME("org.onap.appc.db.user.%s"), + PASSWORD("org.onap.appc.db.pass.%s"), + DRIVER("org.onap.appc.db.jdbc.driver"); + + private String pattern; + + PropertyPattern(String pattern) { + this.pattern = pattern; + } + + public String getPattern() { + return pattern; + } + } + + private final EELFLogger logger = EELFManager.getInstance().getLogger(AppcDatabaseConnectionPool.class); + + private DBConnectionPool dbConnectionPool; + private String dbName; + + public AppcDatabaseConnectionPool() { + // do nothing + } + + public AppcDatabaseConnectionPool(String dbUrl, String userName, String password, String jdbcDriver) { + dbConnectionPool = new DBConnectionPool(dbUrl, userName, password, jdbcDriver); + } + + /** + * Injected by blueprint + * + * @param dbName + */ + public void setDbName(String dbName) { + this.dbName = dbName; + } + + /** + * Bean init method used by blueprint + */ + public void init() { + Configuration configuration = ConfigurationFactory.getConfiguration(); + String dbUrl = getConnectionProperty(configuration, PropertyPattern.DBURL); + String userName = getConnectionProperty(configuration, PropertyPattern.USERNAME); + String password = getConnectionProperty(configuration, PropertyPattern.PASSWORD); + String jdbcDriver = getJDBCDriver(configuration); + + dbConnectionPool = new DBConnectionPool(dbUrl, userName, password, jdbcDriver); + + // a simple health check + Connection connection = null; + try { + connection = dbConnectionPool.getConnection(); + } catch (DBConnectionPoolException e) { + logger.error("DB connection pool is created failed." + + "Please make sure the provided information is correct."); + } + + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + logger.error("DB connection cannot be closed:", e.getMessage()); + } + } + } + + /** + * Bean destroy method used by blueprint + */ + public void destroy() { + if (dbConnectionPool != null) { + dbConnectionPool.shutdown(); + } + } + + /** + * Get the connection from connection pool. + * + * @return Connection. If the provided db information is not correct, + * the return value might be null. + */ + @Override + public Connection getConnection() throws DBConnectionPoolException { + return dbConnectionPool.getConnection(); + } + + /** + * Get dbcp status like active_status. + * <p> + * More details about status of DBConnectionPool, + * go check {@link org.onap.appc.dao.util.dbcp.DBConnectionPool#getDataSourceStatus()} + * + * @return a map contains some dbcp information. + */ + @Override + public Map<String, Integer> getDataSourceStatus() { + return dbConnectionPool.getDataSourceStatus(); + } + + private String getConnectionProperty(Configuration configuration, PropertyPattern propertyPattern) { + String property = configuration.getProperty(String.format(propertyPattern.getPattern(), dbName), ""); + return property; + } + + private String getJDBCDriver(Configuration configuration) { + return configuration.getProperty(PropertyPattern.DRIVER.getPattern(), ""); + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/AppcJdbcConnectionFactory.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/AppcJdbcConnectionFactory.java index e62f03da3..c4af7ceee 100644 --- a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/AppcJdbcConnectionFactory.java +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/AppcJdbcConnectionFactory.java @@ -24,9 +24,20 @@ package org.onap.appc.dao.util; +import org.onap.appc.dao.util.api.JdbcConnectionFactory; +import org.onap.appc.dao.util.exception.JdbcRuntimeException; +import org.onap.appc.dao.util.message.Messages; + import java.sql.Connection; import java.sql.SQLException; +/** + * @deprecated As of release 1802, replaced by {@link #(AppcDatabaseConnectionPool)} + * <p> + * This class provides the ability to create dbconnection by using DBUtils which + * has been depreacted. + */ +@Deprecated public class AppcJdbcConnectionFactory implements JdbcConnectionFactory { private String schema; @@ -38,7 +49,7 @@ public class AppcJdbcConnectionFactory implements JdbcConnectionFactory { public Connection openDbConnection() { try { return DBUtils.getConnection(schema); - } catch(SQLException e) { + } catch (SQLException e) { throw new JdbcRuntimeException(Messages.EXP_APPC_JDBC_CONNECT.format(schema), e); } } @@ -46,7 +57,7 @@ public class AppcJdbcConnectionFactory implements JdbcConnectionFactory { public void closeDbConnection(Connection connection) { try { connection.close(); - } catch(SQLException e) { + } catch (SQLException e) { throw new JdbcRuntimeException(Messages.EXP_APPC_JDBC_DISCONNECT.format(schema), e); } } diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DBUtils.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DBUtils.java index 447dce8fc..95942a3b5 100644 --- a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DBUtils.java +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DBUtils.java @@ -24,46 +24,59 @@ package org.onap.appc.dao.util; -import java.sql.*; - import org.onap.appc.configuration.Configuration; import org.onap.appc.configuration.ConfigurationFactory; +import java.sql.*; +/** + * @deprecated As of release 1802, replaced by {@link #(org.onap.appc.dao.util.dbcp.DBConnectionPool)} + * <p> + * This class provides the ability to access mysql database which has been @Deprecated because + * {@link #getConnection(String)} for each database request is not a good practice especially + * on appc performance. + * <p> + * If you would like to use appcctl (mysql database), bundle:appc-data-access-lib has created + * a database connection pool bean and exported as a service by using blueprint. + * If you would like to create a new database connection pool, refer to the way mentioned above. + * {@link org.onap.appc.dao.util.api.DBConnectionPoolService} has an example of how to use + * the connection pool. + */ @Deprecated public class DBUtils { - private static final String JDBC_DRIVER = "org.mariadb.jdbc.Driver"; - private static final Configuration configuration = ConfigurationFactory.getConfiguration(); - static { - try { - String driver = JDBC_DRIVER; - Class.forName(driver); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } + private static final String JDBC_DRIVER = "org.mariadb.jdbc.Driver"; + private static final Configuration configuration = ConfigurationFactory.getConfiguration(); + + static { + try { + String driver = JDBC_DRIVER; + Class.forName(driver); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } - public static Connection getConnection(String schema) throws SQLException { - DriverManager.registerDriver(new org.mariadb.jdbc.Driver()); - String dbURL = configuration.getProperty(String.format("org.onap.appc.db.url.%s", schema), ""); - String userName = configuration.getProperty(String.format("org.onap.appc.db.user.%s", schema), ""); - String password = configuration.getProperty(String.format("org.onap.appc.db.pass.%s", schema), ""); - return DriverManager.getConnection(dbURL, userName, password); - } + public static Connection getConnection(String schema) throws SQLException { + DriverManager.registerDriver(new org.mariadb.jdbc.Driver()); + String dbURL = configuration.getProperty(String.format("org.onap.appc.db.url.%s", schema), ""); + String userName = configuration.getProperty(String.format("org.onap.appc.db.user.%s", schema), ""); + String password = configuration.getProperty(String.format("org.onap.appc.db.pass.%s", schema), ""); + return DriverManager.getConnection(dbURL, userName, password); + } - public static boolean clearResources(ResultSet resultSet, PreparedStatement ptmt, Connection connection) { - boolean clearFlag = false; - try { - if (resultSet != null) - resultSet.close(); - if (ptmt != null) - ptmt.close(); - if (connection != null) - connection.close(); - clearFlag = true; - } catch (SQLException e) { + public static boolean clearResources(ResultSet resultSet, PreparedStatement ptmt, Connection connection) { + boolean clearFlag = false; + try { + if (resultSet != null) + resultSet.close(); + if (ptmt != null) + ptmt.close(); + if (connection != null) + connection.close(); + clearFlag = true; + } catch (SQLException e) { - } - return clearFlag; + } + return clearFlag; - } + } } diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DefaultJdbcConnectionFactory.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DefaultJdbcConnectionFactory.java index 88599ac72..f877bd220 100644 --- a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DefaultJdbcConnectionFactory.java +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/DefaultJdbcConnectionFactory.java @@ -24,10 +24,28 @@ package org.onap.appc.dao.util; +import org.onap.appc.dao.util.api.JdbcConnectionFactory; +import org.onap.appc.dao.util.exception.JdbcRuntimeException; +import org.onap.appc.dao.util.message.Messages; + import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +/** + * @deprecated As of release 1802, replaced by {@link #(org.onap.appc.dao.util.dbcp.DBConnectionPool)} + * <p> + * This class provides the ability to access mysql database which has been deprecated because + * {@link #openDbConnection()} for each database request is not a good practice especially + * on appc performance. + * <p> + * If you would like to use appcctl (mysql database), bundle:appc-data-access-lib has created + * a database connection pool bean and exported as a service by using blueprint. + * If you would like to create a new database connection pool, refer to the way mentioned above. + * {@link org.onap.appc.dao.util.api.DBConnectionPoolService} has an example of how to use + * the connection pool. + */ +@Deprecated public abstract class DefaultJdbcConnectionFactory implements JdbcConnectionFactory { private static boolean driverRegistered = false; @@ -54,12 +72,12 @@ public abstract class DefaultJdbcConnectionFactory implements JdbcConnectionFact @Override public Connection openDbConnection() { try { - if(!driverRegistered) { + if (!driverRegistered) { registedDriver(); driverRegistered = true; } return DriverManager.getConnection(jdbcURL, jdbcUserName, jdbcPassword); - } catch(SQLException e) { + } catch (SQLException e) { throw new JdbcRuntimeException(Messages.EXP_JDBC_CONNECT.format(jdbcURL), e); } } @@ -68,7 +86,7 @@ public abstract class DefaultJdbcConnectionFactory implements JdbcConnectionFact public void closeDbConnection(Connection connection) { try { connection.close(); - } catch(SQLException e) { + } catch (SQLException e) { throw new JdbcRuntimeException(Messages.EXP_JDBC_DISCONNECT.format(jdbcURL), e); } } diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/api/DBConnectionPoolService.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/api/DBConnectionPoolService.java new file mode 100644 index 000000000..2f51666dc --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/api/DBConnectionPoolService.java @@ -0,0 +1,100 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.api; + +import org.onap.appc.dao.util.exception.DBConnectionPoolException; +import org.onap.appc.dao.util.exception.DataAccessException; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Map; + +/** + * This class is the interface of DBConnectionPool. + * <p> + * Below is an example of how to query an entry from database. + * Inject AppcDatabaseConnectionPool bean by the blueprint first + * for example, + * {@code + * <reference id="AppcMysqlDBConnectionPoolService" availability="mandatory" + * activation="eager" interface="org.onap.appc.dao.util.api.DBConnectionPoolService" /> + * } + * <p> + * Then, query the data and close ResultSet, Statement, Connection. + * <blockquote><pre> + * {@code + * private AppcDatabaseConnectionPool pool; + * public void setAppcDatabaseConnectionPool(AppcDatabaseConnectionPool pool){ + * this.pool = pool; + * } + * public queryAppcDatabase(AppcDatabaseConnectionPool pool){ + * Connection connection = null; + * try { + * connection = pool.getConnection(); + * } catch (DBConnectionPoolException e) { + * e.printStackTrace(); + * } + * Connection conn = null; + * Statement stmt = null; + * ResultSet rs = null; + * try { + * stmt = connection.createStatement(); + * rs = stmt.executeQuery("select * from appcctl.transactions"); + * System.out.println("# of entries in db:"); + * int numcols = rs.getMetaData().getColumnCount(); + * System.out.println(pool.getDataSourceStatus()); + * }catch (SQLException e) { + * e.printStackTrace(); + * } finally { + * try { + * pool.close(rs, stmt, conn); + * } catch (DataAccessException e) { + * e.printStackTrace(); + * } + * } + * } + * } + * <p> + * </pre></blockquote> + */ +public interface DBConnectionPoolService { + /** + * Get a jdbc connection + * + * @return connection {@link Connection} + * @throws DBConnectionPoolException - if a {@link Connection} cannot be return. + */ + Connection getConnection() throws DBConnectionPoolException; + + /** + * Get Data source status + * + * @return map + */ + Map<String, Integer> getDataSourceStatus(); + +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/api/JdbcConnectionFactory.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/api/JdbcConnectionFactory.java new file mode 100644 index 000000000..5c7342508 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/api/JdbcConnectionFactory.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.api; + +import java.sql.Connection; + +/** + * @deprecated As of release 1802, replaced by {@link #(org.onap.appc.dao.util.api.DBConnectionPoolService)} + * <p> + * This interface has been deprecated due to a connection pool has + * been introduced into this bundle. + * refer to {@link DBConnectionPoolService} + */ +@Deprecated +public interface JdbcConnectionFactory { + /** + * Open a jdbc connection + * + * @return {@link Connection} + */ + Connection openDbConnection(); + + /** + * Close a jdbc connection + * + * @param {@link Connection} + */ + void closeDbConnection(Connection connection); +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/dbcp/DBConnectionPool.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/dbcp/DBConnectionPool.java new file mode 100644 index 000000000..7f4b59baa --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/dbcp/DBConnectionPool.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.dbcp; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.apache.commons.dbcp2.BasicDataSource; +import org.onap.appc.dao.util.api.DBConnectionPoolService; +import org.onap.appc.dao.util.exception.DBConnectionPoolException; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +/** + * This class provides ability to create database connection pool. + */ +public class DBConnectionPool implements DBConnectionPoolService { + + private final EELFLogger logger = EELFManager.getInstance().getLogger(DBConnectionPool.class); + private BasicDataSource dataSource; + + public enum DataSourceStatus { + ACTIVE_NUMBER("active_number"), + IDLE_NUMBER("idle_number"); + + private String attribute; + + DataSourceStatus(String attribute) { + this.attribute = attribute; + } + + public String getAttribute() { + return attribute; + } + } + + public DBConnectionPool(String connectURI, String username, String password, String driverClass) { + this(connectURI, username, password, driverClass, null, null, null, null, null); + } + + public DBConnectionPool(String connectURI, String username, String password, + String driverClass, Integer initialSize, Integer maxActive, + Integer maxIdle, Integer maxWait, Integer minIdle) { + this.dataSource = getBasicDataSource(connectURI, username, password, driverClass, + initialSize, maxActive, maxIdle, maxWait, minIdle); + } + + /** + * Get a connection from datasource which is thread safe. + * {@inheritDoc} + */ + @Override + public Connection getConnection() throws DBConnectionPoolException { + if (dataSource == null) { + throw new DBConnectionPoolException(); + } + + Connection connection = null; + try { + connection = dataSource.getConnection(); + } catch (SQLException e) { + logger.error("Get connection failure", e); + throw new DBConnectionPoolException(e); + } + + if(connection == null){ + // + throw new DBConnectionPoolException("Connection was not created"); + } + + return connection; + } + + /** + * Closes and releases all idle connections that are currently stored in the connection pool associated with this + * data source. + */ + public void shutdown() { + if (dataSource != null) { + try { + dataSource.close(); + } catch (SQLException e) { + logger.error("Datasource cannot be closed normally.", e.getMessage()); + } + } + + dataSource = null; + } + + /** + * Get datasource status + * + * @return + */ + public Map<String, Integer> getDataSourceStatus() { + Map<String, Integer> map = new HashMap<>(2); + map.put(DataSourceStatus.ACTIVE_NUMBER.getAttribute(), dataSource.getNumActive()); + map.put(DataSourceStatus.IDLE_NUMBER.getAttribute(), dataSource.getNumIdle()); + + return map; + } + + private BasicDataSource getBasicDataSource(String connectURI, String username, String password, + String driverClass, Integer initialSize, Integer maxtotal, + Integer maxIdle, Integer maxWaitMillis, Integer minIdle) { + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName(driverClass); + dataSource.setUsername(username); + dataSource.setPassword(password); + dataSource.setUrl(connectURI); + + if (initialSize != null) { + dataSource.setInitialSize(initialSize); + } + if (maxtotal != null) { + dataSource.setMaxTotal(maxtotal); + } + if (maxIdle != null) { + dataSource.setMaxIdle(maxIdle); + } + if (maxWaitMillis != null) { + dataSource.setMaxWaitMillis(maxWaitMillis); + } + if (minIdle != null) { + dataSource.setMinIdle(minIdle); + } + + return dataSource; + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/exception/DBConnectionPoolException.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/exception/DBConnectionPoolException.java new file mode 100644 index 000000000..fff269b36 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/exception/DBConnectionPoolException.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.exception; + +import java.sql.SQLException; + +/** + * This class is exception class for DBConnectionPool{@link org.onap.appc.dao.util.dbcp.DBConnectionPool} + */ +public class DBConnectionPoolException extends SQLException { + public DBConnectionPoolException() { + super(); + } + + public DBConnectionPoolException(String message) { + super(message); + } + + public DBConnectionPoolException(String message, Throwable cause) { + super(message, cause); + } + + public DBConnectionPoolException(Throwable cause) { + super(cause); + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/ExecutionQueueServiceFactory.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/exception/DataAccessException.java index f071be6f0..1fae9c979 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/ExecutionQueueServiceFactory.java +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/exception/DataAccessException.java @@ -22,17 +22,27 @@ * ============LICENSE_END========================================================= */ -package org.onap.appc.executionqueue.impl; +package org.onap.appc.dao.util.exception; -import org.onap.appc.executionqueue.ExecutionQueueService; +import java.sql.SQLException; -public class ExecutionQueueServiceFactory { +/** + * This class is exception class for DataAccessException + */ +public class DataAccessException extends SQLException { + public DataAccessException() { + super(); + } + + public DataAccessException(String message) { + super(message); + } - private static class ExecutionQueueServiceHolder { - public static final ExecutionQueueService executionQueueService = new ExecutionQueueServiceImpl(); + public DataAccessException(String message, Throwable cause) { + super(message, cause); } - public static ExecutionQueueService getExecutionQueueService() { - return ExecutionQueueServiceHolder.executionQueueService; + public DataAccessException(Throwable cause) { + super(cause); } } diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/JdbcRuntimeException.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/exception/JdbcRuntimeException.java index 8e606fe94..3ac4f654e 100644 --- a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/JdbcRuntimeException.java +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/exception/JdbcRuntimeException.java @@ -22,7 +22,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.appc.dao.util; +package org.onap.appc.dao.util.exception; public class JdbcRuntimeException extends RuntimeException { diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/helper/DBHelper.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/helper/DBHelper.java new file mode 100644 index 000000000..20e119a12 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/helper/DBHelper.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.helper; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * This class provides the basic utility methods of database connection + * <p> + * Since currently this class only contains stateless methods, the package + * is exported by maven-bundle-plugin. If you have to add some stateful methods + * in this class, one suggested solution is that use blueprint to create a singleton + * which is exported as service + */ +public class DBHelper { + /** + * Closes a database resultSet,statement and connection in that order. Data access objects should call this method + * in a finally block. + * + * @param resultSet or null + * @param statement or null + * @param connection or null + */ + public static void close(ResultSet resultSet, Statement statement, Connection connection) { + try { + closeResultSet(resultSet); + } finally { + try { + closeStatement(statement); + } finally { + closeConnection(connection); + } + } + } + + /** + * Closes a database result set. Data access objects should call this method + * when a result set is no longer needed. + * + * @param rs A ResultSet Object + */ + public static void closeResultSet(ResultSet rs) { + try { + if (rs != null) { + rs.close(); + } + } catch (SQLException se) { + // Ignore this exception and allow execution to continue. + // so that connection can try to be close. + } + } + + /** + * Closes a database query statement. Data access objects should call this + * method when a statement is no longer needed. + * + * @param stmt A Statement Object + */ + public static void closeStatement(Statement stmt) { + try { + if (stmt != null) { + stmt.close(); + } + } catch (SQLException se) { + // Ignore this exception and allow execution to continue. + // so that connection can try to be close. + } + } + + /** + * Closes a database connection. Data access objects should call this method + * when a database connection is no longer needed. + * + * @param connection A Connection Object * + */ + public static void closeConnection(Connection connection) { + try { + if (connection != null && !connection.isClosed()) { + connection.close(); + } + } catch (SQLException se) { + // Ignore this exception and allow execution to continue. + } + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/Messages.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/message/Messages.java index 6330793b7..33696938f 100644 --- a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/Messages.java +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/message/Messages.java @@ -22,7 +22,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.appc.dao.util; +package org.onap.appc.dao.util.message; public enum Messages { EXP_JDBC_CONNECT("Error connecting to JDBC URL [%s]."), diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 000000000..6dc95ec5a --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> + + +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> + + <bean id="AppcMysqlDBConnectionPoolBean" class="org.onap.appc.dao.util.AppcDatabaseConnectionPool" + scope="singleton" init-method="init" destroy-method="destroy"> + <property name="dbName" value="sdnctl"/> + </bean> + + <service id="AppcMysqlDBConnectionPoolService" interface="org.onap.appc.dao.util.api.DBConnectionPoolService" + ref="AppcMysqlDBConnectionPoolBean"/> +</blueprint> diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/AppcDatabaseConnectionPoolTest.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/AppcDatabaseConnectionPoolTest.java new file mode 100644 index 000000000..faee99d84 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/AppcDatabaseConnectionPoolTest.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.onap.appc.configuration.Configuration; +import org.onap.appc.configuration.ConfigurationFactory; +import org.onap.appc.dao.util.dbcp.DBConnectionPool; +import org.onap.appc.dao.util.exception.DBConnectionPoolException; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; +import static org.powermock.api.support.membermodification.MemberMatcher.method; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ConfigurationFactory.class}) +@PowerMockIgnore("javax.management.*") +public class AppcDatabaseConnectionPoolTest { + private String dbName = "dbName"; + private String dbUrl = "jdbc:h2:mem:~/test;MODE=MYSQL;DB_CLOSE_DELAY=-1"; + private String username = "sa"; + private String password = "sa"; + private String driver = "org.h2.Driver"; + + private Configuration configuration; + + private DBConnectionPool dbConnectionPool; + private AppcDatabaseConnectionPool appcDatabaseConnectionPool; + + @Before + public void setUp() throws Exception { + mockStatic(ConfigurationFactory.class); + when(ConfigurationFactory.getConfiguration()).thenReturn(configuration); + appcDatabaseConnectionPool = spy(new AppcDatabaseConnectionPool(dbUrl, username, password, driver)); + dbConnectionPool = mock(DBConnectionPool.class); + Whitebox.setInternalState(appcDatabaseConnectionPool, "dbConnectionPool", dbConnectionPool); + } + + @Test + public void testArgumentConstructor() { + AppcDatabaseConnectionPool appcDatabaseConnectionPool = new AppcDatabaseConnectionPool(dbUrl, username, + password, driver); + Object dbConnectionPool = Whitebox.getInternalState(appcDatabaseConnectionPool, "dbConnectionPool"); + Assert.assertNotNull(dbConnectionPool); + } + + @Test + public void testGetConnection() throws SQLException { + final Connection connection = appcDatabaseConnectionPool.getConnection(); + Mockito.verify(dbConnectionPool, times(1)).getConnection(); + } + + @Test + public void testDestroy() throws SQLException { + appcDatabaseConnectionPool.destroy(); + Mockito.verify(dbConnectionPool, times(1)).shutdown(); + } + + @Test + public void testGetDataSourceStatus() { + Map<String, Integer> dataSourceStatus = appcDatabaseConnectionPool.getDataSourceStatus(); + Mockito.verify(dbConnectionPool, times(1)).getDataSourceStatus(); + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/dbcp/DBConnectionPoolTest.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/dbcp/DBConnectionPoolTest.java new file mode 100644 index 000000000..242d11737 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/dbcp/DBConnectionPoolTest.java @@ -0,0 +1,99 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.dbcp; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.appc.dao.util.exception.DBConnectionPoolException; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({DBConnectionPool.class}) +@PowerMockIgnore("javax.management.*") +public class DBConnectionPoolTest { + private final String connectURI = "jdbc:h2:mem:~/test;MODE=MYSQL;DB_CLOSE_DELAY=-1"; + private final String username = "sa"; + private final String password = "sa"; + private final String driverClass = "org.h2.Driver"; + + private DBConnectionPool dbcp; + private DBConnectionPool dbcp2; + private Connection connection; + + @Before + public void setUp() throws Exception { + dbcp = new DBConnectionPool(connectURI, username, password, driverClass); + dbcp2 = new DBConnectionPool(connectURI, username, password, driverClass); + } + + @Test + public void testGetConnection() { + try { + connection = dbcp.getConnection(); + } catch (DBConnectionPoolException e) { + Assert.fail(e.getMessage()); + } + Assert.assertNotNull(connection); + } + + @Test + public void testGetDataSourceStatus() { + Map<String, Integer> dataSourceStatus = dbcp.getDataSourceStatus(); + Assert.assertNotNull(dataSourceStatus); + } + + @Test(expected = DBConnectionPoolException.class) + public void testShutdown() throws DBConnectionPoolException { + dbcp2.shutdown(); + connection = dbcp2.getConnection(); + Assert.assertNull(connection); + } + + @After + public void clean() { + if (dbcp != null) { + dbcp.shutdown(); + } + if (dbcp2 != null) { + dbcp2.shutdown(); + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/exception/DBConnectionPoolExceptionTest.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/exception/DBConnectionPoolExceptionTest.java new file mode 100644 index 000000000..24f60b8d2 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/exception/DBConnectionPoolExceptionTest.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.exception; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.appc.dao.util.dbcp.DBConnectionPool; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({DBConnectionPoolException.class}) +public class DBConnectionPoolExceptionTest { + @Before + public void setUp() throws Exception { + } + + @Test(expected = DBConnectionPoolException.class) + public void testNonArgumentConstructor() throws DBConnectionPoolException { + throw new DBConnectionPoolException(); + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/exception/DataAccessExceptionTest.java b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/exception/DataAccessExceptionTest.java new file mode 100644 index 000000000..7e9d97510 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/test/java/org/onap/appc/dao/util/exception/DataAccessExceptionTest.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.dao.util.exception; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.junit.Assert.*; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({DataAccessExceptionTest.class}) +public class DataAccessExceptionTest { + @Before + public void setUp() throws Exception { + } + + @Test(expected = DataAccessException.class) + public void testNonArgumentConstructor() throws DataAccessException { + throw new DataAccessException(); + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/pom.xml b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/pom.xml index 204e9f2e4..637b8566b 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/pom.xml @@ -1,19 +1,44 @@ -<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> +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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.onap.appc</groupId> <artifactId>appc-dispatcher-common</artifactId> <version>1.3.0-SNAPSHOT</version> </parent> - <artifactId>domain-model-lib</artifactId> - <packaging>bundle</packaging> - - <name>domain-model-lib</name> - <url>http://maven.apache.org</url> + <artifactId>domain-model-lib</artifactId> + <packaging>bundle</packaging> + <name>APPC Dispatcher Common - Domain Model Lib</name> + <url>http://maven.apache.org</url> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> <build> <plugins> diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ActionLevel.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ActionLevel.java index 230812cef..8544ee427 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ActionLevel.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ActionLevel.java @@ -25,5 +25,9 @@ package org.onap.appc.domainmodel.lcm; public enum ActionLevel { - VNF,VM,VNFC + VNF, // Requests related to VNFs + VM, // Requests related to VMs + VNFC, // Requests related to VNFCs + MGMT // Requests that are applicable to prior requests (and are not applicable to VNF, VM, VNFC + } diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/CommonHeader.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/CommonHeader.java index 7c44efecb..8c7d73c11 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/CommonHeader.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/CommonHeader.java @@ -24,13 +24,13 @@ package org.onap.appc.domainmodel.lcm; -import java.time.Instant; +import java.util.Date; public class CommonHeader { private Flags flags; - private Instant timestamp; + private Date timestamp; private String apiVer; private String originatorId; private String requestId; @@ -44,11 +44,11 @@ public class CommonHeader { this.flags = flags; } - public Instant getTimeStamp() { + public Date getTimeStamp() { return timestamp; } - public void setTimestamp(Instant timestamp) { + public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } diff --git a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/JdbcConnectionFactory.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ExternalActionStatus.java index 1a47db3f7..aeaf3d94c 100644 --- a/appc-dispatcher/appc-dispatcher-common/appc-data-access-lib/src/main/java/org/onap/appc/dao/util/JdbcConnectionFactory.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ExternalActionStatus.java @@ -22,12 +22,15 @@ * ============LICENSE_END========================================================= */ -package org.onap.appc.dao.util; +package org.onap.appc.domainmodel.lcm; -import java.sql.Connection; - -public interface JdbcConnectionFactory { - - Connection openDbConnection(); - void closeDbConnection(Connection connection); +/** + * This class is a Enum class which provides value of external action status + */ +public enum ExternalActionStatus { + FAILED, + IN_PROGRESS, + SUCCESSFUL, + ABORTED, + NOT_FOUND } diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Flags.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Flags.java index 4102955f0..ef151b1a6 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Flags.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Flags.java @@ -27,29 +27,38 @@ package org.onap.appc.domainmodel.lcm; public class Flags { - private final boolean force; - private final int ttl; - private final Mode mode; - - public Flags(Mode mode, boolean force, int ttl) { - super(); - this.force = force; - this.ttl = ttl; - this.mode = mode; - } + private boolean force; + private int ttl; + private Mode mode; public boolean isForce() { return force; } + public void setForce(boolean force) { + this.force = force; + } + public int getTtl() { return ttl; } + public void setTtl(int ttl) { + this.ttl = ttl; + } + public Mode getMode() { return mode; } + public void setMode(Mode mode) { + this.mode = mode; + } + + public void setMode(String mode) { + this.mode = Mode.valueOf(mode); + } + @Override public String toString() { return "Flags{" + diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/OperationType.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/OperationType.java deleted file mode 100644 index b5b017e40..000000000 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/OperationType.java +++ /dev/null @@ -1,29 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP : APPC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Copyright (C) 2017 Amdocs - * ============================================================================= - * 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. - * - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - * ============LICENSE_END========================================================= - */ - -package org.onap.appc.domainmodel.lcm; - -public enum OperationType { - ReadOnly,BuiltIn,OrchestrationStatusUpdate,OperationStatusUpdate -} diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/test/java/org/onap/appc/executionqueue/Listener.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RequestModes.java index ce26fd92a..36b761f58 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/test/java/org/onap/appc/executionqueue/Listener.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RequestModes.java @@ -22,21 +22,18 @@ * ============LICENSE_END========================================================= */ -package org.onap.appc.executionqueue; +package org.onap.appc.domainmodel.lcm; -import org.onap.appc.executionqueue.MessageExpirationListener; +public enum RequestModes { + NORMAL("Normal"), + EXCLUSIVE("Exclusive"); - -public class Listener implements MessageExpirationListener { - - boolean listenerExecuted = false; - - public boolean isListenerExecuted() { - return listenerExecuted; + private String mode; + RequestModes(String mode){ + this.mode=mode; } - @Override - public void onMessageExpiration(Object message) { - listenerExecuted = true; + public String getMode(){ + return mode; } } diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RequestStatus.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RequestStatus.java new file mode 100644 index 000000000..0490e2cf5 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RequestStatus.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.domainmodel.lcm; + +/** + * This is a Enumeration class which introduces various Request Status + */ +public enum RequestStatus { + // Unknown request status + UNKNOWN(ExternalActionStatus.FAILED, "Status cannot be determined.",true), + // Request just entered in APPC boundaries + RECEIVED(ExternalActionStatus.IN_PROGRESS, "Request has been received.",false), + // APPC has accepted the request/transaction to process after applying various business rules/validation + ACCEPTED(ExternalActionStatus.IN_PROGRESS, "Request has been accepted and is in progress.",false), + // APPC decided to reject the request based on various applicable business rules/validation. + REJECTED(ExternalActionStatus.FAILED, "Request has been rejected.",true), + // APPC has processed the VNF management request without any errors + SUCCESSFUL(ExternalActionStatus.SUCCESSFUL, "Request has been successfully completed.",true), + // APPC encountered error during processing the VNF management request + FAILED(ExternalActionStatus.FAILED, "Request failed because of an error",true), + // APPC Timed out because of reason that is out of control of APPC. + TIMEOUT(ExternalActionStatus.FAILED, "Request failed because it timed out",true), + // APPC aborted the request + ABORTED(ExternalActionStatus.ABORTED, "Request was aborted",true), + // APPC cannot find any related request + NOT_FOUND(ExternalActionStatus.NOT_FOUND, "Request was not found",true); + + private ExternalActionStatus externalActionStatus; + private String description; + boolean terminal; + + RequestStatus(ExternalActionStatus externalActionStatus, String description, boolean terminal) { + this.externalActionStatus = externalActionStatus; + this.description = description; + this.terminal=terminal; + } + + public ExternalActionStatus getExternalActionStatus() { + return externalActionStatus; + } + + public String getExternalActionStatusName() { + return externalActionStatus.name(); + } + + public String getDescription() { + return description; + } + public boolean isTerminal() { + return terminal; + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ResponseContext.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ResponseContext.java index da3a6be69..4386f0d08 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ResponseContext.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/ResponseContext.java @@ -31,8 +31,11 @@ import java.util.Map; public class ResponseContext { private CommonHeader commonHeader; private Status status; - private String payload; private Map<String, String> additionalContext; + /** Carries json String response payload */ + private String payload; + /** Carries non-String response payload, such as List or Map of object */ + private Object payloadObject; public CommonHeader getCommonHeader() { return commonHeader; @@ -58,6 +61,14 @@ public class ResponseContext { this.payload = payload; } + public Object getPayloadObject() { + return payloadObject; + } + + public void setPayloadObject(Object payloadObject) { + this.payloadObject = payloadObject; + } + public Map<String, String> getAdditionalContext() { return additionalContext; } diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RuntimeContext.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RuntimeContext.java index 4458e2619..b4ffe3482 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RuntimeContext.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/RuntimeContext.java @@ -32,10 +32,10 @@ public class RuntimeContext { private RequestContext requestContext; private ResponseContext responseContext; private VNFContext vnfContext; + private TransactionRecord transactionRecord; //TODO move fields timeStart abd isLockAcquired to a better place private Instant timeStart; - private boolean isLockAcquired; private String rpcName; public String getRpcName() { @@ -46,22 +46,6 @@ public class RuntimeContext { this.rpcName = rpcName; } - public Instant getTimeStart() { - return timeStart; - } - - public boolean isLockAcquired() { - return isLockAcquired; - } - - public void setIsLockAcquired(boolean isLockAcquired) { - this.isLockAcquired = isLockAcquired; - } - - public void setTimeStart(Instant timeStart) { - this.timeStart = timeStart; - } - public RequestContext getRequestContext() { return requestContext; } @@ -78,6 +62,14 @@ public class RuntimeContext { this.responseContext = responseContext; } + public Instant getTimeStart() { + return timeStart; + } + + public void setTimeStart(Instant timeStart) { + this.timeStart = timeStart; + } + public VNFContext getVnfContext() { return vnfContext; } @@ -86,6 +78,16 @@ public class RuntimeContext { this.vnfContext = vnfContext; } + + public TransactionRecord getTransactionRecord() { + return transactionRecord; + } + + public void setTransactionRecord(TransactionRecord transactionRecord) { + this.transactionRecord = transactionRecord; + } + + @Override public String toString() { return "RuntimeContext{" + @@ -93,7 +95,6 @@ public class RuntimeContext { ", responseContext=" + responseContext + ", vnfContext=" + vnfContext + ", timeStart=" + timeStart + - ", isLockAcquired=" + isLockAcquired + ", rpcName='" + rpcName + '\'' + '}'; } diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Status.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Status.java index 2f8fd1950..2c9725fed 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Status.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/Status.java @@ -27,22 +27,25 @@ package org.onap.appc.domainmodel.lcm; public class Status { - private final int code; - private final String message; - - public Status(int code, String message) { - this.code = code; - this.message = message; - } + private int code; + private String message; public int getCode() { return code; } + public void setCode(int code) { + this.code = code; + } + public String getMessage() { return message; } + public void setMessage(String value) { + this.message = value; + } + @Override public String toString() { return "Status{" + diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/TransactionRecord.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/TransactionRecord.java new file mode 100644 index 000000000..16b32db0a --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/TransactionRecord.java @@ -0,0 +1,217 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.domainmodel.lcm; + +import java.time.Instant; + + +public class TransactionRecord { + + private String transactionId; + private Instant originTimestamp; + private String requestId; + private String subRequestId; + private String originatorId; + private Instant startTime; + private Instant endTime; + private String targetId; + private String targetType; + private VNFOperation operation; + private int resultCode; + private String description; + private RequestStatus requestState; + private String serviceInstanceId; + private String vnfcName; + private String vserverId; + private String vfModuleId; + private Flags.Mode mode; + + public Instant getOriginTimestamp() { + return originTimestamp; + } + + public void setOriginTimestamp(Instant originTimestamp) { + this.originTimestamp = originTimestamp; + } + + public Instant getStartTime() { + return startTime; + } + + public void setStartTime(Instant startTime) { + this.startTime = startTime; + } + + public Instant getEndTime() { + return endTime; + } + + public void setEndTime(Instant endTime) { + this.endTime = endTime; + } + + public String getMode() { + return mode.name(); + } + + public void setMode(Flags.Mode mode) { + this.mode=mode; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getServiceInstanceId() { + return serviceInstanceId; + } + + public void setServiceInstanceId(String serviceInstanceId) { + this.serviceInstanceId = serviceInstanceId; + } + + public String getVnfcName() { + return vnfcName; + } + + public void setVnfcName(String vnfcName) { + this.vnfcName = vnfcName; + } + + public String getVserverId() { + return vserverId; + } + + public void setVserverId(String vserverId) { + this.vserverId = vserverId; + } + + public String getVfModuleId() { + return vfModuleId; + } + + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + + public String getTargetType() { + return targetType; + } + + public void setTargetType(String targetType) { + this.targetType = targetType; + } + + public VNFOperation getOperation() { + return operation; + } + + public void setOperation(VNFOperation operation) { + this.operation = operation; + } + + public int getResultCode() { + return resultCode; + } + + public void setResultCode(int resultCode) { + this.resultCode = resultCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getRequestState() { + return requestState.name(); + } + + public void setRequestState(RequestStatus requestState) { + this.requestState = requestState; + } + + public String getOriginatorId() { + return originatorId; + } + + public void setOriginatorId(String originatorId) { + this.originatorId = originatorId; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getSubRequestId() { + return subRequestId; + } + + public void setSubRequestId(String subRequestId) { + this.subRequestId = subRequestId; + } + + public String getTargetId() { + return targetId; + } + + public void setTargetId(String targetId) { + this.targetId = targetId; + } + + @Override + public String toString() { + return "TransactionRecord{" + + "transactionId='" + transactionId + '\'' + + ", originTimestamp=" + originTimestamp + + ", requestId='" + requestId + '\'' + + ", subRequestId='" + subRequestId + '\'' + + ", originatorId='" + originatorId + '\'' + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", targetId='" + targetId + '\'' + + ", targetType='" + targetType + '\'' + + ", operation='" + operation + '\'' + + ", resultCode='" + resultCode + '\'' + + ", description='" + description + '\'' + + ", requestState='" + requestState + '\'' + + ", serviceInstanceId='" + serviceInstanceId + '\'' + + ", vnfcName='" + vnfcName + '\'' + + ", vserverId='" + vserverId + '\'' + + ", vfModuleId='" + vfModuleId + '\'' + + '}'; + } +} diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java index 228005d34..77ebe43b6 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java @@ -25,36 +25,68 @@ package org.onap.appc.domainmodel.lcm; public enum VNFOperation { - Configure, Test, HealthCheck, Start, Terminate, Restart, Rebuild, Stop, ConfigModify, - ConfigScaleOut,ConfigRestore,Backup, Snapshot, - SoftwareUpload, LiveUpgrade, Rollback, Test_lic, Migrate, Evacuate,StopApplication, StartApplication, - Sync(OperationType.ReadOnly), Audit(OperationType.ReadOnly), - ConfigBackup(OperationType.ReadOnly),ConfigBackupDelete(OperationType.ReadOnly),ConfigExport(OperationType.ReadOnly), - Lock(OperationType.BuiltIn), Unlock(OperationType.BuiltIn), CheckLock(OperationType.BuiltIn); + ActionStatus, + AttachVolume, + Audit, + Backup, + CheckLock(true), + Configure, + ConfigBackup, + ConfigBackupDelete, + ConfigExport, + ConfigModify, + ConfigRestore, + ConfigScaleOut, + DetachVolume, + Evacuate, + HealthCheck, + LiveUpgrade, + Lock(true), + Migrate, + Query, + QuiesceTraffic, + ResumeTraffic, + Reboot, + Rebuild, + Restart, + Rollback, + Snapshot, + SoftwareUpload, + Start, + StartApplication, + Stop, + StopApplication, + Sync, + Terminate, + Test, + Test_lic, + Unlock(true), + UpgradePreCheck, + UpgradeSoftware, + UpgradePostCheck, + UpgradeBackup, + UpgradeBackout; - private OperationType operationType; - - VNFOperation(OperationType operationType){ - this.operationType=operationType; - } + private boolean builtIn; VNFOperation() { - this.operationType=OperationType.OrchestrationStatusUpdate; + this.builtIn=false; } + /** * Operations handled directly by the RequestHandler without further call to DG are built-in operations. */ public boolean isBuiltIn() { - return this.operationType.equals(OperationType.BuiltIn); + return builtIn; } - public OperationType getOperationType() { - return operationType; + VNFOperation(boolean builtIn) { + this.builtIn = builtIn; } public static VNFOperation findByString(String operationName) { - for(VNFOperation operation: VNFOperation.values()) { - if(operation.name().equals(operationName)) { + for (VNFOperation operation : VNFOperation.values()) { + if (operation.name().equals(operationName)) { return operation; } } diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/pom.xml b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/pom.xml index cc89f3c3f..75d4fb09a 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/pom.xml @@ -1,33 +1,59 @@ -<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> +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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.onap.appc</groupId> <artifactId>appc-dispatcher-common</artifactId> <version>1.3.0-SNAPSHOT</version> </parent> - <artifactId>execution-queue-management-lib</artifactId> - <packaging>bundle</packaging> - <name>execution-queue-management-lib</name> - <url>http://maven.apache.org</url> + <artifactId>execution-queue-management-lib</artifactId> + <packaging>bundle</packaging> + <name>APPC Dispatcher Common - Qxecution Queue Mgmt lib</name> + <url>http://maven.apache.org</url> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> - <dependencies> - <dependency> - <groupId>org.onap.appc</groupId> - <artifactId>appc-common</artifactId> - <version>${project.version}</version> - </dependency> + <dependencies> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>appc-common</artifactId> + <version>${project.version}</version> + </dependency> <dependency> - <groupId>com.att.eelf</groupId> - <artifactId>eelf-core</artifactId> - </dependency> - </dependencies> + <groupId>com.att.eelf</groupId> + <artifactId>eelf-core</artifactId> + </dependency> + </dependencies> - <build> + <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> @@ -37,7 +63,9 @@ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-Version>${project.version}</Bundle-Version> <Embed-Transitive>true</Embed-Transitive> - <Export-Package>org.onap.appc.executionqueue,org.onap.appc.executionqueue.impl</Export-Package> + <Export-Package> + org.onap.appc.executionqueue,org.onap.appc.executionqueue.impl + </Export-Package> <Import-Package> *;resolution:=optional </Import-Package> diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/ExecutionQueueService.java b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/ExecutionQueueService.java index 1423962ef..2c4aa0853 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/ExecutionQueueService.java +++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/ExecutionQueueService.java @@ -31,5 +31,4 @@ import org.onap.appc.exceptions.APPCException; public interface ExecutionQueueService<M extends Runnable> { void putMessage(M message) throws APPCException; void putMessage(M message, long timeout, TimeUnit unit) throws APPCException; - void registerMessageExpirationListener(MessageExpirationListener listener); } diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/helper/Util.java b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/helper/Util.java index 164a8b563..09d49deef 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/helper/Util.java +++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/helper/Util.java @@ -24,8 +24,6 @@ package org.onap.appc.executionqueue.helper; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; import org.onap.appc.configuration.Configuration; import org.onap.appc.configuration.ConfigurationFactory; @@ -35,11 +33,10 @@ import java.util.concurrent.atomic.AtomicInteger; public class Util { - private final EELFLogger logger = EELFManager.getInstance().getLogger(Util.class); - private final int default_queue_size = 10; - private final int default_threadpool_size = 10; - private final String queue_size_key = "appc.dispatcher.executionqueue.backlog.size"; - private final String threadpool_size_key = "appc.dispatcher.executionqueue.threadpool.size"; + private int default_queue_size = 10; + private int default_threadpool_size = 10; + private String queue_size_key = "appc.dispatcher.executionqueue.backlog.size"; + private String threadpool_size_key = "appc.dispatcher.executionqueue.threadpool.size"; private Configuration configuration; @@ -48,7 +45,6 @@ public class Util { * <p>Used by blueprint. */ public void init() { - configuration = ConfigurationFactory.getConfiguration(); } @@ -59,7 +55,7 @@ public class Util { try { size = Integer.parseInt(sizeStr); } catch (NumberFormatException e) { - logger.error("Error while parse key:" + queue_size_key + " got from configuration " + e.getMessage(), e); + } return size; @@ -72,8 +68,7 @@ public class Util { try { size = Integer.parseInt(sizeStr); } catch (NumberFormatException e) { - logger.error("Error while parse key:" + threadpool_size_key + " got from configuration " - + e.getMessage(), e); + } return size; @@ -89,8 +84,7 @@ public class Util { Thread t = factory.newThread(r); t.setDaemon(isDaemon); if (threadNamePrefix != null && !threadNamePrefix.isEmpty()) { - final String threadName = String.format(THREAD_NAME_PATTERN, threadNamePrefix, counter - .incrementAndGet()); + final String threadName = String.format(THREAD_NAME_PATTERN, threadNamePrefix, counter.incrementAndGet()); t.setName(threadName); } return t; diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/ExecutionQueueServiceImpl.java b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/ExecutionQueueServiceImpl.java index 0634a0eb2..027cc9d4b 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/ExecutionQueueServiceImpl.java +++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/ExecutionQueueServiceImpl.java @@ -31,58 +31,59 @@ import org.onap.appc.executionqueue.ExecutionQueueService; import org.onap.appc.executionqueue.MessageExpirationListener; import org.onap.appc.executionqueue.impl.object.QueueMessage; -import java.time.Instant; +import java.util.Calendar; +import java.util.Date; import java.util.concurrent.TimeUnit; public class ExecutionQueueServiceImpl<M extends Runnable> implements ExecutionQueueService<M> { - private static final EELFLogger logger = - EELFManager.getInstance().getLogger(ExecutionQueueServiceImpl.class); + private final EELFLogger logger = EELFManager.getInstance().getLogger(ExecutionQueueServiceImpl.class); private QueueManager queueManager; - public ExecutionQueueServiceImpl() { - //do nothing + public ExecutionQueueServiceImpl(){ + + } + + @Override + public void putMessage(M message) throws APPCException { + this.putMessage(message,-1,null); } /** * Injected by blueprint - * - * @param queueManager queue manager to be set + * @param queueManager */ public void setQueueManager(QueueManager queueManager) { this.queueManager = queueManager; } @Override - public void putMessage(M message) throws APPCException { - this.putMessage(message, -1, null); - } + public void putMessage(M message, long timeout, TimeUnit unit) throws APPCException{ + QueueMessage queueMessage; - @Override - public void putMessage(M message, long timeout, TimeUnit unit) throws APPCException { - Instant expirationTime = calculateExpirationTime(timeout, unit); - boolean enqueueTask = queueManager.enqueueTask(new QueueMessage<>(message, expirationTime)); - if (!enqueueTask) { - logger.error("Error in putMessage method of ExecutionQueueServiceImpl"); - throw new APPCException("Failed to put message in queue"); + try { + Date expirationTime = calculateExpirationTime(timeout,unit); + queueMessage = new QueueMessage(message,expirationTime); + boolean enqueueTask = queueManager.enqueueTask(queueMessage); + if(!enqueueTask){ + throw new APPCException("failed to put message in queue"); + } + } catch (Exception e) { + logger.error("Error in putMessage method of ExecutionQueueServiceImpl" + e.getMessage()); + throw new APPCException(e); } } - @Override - public void registerMessageExpirationListener(MessageExpirationListener listener) { - queueManager.setListener(listener); - } - - private Instant calculateExpirationTime(long timeToLive, TimeUnit unit) { - if (timeToLive > 0 && unit != null) { - // as of Java 8, there is no built-in conversion method from - // TimeUnit to ChronoUnit; do it manually - return Instant.now().plusMillis(unit.toMillis(timeToLive)); - } else { - // never expires - return Instant.MAX; + private Date calculateExpirationTime(long timeToLive, TimeUnit unit) { + Date expirationTime = null; + if(timeToLive > 0){ + long currentTime = System.currentTimeMillis(); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentTime + unit.toMillis(timeToLive)); + expirationTime = cal.getTime(); } + return expirationTime; } } diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/QueueManager.java b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/QueueManager.java index db0e3d4c5..c33c66042 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/QueueManager.java +++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/QueueManager.java @@ -41,14 +41,14 @@ public class QueueManager { private final EELFLogger logger = EELFManager.getInstance().getLogger(QueueManager.class); - private MessageExpirationListener listener; private ExecutorService messageExecutor; + private LinkedBlockingQueue<QueueMessage> queue; private int max_thread_size; private int max_queue_size; private Util executionQueueUtil; public QueueManager() { - //do nothing + } /** @@ -90,14 +90,10 @@ public class QueueManager { } } - public void setListener(MessageExpirationListener listener) { - this.listener = listener; - } - /** * Injected by blueprint * - * @param executionQueueUtil Util to be set + * @param executionQueueUtil */ public void setExecutionQueueUtil(Util executionQueueUtil) { this.executionQueueUtil = executionQueueUtil; @@ -106,22 +102,16 @@ public class QueueManager { public boolean enqueueTask(QueueMessage queueMessage) { boolean isEnqueued = true; try { - messageExecutor.execute(() -> { - if (queueMessage.isExpired()) { - logger.debug("Message expired " + queueMessage.getMessage()); - if (listener != null) { - listener.onMessageExpiration(queueMessage.getMessage()); - } else { - logger.warn("Listener not available for expired message "); - } - } else { - queueMessage.getMessage().run(); - } - }); + messageExecutor.execute(() -> queueMessage.getMessage().run()); } catch (RejectedExecutionException ree) { isEnqueued = false; } return isEnqueued; } + + private boolean messageExpired(QueueMessage queueMessage) { + return queueMessage.getExpirationTime() != null && + queueMessage.getExpirationTime().getTime() < System.currentTimeMillis(); + } } diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/object/QueueMessage.java b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/object/QueueMessage.java index bb48da7e5..75d1275d2 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/object/QueueMessage.java +++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/onap/appc/executionqueue/impl/object/QueueMessage.java @@ -24,23 +24,22 @@ package org.onap.appc.executionqueue.impl.object; -import java.time.Instant; -import java.util.Objects; +import java.util.Date; public class QueueMessage<M extends Runnable> { - private final M message; - private final Instant expirationTime; - public QueueMessage(M message, Instant expirationTime){ + M message; + Date expirationTime; + public QueueMessage(M message, Date expirationTime){ this.message = message; - this.expirationTime = Objects.requireNonNull(expirationTime); + this.expirationTime = expirationTime; } public M getMessage() { return message; } - public boolean isExpired() { - return expirationTime.isBefore(Instant.now()); + public Date getExpirationTime() { + return expirationTime; } } diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/test/java/org/onap/appc/executionqueue/ExecutionQueueServiceTest.java b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/test/java/org/onap/appc/executionqueue/TestExecutionQueueService.java index 67f480d47..6884e9ccc 100644 --- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/test/java/org/onap/appc/executionqueue/ExecutionQueueServiceTest.java +++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/test/java/org/onap/appc/executionqueue/TestExecutionQueueService.java @@ -37,18 +37,20 @@ import org.onap.appc.executionqueue.impl.ExecutionQueueServiceImpl; import org.onap.appc.executionqueue.impl.QueueManager; import org.powermock.modules.junit4.PowerMockRunner; +import java.util.concurrent.TimeUnit; + import static org.mockito.Matchers.any; import static org.mockito.Mockito.times; @RunWith(PowerMockRunner.class) -public class ExecutionQueueServiceTest { +public class TestExecutionQueueService { @InjectMocks - private ExecutionQueueServiceImpl service; + ExecutionQueueServiceImpl service; @Spy - private QueueManager queueManager = new QueueManager(); + QueueManager queueManager = new QueueManager(); @Spy - private Util executionQueueUtil = new Util(); + Util executionQueueUtil = new Util(); @Before public void setup() { diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/pom.xml b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/pom.xml index d340bc19b..b03ce9763 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/pom.xml @@ -1,5 +1,30 @@ <?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"> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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>lock-manager-lib</artifactId> @@ -8,6 +33,7 @@ </parent> <artifactId>lock-manager-api</artifactId> + <name>APPC Lock Manager - API</name> <packaging>bundle</packaging> <build> @@ -24,4 +50,4 @@ </plugin> </plugins> </build> -</project>
\ No newline at end of file +</project> diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/src/main/java/org/onap/appc/lockmanager/api/LockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/src/main/java/org/onap/appc/lockmanager/api/LockManager.java index e6a0fb778..723690649 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/src/main/java/org/onap/appc/lockmanager/api/LockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-api/src/main/java/org/onap/appc/lockmanager/api/LockManager.java @@ -69,4 +69,13 @@ public interface LockManager { boolean isLocked(String resource); + /** + * returns the oner of the resource + * if no one owns, returns null + * @param resource + * @return owner of the resource + */ + + String getLockOwner(String resource); + } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/pom.xml b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/pom.xml index 4f34bbaa9..af3556519 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/pom.xml @@ -1,107 +1,133 @@ <?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>lock-manager-lib</artifactId> - <groupId>org.onap.appc</groupId> - <version>1.3.0-SNAPSHOT</version> - </parent> - <name>lock-manager-features</name> - <artifactId>lock-manager-features</artifactId> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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 - <packaging>jar</packaging> + http://www.apache.org/licenses/LICENSE-2.0 - <dependencies> - <dependency> - <groupId>org.onap.appc</groupId> - <artifactId>lock-manager-api</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.onap.appc</groupId> - <artifactId>lock-manager-impl</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. - <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> - <!--<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. –> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <version>2.16</version> - <configuration> - <systemPropertyVariables> - <karaf.distro.groupId>org.opendaylight.controller</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> - <classpathDependencyExcludes> - <!– The dependencies which bring in AbstractDataBrokerTest class - brings in a second PaxExam container which results in the feature tests failing - with a message similar to: "ERROR o.ops4j.pax.exam.spi.PaxExamRuntime - Ambiguous - TestContainer ..." This excludes the container we don't want to use. –> - <classpathDependencyExcludes>org.ops4j.pax.exam:pax-exam-container-native</classpathDependencyExcludes> - </classpathDependencyExcludes> - </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> - - <!-- Skipping ODL feature test --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <skipTests>true</skipTests> - </configuration> - </plugin> - </plugins> - </build> + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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>lock-manager-lib</artifactId> + <groupId>org.onap.appc</groupId> + <version>1.3.0-SNAPSHOT</version> + </parent> + + <artifactId>lock-manager-features</artifactId> + <name>APPC Lock Manager - feature</name> + <packaging>jar</packaging> + + + <dependencies> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>lock-manager-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>lock-manager-impl</artifactId> + <version>${project.version}</version> + </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> + <!--<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. –> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.16</version> + <configuration> + <systemPropertyVariables> + <karaf.distro.groupId>org.opendaylight.controller</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> + <classpathDependencyExcludes> + <!– The dependencies which bring in AbstractDataBrokerTest class + brings in a second PaxExam container which results in the feature tests failing + with a message similar to: "ERROR o.ops4j.pax.exam.spi.PaxExamRuntime - Ambiguous + TestContainer ..." This excludes the container we don't want to use. –> + <classpathDependencyExcludes>org.ops4j.pax.exam:pax-exam-container-native</classpathDependencyExcludes> + </classpathDependencyExcludes> + </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> + + <!-- Skipping ODL feature test --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + </plugins> + </build> </project> diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/pom.xml b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/pom.xml index a4334a2e0..40a7f50c3 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/pom.xml @@ -1,5 +1,30 @@ <?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"> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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>lock-manager-lib</artifactId> @@ -8,8 +33,10 @@ </parent> <artifactId>lock-manager-impl</artifactId> + <name>APPC Lock Manager - Impl</name> <packaging>bundle</packaging> + <dependencies> <dependency> <groupId>org.onap.appc</groupId> @@ -45,8 +72,7 @@ <instructions> <Export-Service>org.onap.appc.lockmanager.api.LockManager</Export-Service> <Import-Package> - org.onap.appc.lockmanager.api.*, - org.onap.appc.dao.util,com.att.eelf.configuration, *;resolution:=optional + org.onap.appc.lockmanager.api.*, com.att.eelf.configuration, *;resolution:=optional </Import-Package> <Private-Package>org.onap.appc.lockmanager.impl.*</Private-Package> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/inmemory/LockManagerInMemoryImpl.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/inmemory/LockManagerInMemoryImpl.java index b141d9607..140d9ebbc 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/inmemory/LockManagerInMemoryImpl.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/inmemory/LockManagerInMemoryImpl.java @@ -38,7 +38,7 @@ public class LockManagerInMemoryImpl implements LockManager { private static LockManagerInMemoryImpl instance = null; private Map<String, LockValue> lockedVNFs; - private static final EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger(); + private final EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger(); private LockManagerInMemoryImpl() { lockedVNFs = new ConcurrentHashMap<>(); @@ -110,7 +110,12 @@ public class LockManagerInMemoryImpl implements LockManager { @Override public boolean isLocked(String resource) { - return lockedVNFs.get(resource)!=null?true:false; + return lockedVNFs.get(resource) != null; + } + + @Override + public String getLockOwner(String resource) { + return lockedVNFs.get(resource).getOwner(); } private boolean lockIsMine(LockValue lockValue, String owner, long now) { diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/JdbcLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/JdbcLockManager.java index 9b2083101..b8cf0f741 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/JdbcLockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/JdbcLockManager.java @@ -26,7 +26,8 @@ package org.onap.appc.lockmanager.impl.sql; import java.sql.Connection; -import org.onap.appc.dao.util.JdbcConnectionFactory; + +import org.onap.appc.dao.util.api.JdbcConnectionFactory; import org.onap.appc.lockmanager.api.LockManager; public abstract class JdbcLockManager implements LockManager { diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/Messages.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/Messages.java index 769d94257..4f2831157 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/Messages.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/Messages.java @@ -27,7 +27,7 @@ package org.onap.appc.lockmanager.impl.sql; public enum Messages { ERR_NULL_LOCK_OWNER("Cannot acquire lock for resource [%s]: lock owner must be specified"), - ERR_LOCK_LOCKED_BY_OTHER("Cannot lock resource [%s] for [%s]: already locked by [%s]"), + ERR_LOCK_LOCKED_BY_OTHER("VNF : [%s] is locked by request id : [%s]"), ERR_UNLOCK_NOT_LOCKED("Error unlocking resource [%s]: resource is not locked"), ERR_UNLOCK_LOCKED_BY_OTHER("Error unlocking resource [%s] by [%s]: resource is locked by [%s]"), EXP_LOCK("Error locking resource [%s]."), diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/MySqlConnectionFactory.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/MySqlConnectionFactory.java index 4df89541d..7f91d21cd 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/MySqlConnectionFactory.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/MySqlConnectionFactory.java @@ -32,6 +32,8 @@ import org.onap.appc.dao.util.DefaultJdbcConnectionFactory; public class MySqlConnectionFactory extends DefaultJdbcConnectionFactory { protected void registedDriver() throws SQLException { - DriverManager.registerDriver(new org.mariadb.jdbc.Driver()); + DriverManager.registerDriver(new org.mariadb.jdbc.Driver()); + } + } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/LockRecord.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/LockRecord.java index ff0e63b8d..94e656d2d 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/LockRecord.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/LockRecord.java @@ -26,49 +26,49 @@ package org.onap.appc.lockmanager.impl.sql.optimistic; class LockRecord { - private String resource; - private String owner; - private long updated; - private long timeout; - private long ver; + private String resource; + private String owner; + private long updated; + private long timeout; + private long ver; - LockRecord(String resource) { - this.resource = resource; - } + LockRecord(String resource) { + this.resource = resource; + } - public String getResource() { - return resource; - } + public String getResource() { + return resource; + } - public String getOwner() { - return owner; - } + public String getOwner() { + return owner; + } - public void setOwner(String owner) { - this.owner = owner; - } + public void setOwner(String owner) { + this.owner = owner; + } - public long getUpdated() { - return updated; - } + public long getUpdated() { + return updated; + } - public void setUpdated(long updated) { - this.updated = updated; - } + public void setUpdated(long updated) { + this.updated = updated; + } - public long getTimeout() { - return timeout; - } + public long getTimeout() { + return timeout; + } - public void setTimeout(long timeout) { - this.timeout = timeout; - } + public void setTimeout(long timeout) { + this.timeout = timeout; + } - public long getVer() { - return ver; - } + public long getVer() { + return ver; + } - public void setVer(long ver) { - this.ver = ver; - } + public void setVer(long ver) { + this.ver = ver; + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManager.java index d1dd2c5a3..1cbc1fb04 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManager.java @@ -28,8 +28,10 @@ import java.sql.SQLException; public class MySqlLockManager extends SqlLockManager { - @Override - protected boolean isDuplicatePkError(SQLException e) { - return (e.getErrorCode() == 1062); - } + @Override + protected boolean isDuplicatePkError(SQLException e) { + return (e.getErrorCode() == 1062); + } + + } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java index 26ec6a274..481350199 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java @@ -36,231 +36,271 @@ import org.onap.appc.lockmanager.impl.sql.Messages; abstract class SqlLockManager extends JdbcLockManager { - private static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?"; - private static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT, VER) VALUES (?, ?, ?, ?, ?)"; - private static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=?, VER=? WHERE RESOURCE_ID=? AND VER=?"; -// private static final String SQL_DELETE_LOCK_RECORD = "DELETE FROM %s WHERE RESOURCE_ID=? AND VER=?"; - private static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()"; + private static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?"; + private static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT, VER) VALUES (?, ?, ?, ?, ?)"; + private static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=?, VER=? WHERE RESOURCE_ID=? AND VER=?"; +// private static final String SQL_DELETE_LOCK_RECORD = "DELETE FROM %s WHERE RESOURCE_ID=? AND VER=?"; + private static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()"; + private static final String SQL_LOAD_LOCK_RECORD_WITH_OWNER = "SELECT * FROM LOCK_MANAGEMENT WHERE RESOURCE_ID = ? AND OWNER = ? "; - private String sqlLoadLockRecord; - private String sqlInsertLockRecord; - private String sqlUpdateLockRecord; -// private String sqlDeleteLockRecord; + private String sqlLoadLockRecord; + private String sqlInsertLockRecord; + private String sqlUpdateLockRecord; +// private String sqlDeleteLockRecord; - @Override - public boolean acquireLock(String resource, String owner) throws LockException { - return acquireLock(resource, owner, 0); - } + @Override + public boolean acquireLock(String resource, String owner) throws LockException { + return acquireLock(resource, owner, 0); + } - @Override - public boolean acquireLock(String resource, String owner, long timeout) throws LockException { - if(owner == null) { - throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource)); - } - boolean res = false; - Connection connection = openDbConnection(); - try { - res = lockResource(connection, resource, owner, timeout); - } finally { - closeDbConnection(connection); - } - return res; - } + @Override + public boolean acquireLock(String resource, String owner, long timeout) throws LockException { + if(owner == null) { + throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource)); + } + boolean res = false; + Connection connection = openDbConnection(); + try { + res = lockResource(connection, resource, owner, timeout); + } finally { + closeDbConnection(connection); + } + return res; + } - @Override - public void releaseLock(String resource, String owner) throws LockException { - Connection connection = openDbConnection(); - try { - unlockResource(connection, resource, owner); - } finally { - closeDbConnection(connection); - } - } + @Override + public void releaseLock(String resource, String owner) throws LockException { + Connection connection = openDbConnection(); + try { + unlockResource(connection, resource, owner); + } finally { + closeDbConnection(connection); + } + } - @Override - public boolean isLocked(String resource) { + @Override + public boolean isLocked(String resource) { Connection connection=openDbConnection(); - try { - LockRecord lockRecord=loadLockRecord(connection,resource); - if(lockRecord==null){ - return false; - }else{ - if(lockRecord.getOwner()==null){ - return false; - }else if(isLockExpired(lockRecord, connection)){ - return false; - }else{ + try { + LockRecord lockRecord=loadLockRecord(connection,resource); + if(lockRecord==null){ + return false; + }else{ + if(lockRecord.getOwner()==null){ + return false; + }else if(isLockExpired(lockRecord, connection)){ + return false; + }else{ return true; } - } - } catch (SQLException e) { - throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource)); - }finally { + } + } catch (SQLException e) { + throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource)); + }finally { closeDbConnection(connection); } } - private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException { - try { - boolean res = false; - LockRecord lockRecord = loadLockRecord(connection, resource); - if(lockRecord != null) { - // lock record already exists - String currentOwner = lockRecord.getOwner(); - if(currentOwner != null) { - if(isLockExpired(lockRecord, connection)) { - currentOwner = null; - } else if(!owner.equals(currentOwner)) { - throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner)); - } - } - // set new owner on the resource lock record - if(!updateLockRecord(connection, resource, owner, timeout, lockRecord.getVer())) { - // try again - maybe same owner updated the record - lockResource(connection, resource, owner, timeout); - } - if(currentOwner == null) { - // no one locked the resource before - res = true; - } - } else { - // resource record does not exist in lock table => create new record - try { - addLockRecord(connection, resource, owner, timeout); - res = true; - } catch(SQLException e) { - if(isDuplicatePkError(e)) { - // try again - maybe same owner inserted the record - lockResource(connection, resource, owner, timeout); - } else { - throw e; - } - } - } - return res; - } catch(SQLException e) { - throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e); - } - } + @Override + public String getLockOwner(String resource) { + Connection connection=openDbConnection(); + try { + LockRecord lockRecord=loadLockRecord(connection,resource); + if(lockRecord==null || lockRecord.getOwner() ==null ){ + return null; + }else{ + if(isLockExpired(lockRecord, connection)){ + return null; + }else{ + return lockRecord.getOwner(); + } + } + } catch (SQLException e) { + throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource)); + }finally { + closeDbConnection(connection); + } + } - protected boolean isDuplicatePkError(SQLException e) { - return e.getSQLState().startsWith("23"); - } + private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException { + try { + boolean res = false; + LockRecord lockRecord = loadLockRecord(connection, resource); + if(lockRecord != null) { + // lock record already exists + String currentOwner = lockRecord.getOwner(); + if(currentOwner != null) { + if(isLockExpired(lockRecord, connection)) { + currentOwner = null; + } else if(!owner.equals(currentOwner)) { + throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, currentOwner)); + } + } + // set new owner on the resource lock record + if(!updateLockRecord(connection, resource, owner, timeout, lockRecord.getVer())) { + // try again - maybe same owner updated the record + lockResource(connection, resource, owner, timeout); + } + if(currentOwner == null) { + // no one locked the resource before + res = true; + } + } else { + // resource record does not exist in lock table => create new record + try { + addLockRecord(connection, resource, owner, timeout); + res = true; + } catch(SQLException e) { + if(isDuplicatePkError(e)) { + // try again - maybe same owner inserted the record + lockResource(connection, resource, owner, timeout); + } else { + throw e; + } + } + } + return res; + } catch(SQLException e) { + throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e); + } + } + + protected boolean isDuplicatePkError(SQLException e) { + return e.getSQLState().startsWith("23"); + } - private void unlockResource(Connection connection, String resource, String owner) throws LockException { - try { - LockRecord lockRecord = loadLockRecord(connection, resource); - if(lockRecord != null) { - // check if expired - if(isLockExpired(lockRecord, connection)) { - // lock is expired => no lock - lockRecord = null; - } - } - if((lockRecord == null) || (lockRecord.getOwner() == null)) { - // resource is not locked - throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource)); - } - String currentOwner = lockRecord.getOwner(); - if(!owner.equals(currentOwner)) { - throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner)); + private void unlockResource(Connection connection, String resource, String owner) throws LockException { + try { + LockRecord lockRecord = loadLockRecord(connection, resource); + if(lockRecord != null) { + // check if expired + if(isLockExpired(lockRecord, connection)) { + // lock is expired => no lock + lockRecord = null; + } + } + if((lockRecord == null) || (lockRecord.getOwner() == null)) { + // resource is not locked + throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource)); + } + String currentOwner = lockRecord.getOwner(); + if(!owner.equals(currentOwner)) { + throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner)); } if (!updateLockRecord(connection, resource, null, 0, lockRecord.getVer())) { - unlockResource(connection, resource, owner); - } - // TODO delete record from table on lock release? -// deleteLockRecord(connection, resource, lockRecord.getVer()); - } catch(SQLException e) { - throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e); - } - } + unlockResource(connection, resource, owner); + } + // TODO delete record from table on lock release? +// deleteLockRecord(connection, resource, lockRecord.getVer()); + } catch(SQLException e) { + throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e); + } + } - protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { - LockRecord res = null; - if(sqlLoadLockRecord == null) { - sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName); - } - try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) { - statement.setString(1, resource); - try(ResultSet resultSet = statement.executeQuery()) { - if(resultSet.next()) { - res = new LockRecord(resource); - res.setOwner(resultSet.getString(2)); - res.setUpdated(resultSet.getLong(3)); - res.setTimeout(resultSet.getLong(4)); - res.setVer(resultSet.getLong(5)); - } - } - } - return res; - } + protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { + LockRecord res = null; + if(sqlLoadLockRecord == null) { + sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName); + } + try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) { + statement.setString(1, resource); + try(ResultSet resultSet = statement.executeQuery()) { + if(resultSet.next()) { + res = new LockRecord(resource); + res.setOwner(resultSet.getString(2)); + res.setUpdated(resultSet.getLong(3)); + res.setTimeout(resultSet.getLong(4)); + res.setVer(resultSet.getLong(5)); + } + } + } + return res; + } + + protected LockRecord loadLockRecord(Connection connection, String resource,String owner) throws SQLException { + LockRecord res = null; + try(PreparedStatement statement = connection.prepareStatement(SQL_LOAD_LOCK_RECORD_WITH_OWNER)) { + statement.setString(1, resource); + statement.setString(2, owner); + try(ResultSet resultSet = statement.executeQuery()) { + if(resultSet.next()) { + res = new LockRecord(resource); + res.setOwner(resultSet.getString(2)); + res.setUpdated(resultSet.getLong(3)); + res.setTimeout(resultSet.getLong(4)); + res.setVer(resultSet.getLong(5)); + } + } + } + return res; + } - protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { - if(sqlInsertLockRecord == null) { - sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName); - } - try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) { - statement.setString(1, resource); - statement.setString(2, owner); + protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { + if(sqlInsertLockRecord == null) { + sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName); + } + try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) { + statement.setString(1, resource); + statement.setString(2, owner); statement.setLong(3, getCurrentTime(connection)); - statement.setLong(4, timeout); - statement.setLong(5, 1); - statement.executeUpdate(); - } - } + statement.setLong(4, timeout); + statement.setLong(5, 1); + statement.executeUpdate(); + } + } - protected boolean updateLockRecord(Connection connection, String resource, String owner, long timeout, long ver) throws SQLException { - if(sqlUpdateLockRecord == null) { - sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName); - } - try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) { - long newVer = (ver >= Long.MAX_VALUE) ? 1 : (ver + 1); - statement.setString(1, owner); + protected boolean updateLockRecord(Connection connection, String resource, String owner, long timeout, long ver) throws SQLException { + if(sqlUpdateLockRecord == null) { + sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName); + } + try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) { + long newVer = (ver >= Long.MAX_VALUE) ? 1 : (ver + 1); + statement.setString(1, owner); statement.setLong(2, getCurrentTime(connection)); - statement.setLong(3, timeout); - statement.setLong(4, newVer); - statement.setString(5, resource); - statement.setLong(6, ver); - return (statement.executeUpdate() != 0); - } - } + statement.setLong(3, timeout); + statement.setLong(4, newVer); + statement.setString(5, resource); + statement.setLong(6, ver); + return (statement.executeUpdate() != 0); + } + } -// protected void deleteLockRecord(Connection connection, String resource, long ver) throws SQLException { -// if(sqlDeleteLockRecord == null) { -// sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName); -// } -// try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) { -// statement.setString(1, resource); -// statement.setLong(2, ver); -// statement.executeUpdate(); -// } -// } +// protected void deleteLockRecord(Connection connection, String resource, long ver) throws SQLException { +// if(sqlDeleteLockRecord == null) { +// sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName); +// } +// try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) { +// statement.setString(1, resource); +// statement.setLong(2, ver); +// statement.executeUpdate(); +// } +// } - private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException { - long timeout = lockRecord.getTimeout(); - if(timeout == 0) { - return false; - } - long updated = lockRecord.getUpdated(); + private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException { + long timeout = lockRecord.getTimeout(); + if(timeout == 0) { + return false; + } + long updated = lockRecord.getUpdated(); long now = getCurrentTime(connection); - long expiration = updated + timeout; - return (now > expiration); - } + long expiration = updated + timeout; + return (now > expiration); + } - private long getCurrentTime(Connection connection) throws SQLException { - long res = -1; - if(connection != null) { - try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) { - try(ResultSet resultSet = statement.executeQuery()) { - if(resultSet.next()) { - res = resultSet.getTimestamp(1).getTime(); - } - } - } - } - if(res == -1) { - res = System.currentTimeMillis(); - } - return res; - } + private long getCurrentTime(Connection connection) throws SQLException { + long res = -1; + if(connection != null) { + try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) { + try(ResultSet resultSet = statement.executeQuery()) { + if(resultSet.next()) { + res = resultSet.getTimestamp(1).getTime(); + } + } + } + } + if(res == -1) { + res = System.currentTimeMillis(); + } + return res; + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/LockRecord.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/LockRecord.java index 1960ba9a3..3a3799697 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/LockRecord.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/LockRecord.java @@ -26,40 +26,40 @@ package org.onap.appc.lockmanager.impl.sql.pessimistic; class LockRecord { - private String resource; - private String owner; - private long updated; - private long timeout; + private String resource; + private String owner; + private long updated; + private long timeout; - LockRecord(String resource) { - this.resource = resource; - } + LockRecord(String resource) { + this.resource = resource; + } - public String getResource() { - return resource; - } + public String getResource() { + return resource; + } - public String getOwner() { - return owner; - } + public String getOwner() { + return owner; + } - public void setOwner(String owner) { - this.owner = owner; - } + public void setOwner(String owner) { + this.owner = owner; + } - public long getUpdated() { - return updated; - } + public long getUpdated() { + return updated; + } - public void setUpdated(long updated) { - this.updated = updated; - } + public void setUpdated(long updated) { + this.updated = updated; + } - public long getTimeout() { - return timeout; - } + public long getTimeout() { + return timeout; + } - public void setTimeout(long timeout) { - this.timeout = timeout; - } + public void setTimeout(long timeout) { + this.timeout = timeout; + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManager.java index b76f15c8f..5268acf20 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManager.java @@ -33,56 +33,56 @@ import org.onap.appc.lockmanager.api.LockRuntimeException; public class MySqlLockManager extends SqlLockManager { - private static final int DEF_CRITICAL_SECTION_WAIT_TIMEOUT = 3; + private static final int DEF_CRITICAL_SECTION_WAIT_TIMEOUT = 3; - protected int criticalSectionWaitTimeoutSecs = DEF_CRITICAL_SECTION_WAIT_TIMEOUT; + protected int criticalSectionWaitTimeoutSecs = DEF_CRITICAL_SECTION_WAIT_TIMEOUT; - public void setCriticalSectionWaitTimeoutSecs(int criticalSectionWaitTimeoutSecs) { - this.criticalSectionWaitTimeoutSecs = criticalSectionWaitTimeoutSecs; - } + public void setCriticalSectionWaitTimeoutSecs(int criticalSectionWaitTimeoutSecs) { + this.criticalSectionWaitTimeoutSecs = criticalSectionWaitTimeoutSecs; + } - @Override - protected void enterCriticalSection(Connection connection, String resource) { - try { - CallableStatement statement = connection.prepareCall("SELECT COALESCE(GET_LOCK(?,?),0)"); - try { - statement.setString(1, resource); - statement.setInt(2, criticalSectionWaitTimeoutSecs); - boolean execRes = statement.execute(); - int result = 0; - if(execRes) { - ResultSet resultSet = statement.getResultSet(); - try { - if(resultSet.next()) { - result = resultSet.getInt(1); - } - } finally { - resultSet.close(); - } - } - if(result != 1) { // lock is not obtained - throw new LockRuntimeException("Cannot obtain critical section lock for resource [" + resource + "]."); - } - } finally { - statement.close(); - } - } catch(SQLException e) { + @Override + protected void enterCriticalSection(Connection connection, String resource) { + try { + CallableStatement statement = connection.prepareCall("SELECT COALESCE(GET_LOCK(?,?),0)"); + try { + statement.setString(1, resource); + statement.setInt(2, criticalSectionWaitTimeoutSecs); + boolean execRes = statement.execute(); + int result = 0; + if(execRes) { + ResultSet resultSet = statement.getResultSet(); + try { + if(resultSet.next()) { + result = resultSet.getInt(1); + } + } finally { + resultSet.close(); + } + } + if(result != 1) { // lock is not obtained + throw new LockRuntimeException("Cannot obtain critical section lock for resource [" + resource + "]."); + } + } finally { + statement.close(); + } + } catch(SQLException e) { throw new LockRuntimeException("Cannot obtain critical section lock for resource [" + resource + "].", e); - } - } + } + } - @Override - protected void leaveCriticalSection(Connection connection, String resource) { - try { - CallableStatement statement = connection.prepareCall("SELECT RELEASE_LOCK(?)"); - try { - statement.setString(1, resource); - statement.execute(); - } finally { - statement.close(); - } - } catch(SQLException e) { - throw new LockRuntimeException("Error releasing critical section lock.", e); - } - } + @Override + protected void leaveCriticalSection(Connection connection, String resource) { + try { + CallableStatement statement = connection.prepareCall("SELECT RELEASE_LOCK(?)"); + try { + statement.setString(1, resource); + statement.execute(); + } finally { + statement.close(); + } + } catch(SQLException e) { + throw new LockRuntimeException("Error releasing critical section lock.", e); + } + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/SqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/SqlLockManager.java index a1536d969..98c753616 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/SqlLockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/onap/appc/lockmanager/impl/sql/pessimistic/SqlLockManager.java @@ -36,219 +36,240 @@ import org.onap.appc.lockmanager.impl.sql.Messages; abstract class SqlLockManager extends JdbcLockManager { - private static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?"; - private static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT) VALUES (?, ?, ?, ?)"; - private static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=? WHERE RESOURCE_ID=?"; - private static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()"; - - private String sqlLoadLockRecord; - private String sqlInsertLockRecord; - private String sqlUpdateLockRecord; - - @Override - public boolean acquireLock(String resource, String owner) throws LockException { - return acquireLock(resource, owner, 0); - } - - @Override - public boolean acquireLock(String resource, String owner, long timeout) throws LockException { - if(owner == null) { - throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource)); - } - boolean res = false; - Connection connection = openDbConnection(); - try { - enterCriticalSection(connection, resource); - try { - res = lockResource(connection, resource, owner, timeout); - } finally { - leaveCriticalSection(connection, resource); - } - } finally { - closeDbConnection(connection); - } - return res; - } - - @Override - public void releaseLock(String resource, String owner) throws LockException { - Connection connection = openDbConnection(); - try { - enterCriticalSection(connection, resource); - try { - unlockResource(connection, resource, owner); - } finally { - leaveCriticalSection(connection, resource); - } - } finally { - closeDbConnection(connection); - } - } - - @Override - public boolean isLocked(String resource) { - Connection connection=openDbConnection(); - try { - LockRecord lockRecord=loadLockRecord(connection,resource); - if(lockRecord==null){ - return false; - }else{ - if(lockRecord.getOwner()==null){ - return false; - }else if(isLockExpired(lockRecord, connection)){ - return false; - }else{ - return true; - } - } - } catch (SQLException e) { - throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource)); - }finally { - closeDbConnection(connection); - } - } - - private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException { - try { - boolean res = false; - LockRecord lockRecord = loadLockRecord(connection, resource); - if(lockRecord != null) { - // lock record already exists - String currentOwner = lockRecord.getOwner(); - if(currentOwner != null) { - if(isLockExpired(lockRecord, connection)) { - currentOwner = null; - } else if(!owner.equals(currentOwner)) { - throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner)); - } - } - // set new owner on the resource lock record - updateLockRecord(connection, resource, owner, timeout); - if(currentOwner == null) { - // no one locked the resource before - res = true; - } - } else { - // resource record does not exist in lock table => create new record - addLockRecord(connection, resource, owner, timeout); - res = true; - } - return res; - } catch(SQLException e) { - throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e); - } - } - - private void unlockResource(Connection connection, String resource, String owner) throws LockException { - try { - LockRecord lockRecord = loadLockRecord(connection, resource); - if(lockRecord != null) { - // check if expired - if(isLockExpired(lockRecord, connection)) { - // lock is expired => no lock - lockRecord = null; - } - } - if((lockRecord == null) || (lockRecord.getOwner() == null)) { - // resource is not locked - throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource)); - } - String currentOwner = lockRecord.getOwner(); - if(!owner.equals(currentOwner)) { - throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner)); - } - updateLockRecord(connection, resource, null, 0); - // TODO delete record from table on lock release? -// deleteLockRecord(connection, resource); - } catch(SQLException e) { - throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e); - } - } - - protected abstract void enterCriticalSection(Connection connection, String resource); - - protected abstract void leaveCriticalSection(Connection connection, String resource); - - protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { - LockRecord res = null; - if(sqlLoadLockRecord == null) { - sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName); - } - try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) { - statement.setString(1, resource); - try(ResultSet resultSet = statement.executeQuery()) { - if(resultSet.next()) { - res = new LockRecord(resource); - res.setOwner(resultSet.getString(2)); - res.setUpdated(resultSet.getLong(3)); - res.setTimeout(resultSet.getLong(4)); - } - } - } - return res; - } - - protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { - if(sqlInsertLockRecord == null) { - sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName); - } - try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) { - statement.setString(1, resource); - statement.setString(2, owner); - statement.setLong(3, getCurrentTime(connection)); - statement.setLong(4, timeout); - statement.executeUpdate(); - } - } - - protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { - if(sqlUpdateLockRecord == null) { - sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName); - } - try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) { - statement.setString(1, owner); - statement.setLong(2, getCurrentTime(connection)); - statement.setLong(3, timeout); - statement.setString(4, resource); - statement.executeUpdate(); - } - } - -// protected void deleteLockRecord(Connection connection, String resource) throws SQLException { -// if(sqlDeleteLockRecord == null) { -// sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName); -// } -// try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) { -// statement.setString(1, resource); -// statement.executeUpdate(); -// } -// } - - private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException { - long timeout = lockRecord.getTimeout(); - if(timeout == 0) { - return false; - } - long updated = lockRecord.getUpdated(); - long now = getCurrentTime(connection); - long expiration = updated + timeout; - return (now > expiration); - } - - private long getCurrentTime(Connection connection) throws SQLException { - long res = -1; - if(connection != null) { - try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) { - try(ResultSet resultSet = statement.executeQuery()) { - if(resultSet.next()) { - res = resultSet.getTimestamp(1).getTime(); - } - } - } - } - if(res == -1) { - res = System.currentTimeMillis(); - } - return res; - } + private static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?"; + private static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT) VALUES (?, ?, ?, ?)"; + private static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=? WHERE RESOURCE_ID=?"; + private static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()"; + + private String sqlLoadLockRecord; + private String sqlInsertLockRecord; + private String sqlUpdateLockRecord; + + @Override + public boolean acquireLock(String resource, String owner) throws LockException { + return acquireLock(resource, owner, 0); + } + + @Override + public boolean acquireLock(String resource, String owner, long timeout) throws LockException { + if(owner == null) { + throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource)); + } + boolean res = false; + Connection connection = openDbConnection(); + try { + enterCriticalSection(connection, resource); + try { + res = lockResource(connection, resource, owner, timeout); + } finally { + leaveCriticalSection(connection, resource); + } + } finally { + closeDbConnection(connection); + } + return res; + } + + @Override + public void releaseLock(String resource, String owner) throws LockException { + Connection connection = openDbConnection(); + try { + enterCriticalSection(connection, resource); + try { + unlockResource(connection, resource, owner); + } finally { + leaveCriticalSection(connection, resource); + } + } finally { + closeDbConnection(connection); + } + } + + @Override + public boolean isLocked(String resource) { + Connection connection=openDbConnection(); + try { + LockRecord lockRecord=loadLockRecord(connection,resource); + if(lockRecord==null){ + return false; + }else{ + if(lockRecord.getOwner()==null){ + return false; + }else if(isLockExpired(lockRecord, connection)){ + return false; + }else{ + return true; + } + } + } catch (SQLException e) { + throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource)); + }finally { + closeDbConnection(connection); + } + } + + @Override + public String getLockOwner(String resource) { + Connection connection=openDbConnection(); + try { + org.onap.appc.lockmanager.impl.sql.pessimistic.LockRecord lockRecord=loadLockRecord(connection,resource); + if(lockRecord==null || lockRecord.getOwner() ==null ){ + return null; + }else{ + if(isLockExpired(lockRecord, connection)){ + return null; + }else{ + return lockRecord.getOwner(); + } + } + } catch (SQLException e) { + throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource)); + }finally { + closeDbConnection(connection); + } + } + + private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException { + try { + boolean res = false; + LockRecord lockRecord = loadLockRecord(connection, resource); + if(lockRecord != null) { + // lock record already exists + String currentOwner = lockRecord.getOwner(); + if(currentOwner != null) { + if(isLockExpired(lockRecord, connection)) { + currentOwner = null; + } else if(!owner.equals(currentOwner)) { + throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, currentOwner)); + } + } + // set new owner on the resource lock record + updateLockRecord(connection, resource, owner, timeout); + if(currentOwner == null) { + // no one locked the resource before + res = true; + } + } else { + // resource record does not exist in lock table => create new record + addLockRecord(connection, resource, owner, timeout); + res = true; + } + return res; + } catch(SQLException e) { + throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e); + } + } + + private void unlockResource(Connection connection, String resource, String owner) throws LockException { + try { + LockRecord lockRecord = loadLockRecord(connection, resource); + if(lockRecord != null) { + // check if expired + if(isLockExpired(lockRecord, connection)) { + // lock is expired => no lock + lockRecord = null; + } + } + if((lockRecord == null) || (lockRecord.getOwner() == null)) { + // resource is not locked + throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource)); + } + String currentOwner = lockRecord.getOwner(); + if(!owner.equals(currentOwner)) { + throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner)); + } + updateLockRecord(connection, resource, null, 0); + // TODO delete record from table on lock release? +// deleteLockRecord(connection, resource); + } catch(SQLException e) { + throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e); + } + } + + protected abstract void enterCriticalSection(Connection connection, String resource); + + protected abstract void leaveCriticalSection(Connection connection, String resource); + + protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { + LockRecord res = null; + if(sqlLoadLockRecord == null) { + sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName); + } + try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) { + statement.setString(1, resource); + try(ResultSet resultSet = statement.executeQuery()) { + if(resultSet.next()) { + res = new LockRecord(resource); + res.setOwner(resultSet.getString(2)); + res.setUpdated(resultSet.getLong(3)); + res.setTimeout(resultSet.getLong(4)); + } + } + } + return res; + } + + protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { + if(sqlInsertLockRecord == null) { + sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName); + } + try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) { + statement.setString(1, resource); + statement.setString(2, owner); + statement.setLong(3, getCurrentTime(connection)); + statement.setLong(4, timeout); + statement.executeUpdate(); + } + } + + protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { + if(sqlUpdateLockRecord == null) { + sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName); + } + try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) { + statement.setString(1, owner); + statement.setLong(2, getCurrentTime(connection)); + statement.setLong(3, timeout); + statement.setString(4, resource); + statement.executeUpdate(); + } + } + +// protected void deleteLockRecord(Connection connection, String resource) throws SQLException { +// if(sqlDeleteLockRecord == null) { +// sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName); +// } +// try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) { +// statement.setString(1, resource); +// statement.executeUpdate(); +// } +// } + + private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException { + long timeout = lockRecord.getTimeout(); + if(timeout == 0) { + return false; + } + long updated = lockRecord.getUpdated(); + long now = getCurrentTime(connection); + long expiration = updated + timeout; + return (now > expiration); + } + + private long getCurrentTime(Connection connection) throws SQLException { + long res = -1; + if(connection != null) { + try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) { + try(ResultSet resultSet = statement.executeQuery()) { + if(resultSet.next()) { + res = resultSet.getTimestamp(1).getTime(); + } + } + } + } + if(res == -1) { + res = System.currentTimeMillis(); + } + return res; + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/api/LockManagerBaseTests.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/api/LockManagerBaseTests.java index 9f7e84c43..8a53372ce 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/api/LockManagerBaseTests.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/api/LockManagerBaseTests.java @@ -32,139 +32,139 @@ import org.onap.appc.lockmanager.api.LockManager; public abstract class LockManagerBaseTests { - protected enum Resource {Resource1, Resource2}; - protected enum Owner {A, B}; - - protected LockManager lockManager; - - @Before - public void beforeTest() { - lockManager = createLockManager(); - } - - protected abstract LockManager createLockManager(); - - @Test - public void testAcquireLock() throws LockException { - boolean lockRes = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - try { - Assert.assertTrue(lockRes); - } finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } - - @Test - public void testAcquireLock_AlreadyLockedBySameOwner() throws LockException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - try { - Assert.assertTrue(lockRes1); - boolean lockRes2 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - Assert.assertFalse(lockRes2); - } finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } - - @Test(expected = LockException.class) - public void testAcquireLock_AlreadyLockedByOtherOwner() throws LockException { - String owner2 = "B"; - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - try { - Assert.assertTrue(lockRes1); - boolean lockRes2 = lockManager.acquireLock(Resource.Resource1.name(), owner2); - Assert.assertFalse(lockRes2); - } finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } - - @Test - public void testAcquireLock_LockDifferentResources() throws LockException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - try { - Assert.assertTrue(lockRes1); - boolean lockRes2 = lockManager.acquireLock(Resource.Resource2.name(), Owner.B.name()); - try { - Assert.assertTrue(lockRes2); - } finally { - lockManager.releaseLock(Resource.Resource2.name(), Owner.B.name()); - } - } finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } - - @Test(expected = LockException.class) - public void testReleaseLock_NotLockedResource() throws LockException { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - - @Test(expected = LockException.class) - public void testReleaseLock_LockedByOtherOwnerResource() throws LockException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - try { - Assert.assertTrue(lockRes1); - lockManager.releaseLock(Resource.Resource1.name(), Owner.B.name()); - } finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } - - @Test(expected = LockException.class) - public void testAcquireLock_LockExpired() throws LockException, InterruptedException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); - Assert.assertTrue(lockRes1); - Thread.sleep(1000); - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - - @Test - public void testAcquireLock_OtherLockExpired() throws LockException, InterruptedException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); - Assert.assertTrue(lockRes1); - Thread.sleep(1000); - boolean lockRes2 = lockManager.acquireLock(Resource.Resource1.name(), Owner.B.name()); - try { - Assert.assertTrue(lockRes2); - }finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.B.name()); - } - } - - @Test - public void testIsLocked_WhenLocked() throws LockException, InterruptedException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); - try { - Assert.assertTrue(lockManager.isLocked(Resource.Resource1.name())); - }finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } + protected enum Resource {Resource1, Resource2}; + protected enum Owner {A, B}; + + protected LockManager lockManager; + + @Before + public void beforeTest() { + lockManager = createLockManager(); + } + + protected abstract LockManager createLockManager(); + + @Test + public void testAcquireLock() throws LockException { + boolean lockRes = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + try { + Assert.assertTrue(lockRes); + } finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + } + + @Test + public void testAcquireLock_AlreadyLockedBySameOwner() throws LockException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + try { + Assert.assertTrue(lockRes1); + boolean lockRes2 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + Assert.assertFalse(lockRes2); + } finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + } + + @Test(expected = LockException.class) + public void testAcquireLock_AlreadyLockedByOtherOwner() throws LockException { + String owner2 = "B"; + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + try { + Assert.assertTrue(lockRes1); + boolean lockRes2 = lockManager.acquireLock(Resource.Resource1.name(), owner2); + Assert.assertFalse(lockRes2); + } finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + } + + @Test + public void testAcquireLock_LockDifferentResources() throws LockException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + try { + Assert.assertTrue(lockRes1); + boolean lockRes2 = lockManager.acquireLock(Resource.Resource2.name(), Owner.B.name()); + try { + Assert.assertTrue(lockRes2); + } finally { + lockManager.releaseLock(Resource.Resource2.name(), Owner.B.name()); + } + } finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + } + + @Test(expected = LockException.class) + public void testReleaseLock_NotLockedResource() throws LockException { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + + @Test(expected = LockException.class) + public void testReleaseLock_LockedByOtherOwnerResource() throws LockException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + try { + Assert.assertTrue(lockRes1); + lockManager.releaseLock(Resource.Resource1.name(), Owner.B.name()); + } finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + } + + @Test(expected = LockException.class) + public void testAcquireLock_LockExpired() throws LockException, InterruptedException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); + Assert.assertTrue(lockRes1); + Thread.sleep(1000); + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + + @Test + public void testAcquireLock_OtherLockExpired() throws LockException, InterruptedException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); + Assert.assertTrue(lockRes1); + Thread.sleep(1000); + boolean lockRes2 = lockManager.acquireLock(Resource.Resource1.name(), Owner.B.name()); + try { + Assert.assertTrue(lockRes2); + }finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.B.name()); + } + } + + @Test + public void testIsLocked_WhenLocked() throws LockException, InterruptedException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); + try { + Assert.assertTrue(lockManager.isLocked(Resource.Resource1.name())); + }finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + } @Test(expected = LockException.class) - public void testIsLocked_LockExpired() throws LockException, InterruptedException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); - Assert.assertTrue(lockRes1); - Assert.assertTrue(lockManager.isLocked(Resource.Resource1.name())); - Thread.sleep(1000); - try { - Assert.assertFalse(lockManager.isLocked(Resource.Resource1.name())); - }finally { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } - - @Test - public void testIsLocked_LockReleased() throws LockException, InterruptedException { - boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - Assert.assertFalse(lockManager.isLocked(Resource.Resource1.name())); - } - - @Test - public void testIsLocked_NoLock() throws LockException, InterruptedException { - Assert.assertFalse(lockManager.isLocked(Resource.Resource1.name())); - } + public void testIsLocked_LockExpired() throws LockException, InterruptedException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); + Assert.assertTrue(lockRes1); + Assert.assertTrue(lockManager.isLocked(Resource.Resource1.name())); + Thread.sleep(1000); + try { + Assert.assertFalse(lockManager.isLocked(Resource.Resource1.name())); + }finally { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + } + } + + @Test + public void testIsLocked_LockReleased() throws LockException, InterruptedException { + boolean lockRes1 = lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name(), 50); + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + Assert.assertFalse(lockManager.isLocked(Resource.Resource1.name())); + } + + @Test + public void testIsLocked_NoLock() throws LockException, InterruptedException { + Assert.assertFalse(lockManager.isLocked(Resource.Resource1.name())); + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/MySqlLockManagerBaseTests.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/MySqlLockManagerBaseTests.java index b8cd95b94..12b587bfa 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/MySqlLockManagerBaseTests.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/MySqlLockManagerBaseTests.java @@ -38,59 +38,59 @@ import java.sql.SQLException; public abstract class MySqlLockManagerBaseTests extends LockManagerBaseTests { - private static final boolean USE_REAL_DB = Boolean.getBoolean("lockmanager.tests.useRealDb"); - private static final String TABLE_LOCK_MANAGEMENT = "TEST_LOCK_MANAGEMENT"; - private static final String JDBC_URL = System.getProperty("lockmanager.tests.jdbcUrl", "jdbc:mysql://192.168.1.2/test"); - private static final String JDBC_USERNAME = System.getProperty("lockmanager.tests.jdbcUsername", "test"); - private static final String JDBC_PASSWORD = System.getProperty("lockmanager.tests.jdbcPassword", "123456"); + private static final boolean USE_REAL_DB = Boolean.getBoolean("lockmanager.tests.useRealDb"); + private static final String TABLE_LOCK_MANAGEMENT = "TEST_LOCK_MANAGEMENT"; + private static final String JDBC_URL = System.getProperty("lockmanager.tests.jdbcUrl", "jdbc:mysql://192.168.1.2/test"); + private static final String JDBC_USERNAME = System.getProperty("lockmanager.tests.jdbcUsername", "test"); + private static final String JDBC_PASSWORD = System.getProperty("lockmanager.tests.jdbcPassword", "123456"); - protected static final int CONCURRENT_TEST_WAIT_TIME = 10; // secs + protected static final int CONCURRENT_TEST_WAIT_TIME = 10; // secs - @Rule - public TestName testName = new TestName(); + @Rule + public TestName testName = new TestName(); - @Override - protected LockManager createLockManager() { - JdbcLockManager jdbcLockManager = createJdbcLockManager(USE_REAL_DB); - DefaultJdbcConnectionFactory connectionFactory = new MySqlConnectionFactory(); - connectionFactory.setJdbcURL(JDBC_URL); - connectionFactory.setJdbcUserName(JDBC_USERNAME); - connectionFactory.setJdbcPassword(JDBC_PASSWORD); - jdbcLockManager.setConnectionFactory(connectionFactory); - jdbcLockManager.setTableName(TABLE_LOCK_MANAGEMENT); - System.out.println("=> Running LockManager test [" + jdbcLockManager.getClass().getName() + "." + testName.getMethodName() + "]" + (USE_REAL_DB ? ". JDBC URL is [" + JDBC_URL + "]" : "")); - clearTestLocks(jdbcLockManager); - return jdbcLockManager; - } + @Override + protected LockManager createLockManager() { + JdbcLockManager jdbcLockManager = createJdbcLockManager(USE_REAL_DB); + DefaultJdbcConnectionFactory connectionFactory = new MySqlConnectionFactory(); + connectionFactory.setJdbcURL(JDBC_URL); + connectionFactory.setJdbcUserName(JDBC_USERNAME); + connectionFactory.setJdbcPassword(JDBC_PASSWORD); + jdbcLockManager.setConnectionFactory(connectionFactory); + jdbcLockManager.setTableName(TABLE_LOCK_MANAGEMENT); + System.out.println("=> Running LockManager test [" + jdbcLockManager.getClass().getName() + "." + testName.getMethodName() + "]" + (USE_REAL_DB ? ". JDBC URL is [" + JDBC_URL + "]" : "")); + clearTestLocks(jdbcLockManager); + return jdbcLockManager; + } - protected abstract JdbcLockManager createJdbcLockManager(boolean useRealDb); + protected abstract JdbcLockManager createJdbcLockManager(boolean useRealDb); - protected boolean setSynchronizer(Synchronizer synchronizer) { - if(!(lockManager instanceof SynchronizerReceiver)) { - System.err.println("Skipping concurrency test [" + testName.getMethodName() + "] for LockManager of type " + lockManager.getClass()); - return false; - } - ((SynchronizerReceiver)lockManager).setSynchronizer(synchronizer); - return true; - } + protected boolean setSynchronizer(Synchronizer synchronizer) { + if(!(lockManager instanceof SynchronizerReceiver)) { + System.err.println("Skipping concurrency test [" + testName.getMethodName() + "] for LockManager of type " + lockManager.getClass()); + return false; + } + ((SynchronizerReceiver)lockManager).setSynchronizer(synchronizer); + return true; + } - private static final String SQL_DELETE_LOCK_RECORD = String.format("DELETE FROM %s WHERE RESOURCE_ID=?", TABLE_LOCK_MANAGEMENT); - private void clearTestLocks(JdbcLockManager jdbcLockManager) { - Connection connection = jdbcLockManager.openDbConnection(); - if(connection == null) { - return; - } - try { - for(Resource resource: Resource.values()) { - try(PreparedStatement statement = connection.prepareStatement(SQL_DELETE_LOCK_RECORD)) { - statement.setString(1, resource.name()); - statement.executeUpdate(); - } - } - } catch(SQLException e) { - throw new RuntimeException("Cannot clear test resources in table", e); - } finally { - jdbcLockManager.closeDbConnection(connection); - } - } + private static final String SQL_DELETE_LOCK_RECORD = String.format("DELETE FROM %s WHERE RESOURCE_ID=?", TABLE_LOCK_MANAGEMENT); + private void clearTestLocks(JdbcLockManager jdbcLockManager) { + Connection connection = jdbcLockManager.openDbConnection(); + if(connection == null) { + return; + } + try { + for(Resource resource: Resource.values()) { + try(PreparedStatement statement = connection.prepareStatement(SQL_DELETE_LOCK_RECORD)) { + statement.setString(1, resource.name()); + statement.executeUpdate(); + } + } + } catch(SQLException e) { + throw new RuntimeException("Cannot clear test resources in table", e); + } finally { + jdbcLockManager.closeDbConnection(connection); + } + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManagerMock.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManagerMock.java index f9c072e6c..076e23343 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManagerMock.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/MySqlLockManagerMock.java @@ -36,100 +36,100 @@ import org.onap.appc.lockmanager.impl.sql.optimistic.MySqlLockManager; class MySqlLockManagerMock extends MySqlLockManager implements SynchronizerReceiver { - private final ConcurrentMap<String, LockRecord> locks = new ConcurrentHashMap<>(); - private boolean useReal; - private Synchronizer synchronizer; + private final ConcurrentMap<String, LockRecord> locks = new ConcurrentHashMap<>(); + private boolean useReal; + private Synchronizer synchronizer; - MySqlLockManagerMock(boolean useReal) { - this.useReal = useReal; - } + MySqlLockManagerMock(boolean useReal) { + this.useReal = useReal; + } - @Override - public void setSynchronizer(Synchronizer synchronizer) { - this.synchronizer = synchronizer; - } + @Override + public void setSynchronizer(Synchronizer synchronizer) { + this.synchronizer = synchronizer; + } - @Override - protected Connection openDbConnection() { - if(useReal) { - return super.openDbConnection(); - } - return null; - } + @Override + protected Connection openDbConnection() { + if(useReal) { + return super.openDbConnection(); + } + return null; + } - @Override - protected void closeDbConnection(Connection connection) { - if(useReal) { - super.closeDbConnection(connection); - } - } + @Override + protected void closeDbConnection(Connection connection) { + if(useReal) { + super.closeDbConnection(connection); + } + } - @Override - protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { - LockRecord res; - if(useReal) { - res = super.loadLockRecord(connection, resource); - } else { - res = locks.get(resource); - } - if(synchronizer != null) { - synchronizer.postLoadLockRecord(resource, (res == null) ? null : res.getOwner()); - } - return res; - } + @Override + protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { + LockRecord res; + if(useReal) { + res = super.loadLockRecord(connection, resource); + } else { + res = locks.get(resource); + } + if(synchronizer != null) { + synchronizer.postLoadLockRecord(resource, (res == null) ? null : res.getOwner()); + } + return res; + } - @Override - protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { - if(synchronizer != null) { - synchronizer.preAddLockRecord(resource, owner); - } - try { - if(useReal) { - super.addLockRecord(connection, resource, owner, timeout); - return; - } - LockRecord lockRecord = new LockRecord(resource); - lockRecord.setOwner(owner); - lockRecord.setUpdated(System.currentTimeMillis()); - lockRecord.setTimeout(timeout); - lockRecord.setVer(1); - LockRecord prevLockRecord = locks.putIfAbsent(resource, lockRecord); - if(prevLockRecord != null) { - // simulate unique constraint violation - throw new SQLException("Duplicate PK exception", "23000", 1062); - } - } finally { - if(synchronizer != null) { - synchronizer.postAddLockRecord(resource, owner); - } - } - } + @Override + protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { + if(synchronizer != null) { + synchronizer.preAddLockRecord(resource, owner); + } + try { + if(useReal) { + super.addLockRecord(connection, resource, owner, timeout); + return; + } + LockRecord lockRecord = new LockRecord(resource); + lockRecord.setOwner(owner); + lockRecord.setUpdated(System.currentTimeMillis()); + lockRecord.setTimeout(timeout); + lockRecord.setVer(1); + LockRecord prevLockRecord = locks.putIfAbsent(resource, lockRecord); + if(prevLockRecord != null) { + // simulate unique constraint violation + throw new SQLException("Duplicate PK exception", "23000", 1062); + } + } finally { + if(synchronizer != null) { + synchronizer.postAddLockRecord(resource, owner); + } + } + } - @Override - protected boolean updateLockRecord(Connection connection, String resource, String owner, long timeout, long ver) throws SQLException { - if(synchronizer != null) { - synchronizer.preUpdateLockRecord(resource, owner); - } - try { - if(useReal) { - return super.updateLockRecord(connection, resource, owner, timeout, ver); - } - LockRecord lockRecord = loadLockRecord(connection, resource); - synchronized(lockRecord) { - // should be atomic operation - if(ver != lockRecord.getVer()) { - return false; - } - lockRecord.setOwner(owner); - lockRecord.setUpdated(System.currentTimeMillis()); - lockRecord.setTimeout(timeout); - lockRecord.setVer(ver + 1); - } - return true; - } finally { - if(synchronizer != null) { - synchronizer.postUpdateLockRecord(resource, owner); - } - } - } + @Override + protected boolean updateLockRecord(Connection connection, String resource, String owner, long timeout, long ver) throws SQLException { + if(synchronizer != null) { + synchronizer.preUpdateLockRecord(resource, owner); + } + try { + if(useReal) { + return super.updateLockRecord(connection, resource, owner, timeout, ver); + } + LockRecord lockRecord = loadLockRecord(connection, resource); + synchronized(lockRecord) { + // should be atomic operation + if(ver != lockRecord.getVer()) { + return false; + } + lockRecord.setOwner(owner); + lockRecord.setUpdated(System.currentTimeMillis()); + lockRecord.setTimeout(timeout); + lockRecord.setVer(ver + 1); + } + return true; + } finally { + if(synchronizer != null) { + synchronizer.postUpdateLockRecord(resource, owner); + } + } + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/TestMySqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/TestMySqlLockManager.java index d652c7523..1ab1e4ef9 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/TestMySqlLockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/optimistic/TestMySqlLockManager.java @@ -35,196 +35,196 @@ import java.util.concurrent.*; public class TestMySqlLockManager extends MySqlLockManagerBaseTests { - @Override - protected JdbcLockManager createJdbcLockManager(boolean useReal) { - return new MySqlLockManagerMock(useReal); - } - - @Test - public void testConcurrentLockDifferentOwners() throws LockException, InterruptedException, ExecutionException, TimeoutException { - - final int participantsNo = 2; - Synchronizer synchronizer = new Synchronizer(participantsNo) { - - private boolean wait = true; - - @Override - public void preAddLockRecord(String resource, String owner) { - if(Owner.A.name().equals(owner)) { - synchronized(this) { - if(wait) { - waitOn(this); - } - } - } - } - - @Override - public void postAddLockRecord(String resource, String owner) { - if(!Owner.A.name().equals(owner)) { - synchronized(this) { - notifyAll(); - wait = false; - } - } - } - - @Override - public void preUpdateLockRecord(String resource, String owner) { - preAddLockRecord(resource, owner); - } - - @Override - public void postUpdateLockRecord(String resource, String owner) { - postAddLockRecord(resource, owner); - } - }; - if(!setSynchronizer(synchronizer)) { - return; - } - ExecutorService executor = Executors.newFixedThreadPool(participantsNo); - // acquireLock by owner A should fail as it will wait for acquireLock by owner B - Future<Boolean> future1 = executor.submit(new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - try { - lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - return false; - } catch(LockException e) { - // this call should fail as Synchronizer delays its lock to make sure the second call locks the resource first - Assert.assertEquals("Cannot lock resource [" + Resource.Resource1.name() + "] for [" + Owner.A.name() + "]: already locked by [" + Owner.B.name() + "]", e.getMessage()); - return true; - } - } - }); - try { - // acquireLock by owner B should success - Future<Boolean> future2 = executor.submit(new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - // this call should success as Synchronizer delays the above lock to make sure this call success to lock the resource - return lockManager.acquireLock(Resource.Resource1.name(), Owner.B.name()); - } - }); - try { - Assert.assertTrue(future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS)); - Assert.assertTrue(future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS)); - } finally { - future2.cancel(true); - } - } finally { - future1.cancel(true); - } - } - - @Test - public void testConcurrentLockSameOwner() throws LockException, InterruptedException, ExecutionException, TimeoutException { - final int participantsNo = 2; - Synchronizer synchronizer = new Synchronizer(participantsNo) { - - private boolean wait = true; - - @Override - public void preAddLockRecord(String resource, String owner) { - synchronized(this) { - if(wait) { - wait = false; - waitOn(this); - } - } - } - - @Override - public void postAddLockRecord(String resource, String owner) { - synchronized(this) { - notifyAll(); - } - } - }; - if(!setSynchronizer(synchronizer)) { - return; - } - ExecutorService executor = Executors.newFixedThreadPool(participantsNo); - // one acquireLock should return true and the other should return false - Callable<Boolean> callable = new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - return lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - } - }; - Future<Boolean> future1 = executor.submit(callable); - try { - Future<Boolean> future2 = executor.submit(callable); - try { - boolean future1Res = future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); - boolean future2Res = future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); - // one of the lock requests should return true, the other one false as lock is requested simultaneously from 2 threads by same owner - Assert.assertNotEquals(future1Res, future2Res); - } finally { - future2.cancel(true); - } - } finally { - future1.cancel(true); - } - } - - @Test - public void testConcurrentUnlockSameOwner() throws LockException, InterruptedException, ExecutionException, TimeoutException { - lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); - final int participantsNo = 2; - Synchronizer synchronizer = new Synchronizer(participantsNo) { - - private boolean wait = true; - - @Override - public void preUpdateLockRecord(String resource, String owner) { - synchronized(this) { - // make sure second call updates the LockRecord first - if(wait) { - wait = false; - waitOn(this); - } - } - } - - @Override - public void postUpdateLockRecord(String resource, String owner) { - synchronized(this) { - notifyAll(); - } - } - }; - if(!setSynchronizer(synchronizer)) { - return; - } - ExecutorService executor = Executors.newFixedThreadPool(participantsNo); - Callable<Boolean> callable = new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - try { - lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - // one of the unlock calls should success - return true; - } catch(LockException e) { - // one of the unlock calls should throw the LockException as the resource should already be unlocked by other call - Assert.assertEquals("Error unlocking resource [" + Resource.Resource1.name() + "]: resource is not locked", e.getMessage()); - return false; - } - } - }; - Future<Boolean> future1 = executor.submit(callable); - try { - Future<Boolean> future2 = executor.submit(callable); - try { - boolean future1Res = future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); - boolean future2Res = future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); - // one of the unlock calls should return true, the other one false as unlock is requested simultaneously from 2 threads by same owner - Assert.assertNotEquals(future1Res, future2Res); - } finally { - future2.cancel(true); - } - } finally { - future1.cancel(true); - } - } + @Override + protected JdbcLockManager createJdbcLockManager(boolean useReal) { + return new MySqlLockManagerMock(useReal); + } + + @Test + public void testConcurrentLockDifferentOwners() throws LockException, InterruptedException, ExecutionException, TimeoutException { + + final int participantsNo = 2; + Synchronizer synchronizer = new Synchronizer(participantsNo) { + + private boolean wait = true; + + @Override + public void preAddLockRecord(String resource, String owner) { + if(Owner.A.name().equals(owner)) { + synchronized(this) { + if(wait) { + waitOn(this); + } + } + } + } + + @Override + public void postAddLockRecord(String resource, String owner) { + if(!Owner.A.name().equals(owner)) { + synchronized(this) { + notifyAll(); + wait = false; + } + } + } + + @Override + public void preUpdateLockRecord(String resource, String owner) { + preAddLockRecord(resource, owner); + } + + @Override + public void postUpdateLockRecord(String resource, String owner) { + postAddLockRecord(resource, owner); + } + }; + if(!setSynchronizer(synchronizer)) { + return; + } + ExecutorService executor = Executors.newFixedThreadPool(participantsNo); + // acquireLock by owner A should fail as it will wait for acquireLock by owner B + Future<Boolean> future1 = executor.submit(new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + try { + lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + return false; + } catch(LockException e) { + // this call should fail as Synchronizer delays its lock to make sure the second call locks the resource first + Assert.assertEquals("VNF : [" + Resource.Resource1.name() + "] is locked by request id : [" + Owner.B.name() + "]", e.getMessage()); + return true; + } + } + }); + try { + // acquireLock by owner B should success + Future<Boolean> future2 = executor.submit(new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + // this call should success as Synchronizer delays the above lock to make sure this call success to lock the resource + return lockManager.acquireLock(Resource.Resource1.name(), Owner.B.name()); + } + }); + try { + Assert.assertTrue(future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS)); + Assert.assertTrue(future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS)); + } finally { + future2.cancel(true); + } + } finally { + future1.cancel(true); + } + } + + @Test + public void testConcurrentLockSameOwner() throws LockException, InterruptedException, ExecutionException, TimeoutException { + final int participantsNo = 2; + Synchronizer synchronizer = new Synchronizer(participantsNo) { + + private boolean wait = true; + + @Override + public void preAddLockRecord(String resource, String owner) { + synchronized(this) { + if(wait) { + wait = false; + waitOn(this); + } + } + } + + @Override + public void postAddLockRecord(String resource, String owner) { + synchronized(this) { + notifyAll(); + } + } + }; + if(!setSynchronizer(synchronizer)) { + return; + } + ExecutorService executor = Executors.newFixedThreadPool(participantsNo); + // one acquireLock should return true and the other should return false + Callable<Boolean> callable = new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + return lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + } + }; + Future<Boolean> future1 = executor.submit(callable); + try { + Future<Boolean> future2 = executor.submit(callable); + try { + boolean future1Res = future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); + boolean future2Res = future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); + // one of the lock requests should return true, the other one false as lock is requested simultaneously from 2 threads by same owner + Assert.assertNotEquals(future1Res, future2Res); + } finally { + future2.cancel(true); + } + } finally { + future1.cancel(true); + } + } + + @Test + public void testConcurrentUnlockSameOwner() throws LockException, InterruptedException, ExecutionException, TimeoutException { + lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); + final int participantsNo = 2; + Synchronizer synchronizer = new Synchronizer(participantsNo) { + + private boolean wait = true; + + @Override + public void preUpdateLockRecord(String resource, String owner) { + synchronized(this) { + // make sure second call updates the LockRecord first + if(wait) { + wait = false; + waitOn(this); + } + } + } + + @Override + public void postUpdateLockRecord(String resource, String owner) { + synchronized(this) { + notifyAll(); + } + } + }; + if(!setSynchronizer(synchronizer)) { + return; + } + ExecutorService executor = Executors.newFixedThreadPool(participantsNo); + Callable<Boolean> callable = new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + try { + lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); + // one of the unlock calls should success + return true; + } catch(LockException e) { + // one of the unlock calls should throw the LockException as the resource should already be unlocked by other call + Assert.assertEquals("Error unlocking resource [" + Resource.Resource1.name() + "]: resource is not locked", e.getMessage()); + return false; + } + } + }; + Future<Boolean> future1 = executor.submit(callable); + try { + Future<Boolean> future2 = executor.submit(callable); + try { + boolean future1Res = future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); + boolean future2Res = future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS); + // one of the unlock calls should return true, the other one false as unlock is requested simultaneously from 2 threads by same owner + Assert.assertNotEquals(future1Res, future2Res); + } finally { + future2.cancel(true); + } + } finally { + future1.cancel(true); + } + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManagerMock.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManagerMock.java index a4bbd3406..51b1c3111 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManagerMock.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/MySqlLockManagerMock.java @@ -40,114 +40,114 @@ import org.onap.appc.lockmanager.impl.sql.pessimistic.MySqlLockManager; class MySqlLockManagerMock extends MySqlLockManager implements SynchronizerReceiver { - private final Map<String, LockRecord> locks = new HashMap<>(); - private final Lock lock = new ReentrantLock(); - private boolean useReal; - private Synchronizer synchronizer; + private final Map<String, LockRecord> locks = new HashMap<>(); + private final Lock lock = new ReentrantLock(); + private boolean useReal; + private Synchronizer synchronizer; - MySqlLockManagerMock(boolean useReal) { - this.useReal = useReal; - } + MySqlLockManagerMock(boolean useReal) { + this.useReal = useReal; + } - @Override - public void setSynchronizer(Synchronizer synchronizer) { - this.synchronizer = synchronizer; - } + @Override + public void setSynchronizer(Synchronizer synchronizer) { + this.synchronizer = synchronizer; + } - @Override - protected Connection openDbConnection() { - if(useReal) { - return super.openDbConnection(); - } - return null; - } + @Override + protected Connection openDbConnection() { + if(useReal) { + return super.openDbConnection(); + } + return null; + } - @Override - protected void closeDbConnection(Connection connection) { - if(useReal) { - super.closeDbConnection(connection); - } - } + @Override + protected void closeDbConnection(Connection connection) { + if(useReal) { + super.closeDbConnection(connection); + } + } - @Override - protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { - LockRecord res; - if(useReal) { - res = super.loadLockRecord(connection, resource); - } else { - res = locks.get(resource); - } - if(synchronizer != null) { - synchronizer.postLoadLockRecord(resource, (res == null) ? null : res.getOwner()); - } - return res; - } + @Override + protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException { + LockRecord res; + if(useReal) { + res = super.loadLockRecord(connection, resource); + } else { + res = locks.get(resource); + } + if(synchronizer != null) { + synchronizer.postLoadLockRecord(resource, (res == null) ? null : res.getOwner()); + } + return res; + } - @Override - protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { - if(synchronizer != null) { - synchronizer.preAddLockRecord(resource, owner); - } - try { - if(useReal) { - super.addLockRecord(connection, resource, owner, timeout); - return; - } - LockRecord lockRecord = new LockRecord(resource); - lockRecord.setOwner(owner); - lockRecord.setUpdated(System.currentTimeMillis()); - lockRecord.setTimeout(timeout); - locks.put(resource, lockRecord); - } finally { - if(synchronizer != null) { - synchronizer.postAddLockRecord(resource, owner); - } - } - } + @Override + protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { + if(synchronizer != null) { + synchronizer.preAddLockRecord(resource, owner); + } + try { + if(useReal) { + super.addLockRecord(connection, resource, owner, timeout); + return; + } + LockRecord lockRecord = new LockRecord(resource); + lockRecord.setOwner(owner); + lockRecord.setUpdated(System.currentTimeMillis()); + lockRecord.setTimeout(timeout); + locks.put(resource, lockRecord); + } finally { + if(synchronizer != null) { + synchronizer.postAddLockRecord(resource, owner); + } + } + } - @Override - protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { - if(synchronizer != null) { - synchronizer.preUpdateLockRecord(resource, owner); - } - try { - if(useReal) { - super.updateLockRecord(connection, resource, owner, timeout); - return; - } - LockRecord lockRecord = loadLockRecord(connection, resource); - lockRecord.setOwner(owner); - lockRecord.setUpdated(System.currentTimeMillis()); - lockRecord.setTimeout(timeout); - locks.put(resource, lockRecord); - } finally { - if(synchronizer != null) { - synchronizer.postUpdateLockRecord(resource, owner); - } - } - } + @Override + protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException { + if(synchronizer != null) { + synchronizer.preUpdateLockRecord(resource, owner); + } + try { + if(useReal) { + super.updateLockRecord(connection, resource, owner, timeout); + return; + } + LockRecord lockRecord = loadLockRecord(connection, resource); + lockRecord.setOwner(owner); + lockRecord.setUpdated(System.currentTimeMillis()); + lockRecord.setTimeout(timeout); + locks.put(resource, lockRecord); + } finally { + if(synchronizer != null) { + synchronizer.postUpdateLockRecord(resource, owner); + } + } + } - @Override - protected void enterCriticalSection(Connection connection, String resource) { - if(useReal) { - super.enterCriticalSection(connection, resource); - return; - } - try { - if(!lock.tryLock(criticalSectionWaitTimeoutSecs, TimeUnit.SECONDS)) { + @Override + protected void enterCriticalSection(Connection connection, String resource) { + if(useReal) { + super.enterCriticalSection(connection, resource); + return; + } + try { + if(!lock.tryLock(criticalSectionWaitTimeoutSecs, TimeUnit.SECONDS)) { throw new LockRuntimeException("Cannot obtain critical section lock for resource [" + resource + "]."); - } - } catch(InterruptedException e) { - throw new LockRuntimeException("Cannot obtain critical section lock.", e); - } - } + } + } catch(InterruptedException e) { + throw new LockRuntimeException("Cannot obtain critical section lock.", e); + } + } - @Override - protected void leaveCriticalSection(Connection connection, String resource) { - if(useReal) { - super.leaveCriticalSection(connection, resource); - return; - } - lock.unlock(); - } + @Override + protected void leaveCriticalSection(Connection connection, String resource) { + if(useReal) { + super.leaveCriticalSection(connection, resource); + return; + } + lock.unlock(); + } } diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/TestMySqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/TestMySqlLockManager.java index c54cfc81a..b13207d6d 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/TestMySqlLockManager.java +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/onap/appc/lockmanager/impl/sql/pessimistic/TestMySqlLockManager.java @@ -39,13 +39,13 @@ public class TestMySqlLockManager extends MySqlLockManagerBaseTests { private static int CRITICAL_SECTION_WAIT_TIMEOUT = 1; // in secs - @Override - protected JdbcLockManager createJdbcLockManager(boolean useReal) { - return new MySqlLockManagerMock(useReal); - } + @Override + protected JdbcLockManager createJdbcLockManager(boolean useReal) { + return new MySqlLockManagerMock(useReal); + } - @Test - public void testConcurrentLock() throws LockException, InterruptedException, ExecutionException, TimeoutException { + @Test + public void testConcurrentLock() throws LockException, InterruptedException, ExecutionException, TimeoutException { try { callConcurrentTest(new Callable<Boolean>() { @Override @@ -61,10 +61,10 @@ public class TestMySqlLockManager extends MySqlLockManagerBaseTests { }); } finally { lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name()); - } - } + } + } - @Test + @Test public void testConcurrentUnlock() throws LockException, InterruptedException, ExecutionException, TimeoutException { lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()); callConcurrentTest(new Callable<Boolean>() { diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/pom.xml b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/pom.xml index 7c6ae9970..b9d259b6a 100644 --- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/pom.xml @@ -1,5 +1,30 @@ <?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"> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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>appc-dispatcher-common</artifactId> @@ -7,11 +32,13 @@ <version>1.3.0-SNAPSHOT</version> </parent> <artifactId>lock-manager-lib</artifactId> + <name>APPC Lock Manager Lib</name> <packaging>pom</packaging> + <modules> <module>lock-manager-api</module> <module>lock-manager-impl</module> <module>lock-manager-features</module> </modules> -</project>
\ No newline at end of file +</project> diff --git a/appc-dispatcher/appc-dispatcher-common/pom.xml b/appc-dispatcher/appc-dispatcher-common/pom.xml index 8afae5e4a..444ac9266 100644 --- a/appc-dispatcher/appc-dispatcher-common/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/pom.xml @@ -1,15 +1,42 @@ <?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.onap.appc</groupId> - <artifactId>appc-dispatcher</artifactId> - <version>1.3.0-SNAPSHOT</version> - </parent> - <artifactId>appc-dispatcher-common</artifactId> - <packaging>pom</packaging> - <name>APPC Dispatcher Common</name> - <description>APPC Dispatcher Common</description> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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.onap.appc</groupId> + <artifactId>appc-dispatcher</artifactId> + <version>1.3.0-SNAPSHOT</version> + </parent> + + <artifactId>appc-dispatcher-common</artifactId> + <packaging>pom</packaging> + <name>APPC Dispatcher Common</name> + <description>APPC Dispatcher Common</description> + <!-- ================================================================================== --> <!-- The modules we build --> @@ -23,4 +50,4 @@ <module>transaction-recorder</module> </modules> -</project>
\ No newline at end of file +</project> diff --git a/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/pom.xml b/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/pom.xml index 8f17c3ff2..d5332bd5a 100644 --- a/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/pom.xml @@ -1,37 +1,71 @@ -<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.onap.appc</groupId> - <artifactId>appc-dispatcher-common</artifactId> - <version>1.3.0-SNAPSHOT</version> - </parent> - <artifactId>appc-ranking-framework-lib</artifactId> - <packaging>bundle</packaging> +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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 - <dependencies> - <dependency> - <groupId>com.att.eelf</groupId> - <artifactId>eelf-core</artifactId> - </dependency> - </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <configuration> - <instructions> - <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> - <Bundle-Version>${project.version}</Bundle-Version> - <Export-Package>org.onap.appc.rankingframework</Export-Package> - <Private-Package>org.onap.appc.rankingframework.impl</Private-Package> - <Embed-Dependency>eelf-core,logback-core,logback-classic;scope=compile|runtime;inline=false</Embed-Dependency> - <Embed-Transitive>true</Embed-Transitive> - <Import-Package>!groovy.lang,!javax.jms,!org.codehaus.commons.compiler,!org.codehaus.groovy.*,!org.codehaus.janino,!com.ibm.icu.*,!com.sun.faces.*,!org.apache.log,*</Import-Package> - </instructions> - </configuration> - </plugin> - </plugins> - </build> + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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.onap.appc</groupId> + <artifactId>appc-dispatcher-common</artifactId> + <version>1.3.0-SNAPSHOT</version> + </parent> + + <artifactId>appc-ranking-framework-lib</artifactId> + <name>APPC Ranking Framework Lib</name> + <packaging>bundle</packaging> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>com.att.eelf</groupId> + <artifactId>eelf-core</artifactId> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <configuration> + <instructions> + <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> + <Bundle-Version>${project.version}</Bundle-Version> + <Export-Package>org.onap.appc.rankingframework</Export-Package> + <Private-Package>org.onap.appc.rankingframework.impl</Private-Package> + <Embed-Dependency>eelf-core,logback-core,logback-classic;scope=compile|runtime;inline=false + </Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + <Import-Package> + !groovy.lang,!javax.jms,!org.codehaus.commons.compiler,!org.codehaus.groovy.*,!org.codehaus.janino,!com.ibm.icu.*,!com.sun.faces.*,!org.apache.log,* + </Import-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> </project> diff --git a/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/src/main/java/org/onap/appc/rankingframework/impl/BacktraceStrategy.java b/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/src/main/java/org/onap/appc/rankingframework/impl/BacktraceStrategy.java index 6523fef65..5da4a8e2b 100644 --- a/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/src/main/java/org/onap/appc/rankingframework/impl/BacktraceStrategy.java +++ b/appc-dispatcher/appc-dispatcher-common/ranking-framework-lib/src/main/java/org/onap/appc/rankingframework/impl/BacktraceStrategy.java @@ -34,7 +34,7 @@ import com.att.eelf.configuration.EELFManager; class BacktraceStrategy implements Strategy { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(BacktraceStrategy.class); + private final EELFLogger logger = EELFManager.getInstance().getLogger(BacktraceStrategy.class); @Override public <R> R resolve(CompositeNode<R> rootNode, List<String> rankedNames, RankedAttributesContext context) { diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/pom.xml b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/pom.xml index 3e9a24bfa..24148cb81 100644 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/pom.xml +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/pom.xml @@ -1,5 +1,29 @@ <?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"> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Copyright (C) 2017 Amdocs + ============================================================================= + 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. + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + ============LICENSE_END========================================================= + --> +<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"> <parent> <artifactId>appc-dispatcher-common</artifactId> <groupId>org.onap.appc</groupId> @@ -9,8 +33,12 @@ <artifactId>transaction-recorder</artifactId> <packaging>bundle</packaging> + <name>APPC Transaction Recorder</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> - <name>transaction-recorder</name> <dependencies> <dependency> <groupId>org.onap.appc</groupId> @@ -22,12 +50,21 @@ <artifactId>appc-data-access-lib</artifactId> <version>${project.version}</version> </dependency> - </dependencies> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>domain-model-lib</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>appc-test-dependencies</artifactId> + <version>${project.version}</version> + <scope>test</scope> + <type>pom</type> + </dependency> + </dependencies> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> <build> <plugins> <plugin> @@ -37,16 +74,18 @@ <instructions> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-Version>${project.version}</Bundle-Version> - <Embed-Dependency>appc-common,eelf-core,logback-core,logback-classic,appc-data-access-lib;scope=compile|runtime;inline=false</Embed-Dependency> <Embed-Transitive>true</Embed-Transitive> <Export-Service>org.onap.appc.transactionrecorder.TransactionRecorder</Export-Service> - <Import-Package>!javax.*,!groovy.lang,!org.apache.log,!org.apache.log4j.*,!org.codehaus.jackson.*,!org.codehaus.jackson.map.*,!org.codehaus.commons.compiler,!org.codehaus.groovy.*,!org.apache.commons.lang3,!org.codehaus.janino,!org.jasypt.*,!com.ibm.icu.*,!com.sun.faces.*,*;resolution:=optional</Import-Package> - <Export-Package>org.onap.appc.transactionrecorder,org.onap.appc.transactionrecorder.objects</Export-Package> + <Import-Package> + org.onap.appc.domainmodel.lcm,org.onap.ccsdk.sli.resource.dblib,org.onap.appc.dao.util,*;resolution:=optional + </Import-Package> + <Export-Package> + org.onap.appc.transactionrecorder,org.onap.appc.transactionrecorder.objects + </Export-Package> </instructions> </configuration> </plugin> </plugins> </build> - -</project>
\ No newline at end of file +</project> diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java index 8f3c51129..8969b5842 100644 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java @@ -25,13 +25,77 @@ package org.onap.appc.transactionrecorder; -import org.onap.appc.transactionrecorder.objects.TransactionRecord; +import org.onap.appc.domainmodel.lcm.RequestStatus; +import org.onap.appc.exceptions.APPCException; +import org.onap.appc.domainmodel.lcm.TransactionRecord; +import org.onap.appc.transactionrecorder.objects.TransactionConstants; +import java.util.List; +import java.util.Map; +/** + * Interface to persist and query LCM requests + */ public interface TransactionRecorder { /** * Stores transaction record to appc database by calling APPC Dao layer. * @param record Transaction record data. */ - void store(TransactionRecord record); + void store(TransactionRecord record) throws APPCException; + + /** + * This method is called when a particular row in transactions needs to be updated + * @param key This is TransactionId which uniquely identifies the record. + * @param updateColumns Map containing names of updated columns and their values. + * @throws APPCException + */ + void update(String key, Map<TransactionConstants.TRANSACTION_ATTRIBUTES, String> updateColumns) throws APPCException; + + /** + * Marks all records in Transactions table in non-terminal state as ABORTED. This method is to be called during + * APPC startup. + * + * @param appcInstanceId + */ + void markTransactionsAborted(String appcInstanceId); + + /** + * Fetch list of Transactions which are in non-terminal state i.e. ACCEPTED or RECEIVED for particular TargetId. + * @param record Transactions object from which TargetId and StartTime is extracted to fetch list of in progress + * requests which APPC received before the current request. + * @return List of Transactions in non terminal state. + * @throws APPCException + */ + List<TransactionRecord> getInProgressRequests(TransactionRecord record) throws APPCException; + + /** + * Checks whether the incoming request is duplicate. + * @param record Transaction object from which RequestId, SubRequestId, OriginatorId is extracted to check duplicate request. + * @return + * @throws APPCException + */ + Boolean isTransactionDuplicate(TransactionRecord record) throws APPCException; + + /** + * Retrieves {@link RequestStatus} from transaction table based on the passed parameters. + * @param requestId: RequestId of the request to search (Required) + * @param subrequestId: Sub-requestId (Optional) + * @param originatorId: Originator Id who sent the request(Optional) + * @param vnfId: VNFId to search (Required) + * @return list of RequestStatus'es + */ + List<RequestStatus> getRecords(String requestId, String subrequestId, String originatorId, String vnfId) + throws APPCException; + + /** + * Count of all requests which are currently in non-terminal state. + * @return Count of all request in state RECEIVED and ACCEPTED. + */ + Integer getInProgressRequestsCount() throws APPCException; + + /** + * + * @param appcInstanceId + */ + void setAppcInstanceId(String appcInstanceId); } diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java index 89e0d9281..ac3e9d819 100644 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java @@ -24,58 +24,357 @@ package org.onap.appc.transactionrecorder.impl; -import org.onap.appc.dao.util.DBUtils; +import org.apache.commons.lang.StringUtils; +import org.onap.appc.domainmodel.lcm.Flags; +import org.onap.appc.domainmodel.lcm.RequestStatus; +import org.onap.appc.domainmodel.lcm.VNFOperation; +import org.onap.appc.exceptions.APPCException; import org.onap.appc.transactionrecorder.TransactionRecorder; -import org.onap.appc.transactionrecorder.objects.TransactionRecord; +import org.onap.appc.domainmodel.lcm.TransactionRecord; +import org.onap.appc.transactionrecorder.objects.TransactionConstants; +import org.onap.ccsdk.sli.core.dblib.DbLibService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.sql.Connection; -import java.sql.PreparedStatement; +import javax.sql.rowset.CachedRowSet; import java.sql.SQLException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import static org.onap.appc.transactionrecorder.objects.TransactionConstants.TRANSACTION_ATTRIBUTES.*; +import static org.onap.appc.transactionrecorder.objects.TransactionConstants.*; public class TransactionRecorderImpl implements TransactionRecorder { - private static String APPCCTL_SCHEMA = "appcctl"; + private final String SCHEMA = "sdnctl"; + + private String appcInstanceId; + + private DbLibService dbLibService; + + public void setDbLibService(DbLibService dbLibService) { + this.dbLibService = dbLibService; + } private static final Logger logger = LoggerFactory.getLogger(TransactionRecorderImpl.class); /** * Stores transaction record to appc database by calling APPC Dao layer. + * * @param record Transaction record data. */ @Override - public void store(TransactionRecord record) { - Connection connection = null; - PreparedStatement stmt = null; - String queryString = "INSERT INTO transactions VALUES (?,?,?,?,?,?,?,?,?,?)"; + public void store(TransactionRecord record) throws APPCException { + if (logger.isTraceEnabled()) { + logger.trace("Transaction data insertion into DB"); + } + final String STORE_DATE_QUERY = TransactionConstants.INSERT_INTO + TransactionConstants.TRANSACTIONS + + "(" + TRANSACTION_ID.getColumnName() + TransactionConstants.COMMA + + ORIGIN_TIMESTAMP.getColumnName() + TransactionConstants.COMMA + + REQUEST_ID.getColumnName() + TransactionConstants.COMMA + + SUBREQUEST_ID.getColumnName() + TransactionConstants.COMMA + + ORIGINATOR_ID.getColumnName() + TransactionConstants.COMMA + + START_TIME.getColumnName() + TransactionConstants.COMMA + + END_TIME.getColumnName() + TransactionConstants.COMMA + + TARGET_ID.getColumnName() + TransactionConstants.COMMA + + TARGET_TYPE.getColumnName() + TransactionConstants.COMMA + + OPERATION.getColumnName() + TransactionConstants.COMMA + + RESULT_CODE.getColumnName() + TransactionConstants.COMMA + + DESCRIPTION.getColumnName() + TransactionConstants.COMMA + + STATE.getColumnName() + TransactionConstants.COMMA + + SERVICE_INSTANCE_ID + TransactionConstants.COMMA + + VNFC_NAME + TransactionConstants.COMMA + + VSERVER_ID + TransactionConstants.COMMA + + VF_MODULE_ID + TransactionConstants.COMMA + + MODE + ") " + + "values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + try { + dbLibService.writeData(STORE_DATE_QUERY, prepareArguments(record), SCHEMA); + } catch (SQLException e) { + logger.error("Error on storing record " + record.toString(), e); + throw new APPCException(ERROR_ACCESSING_DATABASE, e); + } + if (logger.isTraceEnabled()) { + logger.trace("Transaction Data Inserted Successfully into DB"); + } + } + + @Override + public void update(String key, Map<TransactionConstants.TRANSACTION_ATTRIBUTES, String> updateColumns) throws + APPCException { + ArrayList<String> values = new ArrayList<>(); + + StringBuilder queryBuilder = new StringBuilder("UPDATE TRANSACTIONS SET "); + for (Map.Entry<TransactionConstants.TRANSACTION_ATTRIBUTES, String> entry : updateColumns.entrySet()) { + queryBuilder.append(entry.getKey().getColumnName() + " = ? ,"); + values.add(entry.getValue()); + } + queryBuilder.deleteCharAt(queryBuilder.lastIndexOf(",")); + queryBuilder.append(WHERE + TRANSACTION_ID.getColumnName() + " = ?"); + values.add(appcInstanceId + "~" + key); + + String query = queryBuilder.toString(); + try { + dbLibService.writeData(query, values, SCHEMA); + } catch (SQLException e) { + logger.error("Error in updating records " + e); + throw new APPCException(ERROR_ACCESSING_DATABASE, e); + } + if (logger.isTraceEnabled()) { + logger.trace("Transaction data updated successfully"); + } + + } + + @Override + public void markTransactionsAborted(String appcInstanceId) { + if (logger.isTraceEnabled()) { + logger.trace("marking in progress transactions to aborted"); + } + final String updateQuery = + "UPDATE " + TransactionConstants.TRANSACTIONS + + " SET " + STATE.getColumnName() + " = '" + RequestStatus.ABORTED.name() + "'," + + END_TIME.getColumnName() + " = ? " + + WHERE + TRANSACTION_ID.getColumnName() + " LIKE '" + appcInstanceId + "%' AND " + + STATE.getColumnName() + " in (?,?)"; + + if (logger.isDebugEnabled()) { + logger.debug("Update query " + updateQuery + " appc-instance-id " + appcInstanceId); + } + + ArrayList<String> arguments = new ArrayList<>(); + arguments.add(dateToStringConverterMillis(Instant.now())); + arguments.add(RequestStatus.ACCEPTED.name()); + arguments.add(RequestStatus.RECEIVED.name()); try { - if (logger.isDebugEnabled()) { - logger.debug("Transaction Data started Inserting Successfully into DB"); + dbLibService.writeData(updateQuery, arguments, SCHEMA); + } catch (SQLException e) { + String message = "In progress transactions couldn't be marked aborted on server start up"; + logger.error(message); + throw new RuntimeException(message); + } + if (logger.isTraceEnabled()) { + logger.trace("In progress transactions marked aborted"); + } + } + + @Override + public List<TransactionRecord> getInProgressRequests(TransactionRecord record) throws APPCException { + + final String IN_PROGRESS_REQUESTS_QUERY = "SELECT * FROM " + + TransactionConstants.TRANSACTIONS + WHERE + + TARGET_ID + " = ? AND " + + STATE.getColumnName() + " IN (?,?) AND " + + START_TIME.getColumnName() + " < ?"; + + ArrayList<String> inProgressQueryParams = new ArrayList<>(); + inProgressQueryParams.add(record.getTargetId()); + inProgressQueryParams.add(RequestStatus.RECEIVED.name()); + inProgressQueryParams.add(RequestStatus.ACCEPTED.name()); + inProgressQueryParams.add(dateToStringConverterMillis(record.getStartTime())); + + try (CachedRowSet rowSet = dbLibService.getData(IN_PROGRESS_REQUESTS_QUERY, inProgressQueryParams, SCHEMA)) { + List<TransactionRecord> inProgressRecords = new ArrayList<>(); + TransactionRecord transaction; + while (rowSet.next()) { + transaction = new TransactionRecord(); + transaction.setTransactionId(rowSet.getString(TRANSACTION_ID.getColumnName())); + transaction.setRequestId(rowSet.getString(REQUEST_ID.getColumnName())); + transaction.setSubRequestId(rowSet.getString(SUBREQUEST_ID.getColumnName())); + transaction.setOriginatorId(rowSet.getString(ORIGINATOR_ID.getColumnName())); + transaction.setStartTime(stringToDateConverterMillis(rowSet.getString(START_TIME.getColumnName()))); + transaction.setTargetId(rowSet.getString(TARGET_ID.getColumnName())); + transaction.setTargetType(rowSet.getString(TARGET_TYPE.getColumnName())); + transaction.setOperation(VNFOperation.valueOf(rowSet.getString(OPERATION.getColumnName()))); + transaction.setRequestState(RequestStatus.valueOf(rowSet.getString(STATE.getColumnName()))); + transaction.setVnfcName(rowSet.getString(VNFC_NAME.getColumnName())); + transaction.setVserverId(rowSet.getString(VSERVER_ID.getColumnName())); + transaction.setVfModuleId(rowSet.getString(VF_MODULE_ID.getColumnName())); + transaction.setServiceInstanceId(rowSet.getString(SERVICE_INSTANCE_ID.getColumnName())); + transaction.setMode(Flags.Mode.valueOf(rowSet.getString(MODE.getColumnName()))); + inProgressRecords.add(transaction); + } + if (logger.isTraceEnabled()) { + logger.trace("In progress transaction records fetched from database successfully."); + } + return inProgressRecords; + } catch (ParseException e) { + logger.error("Error parsing start date during fetching in progress records ", e); + throw new APPCException(ERROR_ACCESSING_DATABASE, e); + } catch (SQLException e) { + logger.error("Error fetching in progress records for Transaction ID = " + appcInstanceId + "~" + record + .getTransactionId(), e); + throw new APPCException(ERROR_ACCESSING_DATABASE, e); + } + } + + @Override + public Boolean isTransactionDuplicate(TransactionRecord record) throws APPCException { + + StringBuilder duplicateRequestCheckQuery = new StringBuilder("SELECT " + + TRANSACTION_ID.getColumnName() + " FROM " + + TransactionConstants.TRANSACTIONS + WHERE + + TRANSACTION_ID.getColumnName() + " <> ? AND " + + REQUEST_ID.getColumnName() + " = ? AND " + + STATE.getColumnName() + " IN(?,?) "); + + ArrayList<String> duplicateCheckParams = new ArrayList<>(); + duplicateCheckParams.add(appcInstanceId + "~" + record.getTransactionId()); + duplicateCheckParams.add(record.getRequestId()); + duplicateCheckParams.add(RequestStatus.RECEIVED.name()); + duplicateCheckParams.add(RequestStatus.ACCEPTED.name()); + + if (!StringUtils.isBlank(record.getSubRequestId())) { + duplicateRequestCheckQuery.append(AND + SUBREQUEST_ID.getColumnName() + " = ? "); + duplicateCheckParams.add(record.getSubRequestId()); + } else { + duplicateRequestCheckQuery.append(AND + SUBREQUEST_ID.getColumnName() + IS_NULL); + } + if (!StringUtils.isBlank(record.getOriginatorId())) { + duplicateRequestCheckQuery.append(AND + ORIGINATOR_ID.getColumnName() + " = ? "); + duplicateCheckParams.add(record.getOriginatorId()); + } else { + duplicateRequestCheckQuery.append(AND + ORIGINATOR_ID.getColumnName() + IS_NULL); + } + if (logger.isDebugEnabled()) { + logger.debug(duplicateRequestCheckQuery.toString()); + } + try (CachedRowSet rowSet = dbLibService.getData(duplicateRequestCheckQuery.toString(), duplicateCheckParams, + SCHEMA)) { + if (rowSet.first()) { + String transactionId = rowSet.getString(TRANSACTION_ID.getColumnName()); + if (logger.isErrorEnabled()) { + logger.error("Duplicate request found. Transaction ID " + transactionId + " is currently in " + + "progress."); + } + return true; + } + return false; + } catch (SQLException e) { + logger.error("Error checking duplicate records for Transaction ID = " + appcInstanceId + "~" + record + .getTransactionId(), e); + throw new APPCException(ERROR_ACCESSING_DATABASE, e); + } + } + + @Override + public Integer getInProgressRequestsCount() throws APPCException { + final String inProgressRequestCountQuery = "SELECT COUNT(*) as VALUE FROM " + + TransactionConstants.TRANSACTIONS + + WHERE + STATE.getColumnName() + " IN (?,?) "; + + ArrayList<String> checkInProgressParams = new ArrayList<>(); + checkInProgressParams.add(RequestStatus.RECEIVED.name()); + checkInProgressParams.add(RequestStatus.ACCEPTED.name()); + try(CachedRowSet rowSet=dbLibService.getData(inProgressRequestCountQuery,checkInProgressParams,SCHEMA)){ + if (rowSet.first()) { + int count = rowSet.getInt("VALUE"); + logger.info("In progress request count fetched from database successfully."); + return count; } - connection = DBUtils.getConnection(APPCCTL_SCHEMA); - stmt = connection.prepareStatement(queryString); - stmt.setTimestamp(1, new java.sql.Timestamp(record.getTimeStamp().toEpochMilli())); - stmt.setString(2, record.getRequestID()); - stmt.setTimestamp(3, new java.sql.Timestamp(record.getStartTime().toEpochMilli())); - stmt.setTimestamp(4, new java.sql.Timestamp(record.getEndTime().toEpochMilli())); - stmt.setString(5, record.getTargetID()); - stmt.setString(6, record.getTargetType()); - stmt.setString(7, record.getSubComponent()); - stmt.setString(8, record.getOperation()); - stmt.setString(9, record.getResultCode()); - stmt.setString(10, record.getDescription()); - stmt.execute(); - if (logger.isDebugEnabled()) { - logger.debug("Transaction Data Inserted Successfully into DB"); + } + catch (SQLException e) { + logger.error("Error checking in progress request count in the transaction table", e); + throw new APPCException(ERROR_ACCESSING_DATABASE, e); + } + logger.error("Error checking in progress request count in the transaction table"); + throw new APPCException(ERROR_ACCESSING_DATABASE); + } + + @Override + public void setAppcInstanceId(String appcInstanceId) { + this.appcInstanceId = appcInstanceId; + } + + + @Override + public List<RequestStatus> getRecords(String requestId, String subrequestId, String originatorId, String vnfId) + throws APPCException { + StringBuilder queryString = (new StringBuilder(1024)) + .append("SELECT " + TRANSACTION_ATTRIBUTES.STATE.getColumnName()) + .append(" FROM " + TRANSACTIONS) + .append(" WHERE " + TRANSACTION_ATTRIBUTES.REQUEST_ID.getColumnName() + " = ? AND " + + TRANSACTION_ATTRIBUTES.TARGET_ID.getColumnName() + " = ?"); + + ArrayList<String> argList = new ArrayList<>(); + argList.add(requestId); + argList.add(vnfId); + + if (subrequestId != null) { + queryString.append(" AND " + TRANSACTION_ATTRIBUTES.SUBREQUEST_ID.getColumnName() + " = ?"); + argList.add(subrequestId); + } + if (originatorId != null) { + queryString.append(" AND " + TRANSACTION_ATTRIBUTES.ORIGINATOR_ID.getColumnName() + " = ?"); + argList.add(originatorId); + } + + List<RequestStatus> requestStatusList = new ArrayList<>(); + try { + CachedRowSet resultSet = dbLibService.getData(queryString.toString(), argList, SCHEMA); + while (resultSet.next()) { + String name = resultSet.getString(TRANSACTION_ATTRIBUTES.STATE.getColumnName()); + RequestStatus requestStatus = null; + try { + requestStatus = RequestStatus.valueOf(name); + } catch (IllegalArgumentException e) { + logger.error(String.format("Invalid request status (%s) using (%s) :", name, RequestStatus + .UNKNOWN), e); + requestStatus = RequestStatus.UNKNOWN; + } + requestStatusList.add(requestStatus); + logger.debug(String.format("Request Status obtained (%s).", requestStatus)); } } catch (SQLException e) { - logger.error("Error Accessing Database " + e); - throw new RuntimeException(e); - } finally { - DBUtils.clearResources(null, stmt, connection); + logger.error("Error Accessing Database ", e); + throw new APPCException(String.format("Error retrieving record for requestID %s and vnfId %s " + + "from the transactions table", requestId, vnfId), e); + } + + return requestStatusList; + } + + private ArrayList<String> prepareArguments(TransactionRecord input) { + ArrayList<String> arguments = new ArrayList<>(); + arguments.add(appcInstanceId + "~" + input.getTransactionId()); + arguments.add(dateToStringConverterMillis(input.getOriginTimestamp())); + arguments.add(input.getRequestId()); + arguments.add(input.getSubRequestId()); + arguments.add(input.getOriginatorId()); + arguments.add(dateToStringConverterMillis(input.getStartTime())); + arguments.add(dateToStringConverterMillis(input.getEndTime())); + arguments.add(input.getTargetId()); + arguments.add(input.getTargetType()); + arguments.add(input.getOperation().name()); + arguments.add(String.valueOf(input.getResultCode())); + arguments.add(input.getDescription()); + arguments.add(input.getRequestState()); + arguments.add(input.getServiceInstanceId()); + arguments.add(input.getVnfcName()); + arguments.add(input.getVserverId()); + arguments.add(input.getVfModuleId()); + arguments.add(input.getMode()); + + return arguments; + } + + private static String dateToStringConverterMillis(Instant date) { + if (date == null) { + return null; } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(ZoneOffset.UTC); + return formatter.format(date); + } + + private static Instant stringToDateConverterMillis(String dateString) throws ParseException { + SimpleDateFormat customDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + return customDate.parse(dateString).toInstant(); } } diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/objects/TransactionConstants.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/objects/TransactionConstants.java new file mode 100644 index 000000000..ada9f0751 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/objects/TransactionConstants.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.transactionrecorder.objects; + +public class TransactionConstants { + + public static final String INSERT_INTO = "INSERT INTO "; + public static final String TRANSACTIONS = "TRANSACTIONS"; + public static final String COMMA= " , "; + public static final String WHERE = " WHERE "; + public static final String IS_NULL= " IS NULL "; + public static final String AND=" AND "; + public static final String ERROR_ACCESSING_DATABASE = "Error Accessing Database "; + + public enum TRANSACTION_ATTRIBUTES { + + TRANSACTION_ID("TRANSACTION_ID"), + ORIGIN_TIMESTAMP("ORIGIN_TIMESTAMP"), + REQUEST_ID("REQUEST_ID"), + SUBREQUEST_ID("SUBREQUEST_ID"), + ORIGINATOR_ID("ORIGINATOR_ID"), + START_TIME("START_TIME"), + END_TIME("END_TIME"), + TARGET_ID("TARGET_ID"), + TARGET_TYPE("TARGET_TYPE"), + OPERATION("OPERATION"), + RESULT_CODE("RESULT_CODE"), + DESCRIPTION("DESCRIPTION"), + STATE("STATE"), + SERVICE_INSTANCE_ID("SERVICE_INSTANCE_ID"), + VNFC_NAME("VNFC_NAME"), + VSERVER_ID("VSERVER_ID"), + VF_MODULE_ID("VF_MODULE_ID"), + MODE("MODE"); + + private String columnName; + TRANSACTION_ATTRIBUTES(String columnName){ + this.columnName=columnName; + } + + public String getColumnName(){ + return columnName; + } + } + +} diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/objects/TransactionRecord.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/objects/TransactionRecord.java deleted file mode 100644 index ba3af9985..000000000 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/objects/TransactionRecord.java +++ /dev/null @@ -1,150 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP : APPC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Copyright (C) 2017 Amdocs - * ============================================================================= - * 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. - * - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - * ============LICENSE_END========================================================= - */ - -package org.onap.appc.transactionrecorder.objects; - -import java.time.Instant; - - -public class TransactionRecord { - - /* -- Timestamp = RequestHandlerInput.RequestHeader.timeStamp -- Request ID = RequestHandlerInput.RequestHeader.requestID -- Start time = from flow -- End time = from flow -- VF_ID = RequestHandlerInput.targetID -- VF_type = genericVnf.getVnfType() -- Sub-component (optional) e.g. VFC_ID/VM UUID - ???? empty -- Operation e.g. Start, Configure etc. = CommandContext.Command -- Result - Success/Error code + description,as published to the initiator RequestHandlerResponse.ACCEPTED/RequestHandlerResponse.REJECTED + String (description) - */ - - private Instant timeStamp; - private String requestID; - private Instant startTime; - private Instant endTime; - private String targetID; - private String targetType; - private String subComponent; - private String operation; - private String resultCode; - private String description; - - public Instant getTimeStamp() { - return timeStamp; - } - - public void setTimeStamp(Instant timeStamp) { - this.timeStamp = timeStamp; - } - - public String getRequestID() { - return requestID; - } - - public void setRequestID(String requestID) { - this.requestID = requestID; - } - - public Instant getStartTime() { - return startTime; - } - - public void setStartTime(Instant startTime) { - this.startTime = startTime; - } - - public Instant getEndTime() { - return endTime; - } - - public void setEndTime(Instant endTime) { - this.endTime = endTime; - } - - public String getTargetID() { - return targetID; - } - - public void setTargetID(String targetID) { - this.targetID = targetID; - } - - public String getTargetType() { - return targetType; - } - - public void setTargetType(String targetType) { - this.targetType = targetType; - } - - public String getSubComponent() { - return subComponent; - } - - public void setSubComponent(String subComponent) { - this.subComponent = subComponent; - } - - public String getOperation() { - return operation; - } - - public void setOperation(String operation) { - this.operation = operation; - } - - public String getResultCode() { - return resultCode; - } - - public void setResultCode(String resultCode) { - this.resultCode = resultCode; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String toString() { - return "TransactionRecord{" + - "timeStamp=" + timeStamp + - ", requestID='" + requestID + '\'' + - ", startTime=" + startTime + - ", endTime=" + endTime + - ", targetID='" + targetID + '\'' + - ", targetType='" + targetType + '\'' + - ", subComponent='" + subComponent + '\'' + - ", operation='" + operation + '\'' + - ", resultCode='" + resultCode + '\'' + - ", description='" + description + '\'' + - '}'; - } -} diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/resources/OSGI-INF/blueprint/blueprint.xml index ba8d9f8a0..9240b0efe 100644 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/resources/OSGI-INF/blueprint/blueprint.xml +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -29,6 +29,13 @@ <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> - <bean id="transactionRecorderBean" class="org.onap.appc.transactionrecorder.impl.TransactionRecorderImpl" scope="singleton" ></bean> - <service id="transactionRecorderService" interface="org.onap.appc.transactionrecorder.TransactionRecorder" ref="transactionRecorderBean"/> + <reference id="dbLibServiceRef" availability="mandatory" activation="eager" + interface="org.onap.ccsdk.sli.core.dblib.DbLibService"/> + <bean id="transactionRecorderBean" class="org.onap.appc.transactionrecorder.impl.TransactionRecorderImpl" + scope="singleton"> + <property name="dbLibService" ref="dbLibServiceRef"/> + </bean> + + <service id="transactionRecorderService" interface="org.onap.appc.transactionrecorder.TransactionRecorder" + ref="transactionRecorderBean"/> </blueprint> diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/test/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImplTest.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/test/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImplTest.java new file mode 100644 index 000000000..738a8a638 --- /dev/null +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/test/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImplTest.java @@ -0,0 +1,466 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.transactionrecorder.impl; + +import com.sun.rowset.CachedRowSetImpl; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import org.onap.appc.dao.util.dbcp.DBConnectionPool; +import org.onap.appc.dao.util.helper.DBHelper; +import org.onap.appc.domainmodel.lcm.Flags; +import org.onap.appc.domainmodel.lcm.RequestStatus; +import org.onap.appc.domainmodel.lcm.TransactionRecord; +import org.onap.appc.domainmodel.lcm.VNFOperation; +import org.onap.appc.exceptions.APPCException; +import org.onap.appc.transactionrecorder.objects.TransactionConstants; +import org.onap.ccsdk.sli.core.dblib.DbLibService; + +import javax.sql.rowset.CachedRowSet; +import java.sql.*; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.mockito.Matchers.*; + +/** + * Test class for TransactionRecorder + */ +public class TransactionRecorderImplTest { + + private String dbUrl = "jdbc:h2:mem:test;MODE=MYSQL;DB_CLOSE_DELAY=-1"; + private String username = "sa"; + private String password = "sa"; + private String driver = "org.h2.Driver"; + + private TransactionRecorderImpl transactionRecorderImpl; + private DbLibService dbLibService; + + private DBConnectionPool dbConnectionPool; + + + /** + * Ideally JUnit should grab the SQL to create the transaction table from the same source used in deployments; + * however, at the time of writing this that was not possible. Should it become possible in the future please + * update this JUnit test to use the deployment source. + * <p> + * Please ensure this table create script is identical to the source script used in a deployment. + */ + private String TRANSACTION_CREATE_TABLE = "CREATE TABLE TRANSACTIONS (" + + " TRANSACTION_ID VARCHAR(75) NOT NULL PRIMARY KEY," + + " ORIGIN_TIMESTAMP DATETIME(3) NOT NULL," + + " REQUEST_ID VARCHAR(256) NOT NULL," + + " SUBREQUEST_ID VARCHAR(256) DEFAULT NULL," + + " ORIGINATOR_ID VARCHAR(256) DEFAULT NULL," + + " START_TIME DATETIME(3) NOT NULL," + + " END_TIME DATETIME(3) DEFAULT NULL," + + " TARGET_ID VARCHAR(256) NOT NULL," + + " TARGET_TYPE VARCHAR(256) DEFAULT NULL," + + " OPERATION VARCHAR(256) NOT NULL," + + " RESULT_CODE INT(11) DEFAULT NULL," + + " DESCRIPTION TEXT," + + " STATE VARCHAR(50) NOT NULL," + + " SERVICE_INSTANCE_ID VARCHAR(256) DEFAULT NULL," + + " VNFC_NAME VARCHAR(256) DEFAULT NULL," + + " VSERVER_ID VARCHAR(256) DEFAULT NULL," + + " VF_MODULE_ID VARCHAR(256) DEFAULT NULL," + + " MODE VARCHAR(50) NOT NULL," + + ")"; + private String TRANSACTION_DROP_TABLE = "DROP TABLE IF EXISTS TRANSACTIONS"; + + @Before + public void setUp() throws Exception { + transactionRecorderImpl = new TransactionRecorderImpl(); + transactionRecorderImpl.setAppcInstanceId("123"); + dbLibService = Mockito.mock(DbLibService.class); + transactionRecorderImpl.setDbLibService(dbLibService); + dbConnectionPool = new DBConnectionPool(dbUrl, username, password, driver); + executeUpdate(TRANSACTION_CREATE_TABLE); + + } + + + @After + public void shutdown() { + if (dbConnectionPool != null) { + executeUpdate(TRANSACTION_DROP_TABLE); + dbConnectionPool.shutdown(); + } + } + + private void executeUpdate(String updateSQL) { + Connection connection = null; + Statement stmt = null; + try { + connection = dbConnectionPool.getConnection(); + stmt = connection.createStatement(); + stmt.executeUpdate(updateSQL); + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + DBHelper.close(null, stmt, connection); + } + } + + /** + * Verify the transactionRecorderImpl.sore() store the TransactionRecord correctly in the database. + */ + @Test + public void testStore() throws Exception { + + TransactionRecord input = prepareTransactionsInput(); + Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> + testStoreInMemory(invocation.getArguments())); + transactionRecorderImpl.store(input); + + } + + @Test + public void testGetInProgressRequests() throws SQLException, APPCException { + TransactionRecord record1 = prepareTransactionsInput(); + insertRecord(record1); + TransactionRecord input = prepareTransactionsInput(); + input.setStartTime(Instant.now()); + Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> + inMemoryExecutionWithResultSet(invocation.getArguments())); + Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input).size()); + + } + + @Test + public void testIsTransactionDuplicate() throws SQLException, APPCException { + TransactionRecord input = prepareTransactionsInput(); + Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> + inMemoryExecutionWithResultSet(invocation.getArguments())); + Assert.assertFalse(transactionRecorderImpl.isTransactionDuplicate(input)); + + } + + @Test + public void testGetInProgressRequestsCount() throws SQLException, APPCException { + TransactionRecord input = prepareTransactionsInput(); + Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> + inMemoryExecutionWithResultSet(invocation.getArguments())); + Assert.assertEquals(0, transactionRecorderImpl.getInProgressRequestsCount().intValue()); + } + + @Test + public void testUpdate() throws APPCException, SQLException { + TransactionRecord input = prepareTransactionsInput(); + insertRecord(input); + Map<TransactionConstants.TRANSACTION_ATTRIBUTES, String> updateColumns = new HashMap<>(); + updateColumns.put(TransactionConstants.TRANSACTION_ATTRIBUTES.TARGET_TYPE, "Firewall"); + Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> + testUpdateInMemory(invocation.getArguments())); + transactionRecorderImpl.update(input.getTransactionId(), updateColumns); + } + + @Test + public void testMarkTransactionsAborted() throws SQLException { + TransactionRecord input = prepareTransactionsInput(); + insertRecord(input); + Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> + testMarkAbortedInMemory(invocation.getArguments())); + transactionRecorderImpl.markTransactionsAborted("123~"); + } + + private ResultSet inMemoryExecutionWithResultSet(Object[] obj) throws Exception { + String query = (String) obj[0]; + ArrayList<String> args = (ArrayList<String>) obj[1]; + Connection con = dbConnectionPool.getConnection(); + PreparedStatement ps = con.prepareStatement(query); + for (int i = 1; i <= args.size(); i++) { + ps.setString(i, args.get(i - 1)); + } + CachedRowSet rowSet = new CachedRowSetImpl(); + rowSet.populate(ps.executeQuery()); + return rowSet; + } + + private boolean testMarkAbortedInMemory(Object[] obj) throws Exception { + String query = (String) obj[0]; + ArrayList<String> args = (ArrayList<String>) obj[1]; + Connection con = dbConnectionPool.getConnection(); + PreparedStatement ps = con.prepareStatement(query); + for (int i = 1; i <= args.size(); i++) { + ps.setString(i, args.get(i - 1)); + } + ps.execute(); + return isTransactionAborted(); + } + + private boolean isTransactionAborted() throws Exception { + String query = "SELECT COUNT(*) FROM TRANSACTIONS WHERE STATE = ?"; + Connection con = dbConnectionPool.getConnection(); + PreparedStatement ps = con.prepareStatement(query); + ps.setString(1, RequestStatus.ABORTED.toString()); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + int value = rs.getInt(1); + if (value == 1) { + System.out.println("Non terminal Transactions are aborted"); + return true; + } + } + throw new Exception("Transactions are not aborted"); + } + + private boolean testUpdateInMemory(Object[] obj) throws Exception { + String query = (String) obj[0]; + ArrayList<String> args = (ArrayList<String>) obj[1]; + Connection con = dbConnectionPool.getConnection(); + PreparedStatement ps = con.prepareStatement(query); + for (int i = 1; i <= args.size(); i++) { + ps.setString(i, args.get(i - 1)); + } + ps.execute(); + String updatedValue = checkIfValueIsUpdated(args.get(1)); + System.out.println("updated Value is " + updatedValue); + if (updatedValue.equals("Firewall")) { + return true; + } + throw new Exception("Not Updated"); + } + + private boolean testStoreInMemory(Object[] obj) throws Exception { + String query = (String) obj[0]; + ArrayList<String> args = (ArrayList<String>) obj[1]; + Connection con = dbConnectionPool.getConnection(); + PreparedStatement ps = con.prepareStatement(query); + for (int i = 1; i <= args.size(); i++) { + ps.setString(i, args.get(i - 1)); + } + ps.execute(); + if (checkIfRowIsPresent(args.get(0))) { + return true; + } + throw new Exception("Failed to update"); + } + + private TransactionRecord prepareTransactionsInput() { + TransactionRecord input = new TransactionRecord(); + input.setTransactionId(UUID.randomUUID().toString()); + input.setOriginTimestamp(Instant.parse("2017-09-11T00:00:01.00Z")); + input.setRequestId("REQUEST_ID"); + input.setSubRequestId("SUB_REQUEST_ID"); + input.setOriginatorId("ORIGINATOR_ID"); + input.setStartTime(Instant.parse("2017-09-11T00:00:02.00Z")); + input.setTargetId("TARGET_ID"); + input.setTargetType("TARGET_TYPE"); + input.setServiceInstanceId("SERVICE_INSTANCE_ID"); + input.setOperation(VNFOperation.ActionStatus); + input.setResultCode(200); + input.setRequestState(RequestStatus.ACCEPTED); + input.setDescription("DESCRIPTION"); + input.setMode(Flags.Mode.EXCLUSIVE); + return input; + } + + private void insertRecord(TransactionRecord input) throws SQLException { + final String STORE_DATE_QUERY = TransactionConstants.INSERT_INTO + TransactionConstants.TRANSACTIONS + + " values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + Connection con = dbConnectionPool.getConnection(); + PreparedStatement ps = con.prepareStatement(STORE_DATE_QUERY); + ArrayList<String> args = prepareArguments(input); + args.remove(0); + args.add(0, "123~" + input.getTransactionId()); + for (int i = 1; i <= 18; i++) { + ps.setString(i, args.get(i - 1)); + } + ps.execute(); + if (checkIfRowIsPresent(args.get(0))) { + System.out.println("RECORD INSERTED " + args.get(0)); + } + + } + + private ArrayList<String> prepareArguments(TransactionRecord input) { + ArrayList<String> arguments = new ArrayList<>(); + arguments.add(input.getTransactionId()); + arguments.add(dateToStringConverterMillis(input.getOriginTimestamp())); + arguments.add(input.getRequestId()); + arguments.add(input.getSubRequestId()); + arguments.add(input.getOriginatorId()); + arguments.add(dateToStringConverterMillis(input.getStartTime())); + arguments.add(dateToStringConverterMillis(input.getEndTime())); + arguments.add(input.getTargetId()); + arguments.add(input.getTargetType()); + arguments.add(input.getOperation().name()); + arguments.add(String.valueOf(input.getResultCode())); + arguments.add(input.getDescription()); + arguments.add(input.getRequestState()); + arguments.add(input.getServiceInstanceId()); + arguments.add(input.getVnfcName()); + arguments.add(input.getVserverId()); + arguments.add(input.getVfModuleId()); + arguments.add(input.getMode()); + + return arguments; + } + + private static String dateToStringConverterMillis(Instant date) { + if (date == null) { + return null; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(ZoneOffset.UTC); + return formatter.format(date); + } + + private boolean checkIfRowIsPresent(String key) { + Connection con = null; + ResultSet rs = null; + PreparedStatement ps = null; + try { + con = dbConnectionPool.getConnection(); + ps = con.prepareStatement("SELECT COUNT(*) FROM TRANSACTIONS WHERE TRANSACTION_ID = ?"); + ps.setString(1, key); + rs = ps.executeQuery(); + while (rs.next()) { + int value = rs.getInt(1); + System.out.println("KEY checked is " + key + " COUNT RETURNED IS " + value); + if (value == 1) { + return true; + } + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + DBHelper.close(rs, ps, con); + } + return false; + } + + private String checkIfValueIsUpdated(String key) throws Exception { + Connection con = dbConnectionPool.getConnection(); + PreparedStatement ps = con.prepareStatement("SELECT TARGET_TYPE FROM TRANSACTIONS WHERE TRANSACTION_ID = ?"); + ps.setString(1, key); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + String value = rs.getString("TARGET_TYPE"); + return value; + } + throw new Exception("Value not found"); + } + + + /** + * Verify the transactionRecorderImpl. getRecords () can be fetch with each of the parameter combinations + * @throws Exception + *//* + @Test + public void test_api_getRecords() throws Exception { + + + final int requestId = 0; + final int subrequestId = 1; + final int originatorId = 2; + final int vnfId = 3; + final int requestStatus = 4; + + + String[][] trCreateMatrix = { + {"request1", "subrequestId1", "originatorId1", "vnfId1", RequestStatus.UNKNOWN.name()}, + {"request1", "subrequestId2", "originatorId1", "vnfId1", RequestStatus.RECEIVED.name()}, + {"request2", "subrequestId1", "originatorId1", "vnfId1", RequestStatus.ACCEPTED.name()}, + {"request2", "subrequestId2", "originatorId1", "vnfId1", RequestStatus.REJECTED.name()}, + {"request1", "subrequestId1", "originatorId1", "vnfId2", RequestStatus.SUCCESSFUL.name()}, + {"request1", "subrequestId2", "originatorId1", "vnfId2", RequestStatus.FAILED.name()}, + {"request2", "subrequestId1", "originatorId1", "vnfId2", RequestStatus.TIMEOUT.name()}, + {"request2", "subrequestId2", "originatorId1", "vnfId2", RequestStatus.ABORTED.name()}, + {"request1", "subrequestId1", "originatorId2", "vnfId1", RequestStatus.UNKNOWN.name()}, + {"request1", "subrequestId2", "originatorId2", "vnfId1", RequestStatus.RECEIVED.name()}, + {"request2", "subrequestId1", "originatorId2", "vnfId1", RequestStatus.ACCEPTED.name()}, + {"request2", "subrequestId2", "originatorId2", "vnfId1", RequestStatus.REJECTED.name()}, + {"request1", "subrequestId1", "originatorId2", "vnfId2", RequestStatus.SUCCESSFUL.name()}, + {"request1", "subrequestId2", "originatorId2", "vnfId2", RequestStatus.FAILED.name()}, + {"request2", "subrequestId1", "originatorId2", "vnfId2", RequestStatus.TIMEOUT.name()}, + {"request2", "subrequestId2", "originatorId2", "vnfId2", RequestStatus.ABORTED.name()}, + }; + + + TransactionRecord tr = new TransactionRecord(); + tr.setTimeStamp(Instant.parse("2017-09-11T00:00:01.00Z")); + tr.setStartTime(Instant.parse("2017-09-11T00:00:02.00Z")); + tr.setEndTime(Instant.parse("2017-09-11T00:00:03.00Z")); + tr.setTargetType("TARGET_TYPE"); + tr.setSubComponent("SUB_COMPONENT"); + tr.setOperation(VNFOperation.ActionStatus); + tr.setResultCode("RESULT_CODE"); + tr.setDescription("DESCRIPTION"); + + for (int row = 0; row < trCreateMatrix.length; row++) { + tr.setRequestID(trCreateMatrix[row][requestId]); + tr.setSubRequestID(trCreateMatrix[row][subrequestId]); + tr.setOriginatorId(trCreateMatrix[row][originatorId]); + tr.setTargetID(trCreateMatrix[row][vnfId]); + tr.setRequestStatus(RequestStatus.valueOf(trCreateMatrix[row][requestStatus])); + transactionRecorderImpl.store(tr); + } + + + String[][] trSearchMatrix = { + {"request1", null, null, "vnfId1"}, + {"request2", "subrequestId1", null, "vnfId1"}, + {"request1", null, "originatorId1", "vnfId1"}, + {"request2", "subrequestId2", "originatorId1", "vnfId1"}, + }; + + + for (int i = 0; i < trSearchMatrix.length; i++) { + final int row = i; + List<RequestStatus> actualList = transactionRecorderImpl + .getRecords(trSearchMatrix[row][requestId], trSearchMatrix[row][subrequestId], + trSearchMatrix[row][originatorId], trSearchMatrix[row][vnfId]) + .stream() + .sorted() + .collect(Collectors.toList()); + + List<RequestStatus> expectedList = Arrays.stream(trCreateMatrix) + .filter(entry -> entry[requestId].equals(trSearchMatrix[row][requestId])) + .filter(entry -> trSearchMatrix[row][subrequestId] == null || entry[subrequestId].equals + (trSearchMatrix[row][subrequestId])) + .filter(entry -> trSearchMatrix[row][originatorId] == null || entry[originatorId].equals + (trSearchMatrix[row][originatorId])) + .filter(entry -> entry[vnfId].equals(trSearchMatrix[row][vnfId])) + .map(entry -> RequestStatus.valueOf(entry[requestStatus])) + .sorted() + .collect(Collectors.toList()); + System.out.println(expectedList); + System.out.println(actualList); + Assert.assertEquals("Unexpected results: ", expectedList, actualList); + + } + + + }*/ +} |