Merge of new rebased code

Change-Id: I9b8d1f69eb3e0af1935ed8304fea4bf54c1aac47
Signed-off-by: Patrick Brady <pb071s@att.com>
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 cae7eed..94a45e3 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
@@ -6,7 +6,7 @@
         <version>1.1.0-SNAPSHOT</version>
     </parent>
   <artifactId>appc-data-access-lib</artifactId>
-  <packaging>jar</packaging>
+  <packaging>bundle</packaging>
 
   <name>appc-data-access-lib</name>
   <url>http://maven.apache.org</url>
@@ -35,7 +35,24 @@
           <groupId>org.openecomp.appc</groupId>
           <artifactId>appc-common</artifactId>
           <version>${project.version}</version>
-          <scope>compile</scope>
       </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.openecomp.appc.dao.util</Export-Package>
+                    <Import-Package>org.openecomp.appc.configuration,*;resolution:=optional</Import-Package>
+                    <Embed-Dependency>mysql-connector-java</Embed-Dependency>
+                    <Embed-Transitive>true</Embed-Transitive>
+                </instructions>
+            </configuration>
+        </plugin>
+    </plugins>
+  </build>
 </project>
diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/openecomp/appc/domainmodel/lcm/VNFOperation.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/openecomp/appc/domainmodel/lcm/VNFOperation.java
index c61901e..904722f 100644
--- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/openecomp/appc/domainmodel/lcm/VNFOperation.java
+++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/openecomp/appc/domainmodel/lcm/VNFOperation.java
@@ -23,8 +23,9 @@
 
 public enum VNFOperation {
 
-	Configure, Test, HealthCheck, Start, Terminate, Restart, Rebuild, Stop, ModifyConfig, Backup, Snapshot,
-	SoftwareUpload, LiveUpgrade, Rollback, Sync, Audit, Test_lic, Migrate, Evacuate,
+	Configure, Test, HealthCheck, Start, Terminate, Restart, Rebuild, Stop, ConfigModify,
+	ConfigScaleOut,ConfigRestore,Backup, Snapshot,
+	SoftwareUpload, LiveUpgrade, Rollback, Sync, Audit, Test_lic, Migrate, Evacuate,ConfigBackup,ConfigBackupDelete,ConfigExport,
 	Lock(true), Unlock(true), CheckLock(true);
 
 	private boolean builtIn;
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 f8b1e56..d20759f 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
@@ -26,7 +26,7 @@
       <artifactId>eelf-core</artifactId>
       </dependency>
   </dependencies>
-  
+
       <build>
         <plugins>
             <plugin>
@@ -36,10 +36,11 @@
                     <instructions>
                         <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                         <Bundle-Version>${project.version}</Bundle-Version>
-			            <Embed-Dependency>appc-common,eelf-core,logback-core,logback-classic;scope=compile|runtime;inline=false</Embed-Dependency>
                         <Embed-Transitive>true</Embed-Transitive>
                         <Export-Package>org.openecomp.appc.executionqueue,org.openecomp.appc.executionqueue.impl</Export-Package>
-                        <Import-Package>!groovy.lang,!javax.*,!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.*,*</Import-Package>
+                        <Import-Package>
+                            *;resolution:=optional
+                        </Import-Package>
                     </instructions>
                 </configuration>
             </plugin>
diff --git a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/openecomp/appc/executionqueue/impl/ExecutionQueueServiceFactory.java b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/openecomp/appc/executionqueue/impl/ExecutionQueueServiceFactory.java
index 01e4358..29de597 100644
--- a/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/openecomp/appc/executionqueue/impl/ExecutionQueueServiceFactory.java
+++ b/appc-dispatcher/appc-dispatcher-common/execution-queue-management-lib/src/main/java/org/openecomp/appc/executionqueue/impl/ExecutionQueueServiceFactory.java
@@ -25,16 +25,11 @@
 
 public class ExecutionQueueServiceFactory {
 
-    private static ExecutionQueueService executionQueueService =null;
-
-    public static ExecutionQueueService getExecutionQueueService(){
-        if(executionQueueService == null){
-            synchronized (ExecutionQueueServiceFactory.class){
-                if(executionQueueService == null)
-                    executionQueueService = new ExecutionQueueServiceImpl();
-            }
-        }
-        return executionQueueService;
+    private static class ExecutionQueueServiceHolder {
+        public static final ExecutionQueueService executionQueueService = new ExecutionQueueServiceImpl();
     }
 
+    public static ExecutionQueueService getExecutionQueueService() {
+        return ExecutionQueueServiceHolder.executionQueueService;
+    }
 }
diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/src/main/resources/features.xml b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/src/main/resources/features.xml
index ed51ca7..8b21318 100644
--- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/src/main/resources/features.xml
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-features/src/main/resources/features.xml
@@ -26,6 +26,10 @@
     xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0  http://karaf.apache.org/xmlns/features/v1.2.0">     
         
     <feature name='lock-manager' description="lock-manager" version='${project.version}'>
+        <!-- appc-common and appc-data-access-lib bundles are flagged as being a dependency -->
+        <bundle dependency="true">mvn:org.openecomp.appc/appc-common/${project.version}</bundle>
+        <bundle dependency="true">mvn:org.openecomp.appc/appc-data-access-lib/${project.version}</bundle>
+
     	<bundle start-level="80" start="true">mvn:org.openecomp.appc/lock-manager-api/${project.version}</bundle>
         <bundle start-level="85" start="true">mvn:org.openecomp.appc/lock-manager-impl/${project.version}</bundle>
     </feature>
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 48befce..8da6519 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
@@ -28,7 +28,6 @@
             <groupId>org.openecomp.appc</groupId>
             <artifactId>appc-data-access-lib</artifactId>
             <version>${project.version}</version>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.att.eelf</groupId>
@@ -49,16 +48,16 @@
                 <configuration>
                     <instructions>
                         <Export-Service>org.openecomp.appc.lockmanager.api.LockManager</Export-Service>
-                        <Import-Package>org.openecomp.appc.lockmanager.api.*,*</Import-Package>
+                        <Import-Package>
+                            org.openecomp.appc.lockmanager.api.*,
+                            org.openecomp.appc.dao.util,com.att.eelf.configuration, *;resolution:=optional
+                        </Import-Package>
                         <Private-Package>org.openecomp.appc.lockmanager.impl.*</Private-Package>
                         <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                         <Bundle-Version>${project.version}</Bundle-Version>
-                        <Import-Package>!org.apache.log,!org.apache.commons.logging,!groovy.lang,!javax.jms,!javax.mail.*,!org.codehaus.commons.compiler,!org.codehaus.groovy.*,!org.codehaus.janino,!com.ibm.icu.*,!com.sun.faces.*,!org.jasypt.*,*</Import-Package>
-                        <Embed-Dependency>appc-common,appc-data-access-lib,eelf-core,logback-core,logback-classic;scope=compile|runtime;inline=false</Embed-Dependency>
-                        <Embed-Transitive>true</Embed-Transitive>
                     </instructions>
                 </configuration>
             </plugin>
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/Messages.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/Messages.java
index 0399726..62181d4 100644
--- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/Messages.java
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/Messages.java
@@ -28,6 +28,7 @@
     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]."),
+    EXP_CHECK_LOCK("Error check locking resource [%s]."),//for checklock operation
     EXP_UNLOCK("Error unlocking resource [%s]."),
     ;
 
diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java
index 52c75d2..54622c4 100644
--- a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/optimistic/SqlLockManager.java
@@ -91,7 +91,7 @@
                 }
 			}
 		} catch (SQLException e) {
-			throw new LockRuntimeException(Messages.EXP_LOCK.format(resource));
+			throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource));
 		}finally {
             closeDbConnection(connection);
         }
diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/LockRecord.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/LockRecord.java
new file mode 100644
index 0000000..7d53737
--- /dev/null
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/LockRecord.java
@@ -0,0 +1,62 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * 						reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.lockmanager.impl.sql.pessimistic;
+
+class LockRecord {
+
+	private String resource;
+	private String owner;
+	private long updated;
+	private long timeout;
+
+	LockRecord(String resource) {
+		this.resource = resource;
+	}
+
+	public String getResource() {
+		return resource;
+	}
+
+	public String getOwner() {
+		return owner;
+	}
+
+	public void setOwner(String owner) {
+		this.owner = owner;
+	}
+
+	public long getUpdated() {
+		return updated;
+	}
+
+	public void setUpdated(long updated) {
+		this.updated = updated;
+	}
+
+	public long getTimeout() {
+		return 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/openecomp/appc/lockmanager/impl/sql/pessimistic/MySqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/MySqlLockManager.java
new file mode 100644
index 0000000..79d0f6c
--- /dev/null
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/MySqlLockManager.java
@@ -0,0 +1,85 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * 						reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.lockmanager.impl.sql.pessimistic;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.openecomp.appc.lockmanager.api.LockRuntimeException;
+
+public class MySqlLockManager extends SqlLockManager {
+
+	private static final int DEF_CRITICAL_SECTION_WAIT_TIMEOUT = 3;
+
+	protected int criticalSectionWaitTimeoutSecs = DEF_CRITICAL_SECTION_WAIT_TIMEOUT;
+
+	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) {
+            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);
+		}
+	}
+}
diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/SqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/SqlLockManager.java
new file mode 100644
index 0000000..71f6492
--- /dev/null
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/main/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/SqlLockManager.java
@@ -0,0 +1,251 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * 						reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.lockmanager.impl.sql.pessimistic;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.openecomp.appc.lockmanager.api.LockException;
+import org.openecomp.appc.lockmanager.api.LockRuntimeException;
+import org.openecomp.appc.lockmanager.impl.sql.JdbcLockManager;
+import org.openecomp.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;
+	}
+}
diff --git a/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/MySqlLockManagerMock.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/MySqlLockManagerMock.java
new file mode 100644
index 0000000..a94dc18
--- /dev/null
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/MySqlLockManagerMock.java
@@ -0,0 +1,150 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * 						reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.lockmanager.impl.sql.pessimistic;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.openecomp.appc.lockmanager.api.LockRuntimeException;
+import org.openecomp.appc.lockmanager.impl.sql.Synchronizer;
+import org.openecomp.appc.lockmanager.impl.sql.SynchronizerReceiver;
+import org.openecomp.appc.lockmanager.impl.sql.pessimistic.LockRecord;
+import org.openecomp.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;
+
+	MySqlLockManagerMock(boolean useReal) {
+		this.useReal = useReal;
+	}
+
+	@Override
+	public void setSynchronizer(Synchronizer synchronizer) {
+		this.synchronizer = synchronizer;
+	}
+
+	@Override
+	protected Connection openDbConnection() {
+		if(useReal) {
+			return super.openDbConnection();
+		}
+		return null;
+	}
+
+	@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 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 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);
+		}
+	}
+
+	@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/openecomp/appc/lockmanager/impl/sql/pessimistic/TestMySqlLockManager.java b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/TestMySqlLockManager.java
new file mode 100644
index 0000000..cf8781b
--- /dev/null
+++ b/appc-dispatcher/appc-dispatcher-common/lock-manager-lib/lock-manager-impl/src/test/java/org/openecomp/appc/lockmanager/impl/sql/pessimistic/TestMySqlLockManager.java
@@ -0,0 +1,121 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * 						reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.lockmanager.impl.sql.pessimistic;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openecomp.appc.lockmanager.api.LockException;
+import org.openecomp.appc.lockmanager.api.LockRuntimeException;
+import org.openecomp.appc.lockmanager.impl.sql.JdbcLockManager;
+import org.openecomp.appc.lockmanager.impl.sql.MySqlLockManagerBaseTests;
+import org.openecomp.appc.lockmanager.impl.sql.Synchronizer;
+import org.openecomp.appc.lockmanager.impl.sql.pessimistic.MySqlLockManager;
+
+import java.util.concurrent.*;
+
+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);
+	}
+
+	@Test
+	public void testConcurrentLock() throws LockException, InterruptedException, ExecutionException, TimeoutException {
+        try {
+            callConcurrentTest(new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    try {
+                        Assert.assertTrue(lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name()));
+                        return true;
+                    } catch(LockRuntimeException e) {
+                        Assert.assertEquals("Cannot obtain critical section lock for resource [" + Resource.Resource1.name() + "].", e.getMessage());
+                        return false;
+                    }
+                }
+            });
+        } finally {
+            lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name());
+		}
+	}
+
+	@Test
+    public void testConcurrentUnlock() throws LockException, InterruptedException, ExecutionException, TimeoutException {
+        lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name());
+        callConcurrentTest(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                try {
+                    lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name());
+                    return true;
+                } catch(LockRuntimeException e) {
+                    Assert.assertEquals("Cannot obtain critical section lock for resource [" + Resource.Resource1.name() + "].", e.getMessage());
+                    return false;
+                }
+            }
+        });
+    }
+
+    private void callConcurrentTest(Callable<Boolean> callable) throws LockException, InterruptedException, ExecutionException, TimeoutException {
+        final int participantsNo = 2;
+        Synchronizer synchronizer = new Synchronizer(participantsNo) {
+
+            @Override
+            protected void waitForAllParticipants(Object waitObj, int totalParticipantsNo, int currentParticipantsNo) {
+                waitOn(this, TimeUnit.MILLISECONDS.convert(1 + CRITICAL_SECTION_WAIT_TIMEOUT, TimeUnit.SECONDS)); // add 1 sec to make sure timeout occured
+            }
+        };
+        if(!setSynchronizer(synchronizer)) {
+            return;
+        }
+        ((MySqlLockManager)lockManager).setCriticalSectionWaitTimeoutSecs(CRITICAL_SECTION_WAIT_TIMEOUT);
+        ExecutorService executor = Executors.newFixedThreadPool(participantsNo);
+        Future<Boolean> future1 = executor.submit(callable);
+        try {
+            for(int i = 0; i < 10; i++) {
+                Thread.sleep(100);
+                if(synchronizer.getParticipantCount() > 0) {
+                    break;
+                }
+            }
+            // make sure 1st thread gets inside critical section
+            if(synchronizer.getParticipantCount() < 1) {
+                Assert.fail(getClass().getName() + " first thread failed to acquireLock()");
+            }
+            Future<Boolean> future2 = executor.submit(callable);
+            try {
+                // 1st thread should acquire the lock
+                Assert.assertTrue(future1.get(3 + CRITICAL_SECTION_WAIT_TIMEOUT, TimeUnit.SECONDS));
+                // 2nd thread should fail waiting for critical section
+                Assert.assertFalse(future2.get(2 + CRITICAL_SECTION_WAIT_TIMEOUT, TimeUnit.SECONDS));
+            } finally {
+                future2.cancel(true);
+            }
+        } finally {
+            future1.cancel(true);
+            setSynchronizer(null);
+        }
+    }
+}