2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.appc.lockmanager.impl.sql.pessimistic;
24 import java.sql.Connection;
25 import java.sql.PreparedStatement;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
29 import org.openecomp.appc.lockmanager.api.LockException;
30 import org.openecomp.appc.lockmanager.api.LockRuntimeException;
31 import org.openecomp.appc.lockmanager.impl.sql.JdbcLockManager;
32 import org.openecomp.appc.lockmanager.impl.sql.Messages;
34 abstract class SqlLockManager extends JdbcLockManager {
36 private static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?";
37 private static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT) VALUES (?, ?, ?, ?)";
38 private static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=? WHERE RESOURCE_ID=?";
39 private static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()";
41 private String sqlLoadLockRecord;
42 private String sqlInsertLockRecord;
43 private String sqlUpdateLockRecord;
46 public boolean acquireLock(String resource, String owner) throws LockException {
47 return acquireLock(resource, owner, 0);
51 public boolean acquireLock(String resource, String owner, long timeout) throws LockException {
53 throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource));
56 Connection connection = openDbConnection();
58 enterCriticalSection(connection, resource);
60 res = lockResource(connection, resource, owner, timeout);
62 leaveCriticalSection(connection, resource);
65 closeDbConnection(connection);
71 public void releaseLock(String resource, String owner) throws LockException {
72 Connection connection = openDbConnection();
74 enterCriticalSection(connection, resource);
76 unlockResource(connection, resource, owner);
78 leaveCriticalSection(connection, resource);
81 closeDbConnection(connection);
86 public boolean isLocked(String resource) {
87 Connection connection=openDbConnection();
89 LockRecord lockRecord=loadLockRecord(connection,resource);
93 if(lockRecord.getOwner()==null){
95 }else if(isLockExpired(lockRecord, connection)){
101 } catch (SQLException e) {
102 throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource));
104 closeDbConnection(connection);
108 private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException {
111 LockRecord lockRecord = loadLockRecord(connection, resource);
112 if(lockRecord != null) {
113 // lock record already exists
114 String currentOwner = lockRecord.getOwner();
115 if(currentOwner != null) {
116 if(isLockExpired(lockRecord, connection)) {
118 } else if(!owner.equals(currentOwner)) {
119 throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner));
122 // set new owner on the resource lock record
123 updateLockRecord(connection, resource, owner, timeout);
124 if(currentOwner == null) {
125 // no one locked the resource before
129 // resource record does not exist in lock table => create new record
130 addLockRecord(connection, resource, owner, timeout);
134 } catch(SQLException e) {
135 throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e);
139 private void unlockResource(Connection connection, String resource, String owner) throws LockException {
141 LockRecord lockRecord = loadLockRecord(connection, resource);
142 if(lockRecord != null) {
144 if(isLockExpired(lockRecord, connection)) {
145 // lock is expired => no lock
149 if((lockRecord == null) || (lockRecord.getOwner() == null)) {
150 // resource is not locked
151 throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource));
153 String currentOwner = lockRecord.getOwner();
154 if(!owner.equals(currentOwner)) {
155 throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner));
157 updateLockRecord(connection, resource, null, 0);
158 // TODO delete record from table on lock release?
159 // deleteLockRecord(connection, resource);
160 } catch(SQLException e) {
161 throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e);
165 protected abstract void enterCriticalSection(Connection connection, String resource);
167 protected abstract void leaveCriticalSection(Connection connection, String resource);
169 protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException {
170 LockRecord res = null;
171 if(sqlLoadLockRecord == null) {
172 sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName);
174 try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) {
175 statement.setString(1, resource);
176 try(ResultSet resultSet = statement.executeQuery()) {
177 if(resultSet.next()) {
178 res = new LockRecord(resource);
179 res.setOwner(resultSet.getString(2));
180 res.setUpdated(resultSet.getLong(3));
181 res.setTimeout(resultSet.getLong(4));
188 protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
189 if(sqlInsertLockRecord == null) {
190 sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName);
192 try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) {
193 statement.setString(1, resource);
194 statement.setString(2, owner);
195 statement.setLong(3, getCurrentTime(connection));
196 statement.setLong(4, timeout);
197 statement.executeUpdate();
201 protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
202 if(sqlUpdateLockRecord == null) {
203 sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName);
205 try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) {
206 statement.setString(1, owner);
207 statement.setLong(2, getCurrentTime(connection));
208 statement.setLong(3, timeout);
209 statement.setString(4, resource);
210 statement.executeUpdate();
214 // protected void deleteLockRecord(Connection connection, String resource) throws SQLException {
215 // if(sqlDeleteLockRecord == null) {
216 // sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName);
218 // try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) {
219 // statement.setString(1, resource);
220 // statement.executeUpdate();
224 private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException {
225 long timeout = lockRecord.getTimeout();
229 long updated = lockRecord.getUpdated();
230 long now = getCurrentTime(connection);
231 long expiration = updated + timeout;
232 return (now > expiration);
235 private long getCurrentTime(Connection connection) throws SQLException {
237 if(connection != null) {
238 try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) {
239 try(ResultSet resultSet = statement.executeQuery()) {
240 if(resultSet.next()) {
241 res = resultSet.getTimestamp(1).getTime();
247 res = System.currentTimeMillis();