2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * ================================================================================
9 * Modifications Copyright (C) 2019 Ericsson
10 * =============================================================================
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
23 * ============LICENSE_END=========================================================
26 package org.onap.appc.lockmanager.impl.sql.pessimistic;
28 import java.sql.Connection;
29 import java.sql.PreparedStatement;
30 import java.sql.ResultSet;
31 import java.sql.SQLException;
33 import org.onap.appc.lockmanager.api.LockException;
34 import org.onap.appc.lockmanager.api.LockRuntimeException;
35 import org.onap.appc.lockmanager.impl.sql.JdbcLockManager;
36 import org.onap.appc.lockmanager.impl.sql.Messages;
38 abstract class SqlLockManager extends JdbcLockManager {
40 static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?";
41 static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT) VALUES (?, ?, ?, ?)";
42 static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=? WHERE RESOURCE_ID=?";
43 static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()";
45 private String sqlLoadLockRecord;
46 private String sqlInsertLockRecord;
47 private String sqlUpdateLockRecord;
50 public boolean acquireLock(String resource, String owner) throws LockException {
51 return acquireLock(resource, owner, 0);
55 public boolean acquireLock(String resource, String owner, long timeout) throws LockException {
57 throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource));
60 Connection connection = openDbConnection();
62 enterCriticalSection(connection, resource);
64 res = lockResource(connection, resource, owner, timeout);
66 leaveCriticalSection(connection, resource);
69 closeDbConnection(connection);
75 public void releaseLock(String resource, String owner) throws LockException {
76 Connection connection = openDbConnection();
78 enterCriticalSection(connection, resource);
80 unlockResource(connection, resource, owner);
82 leaveCriticalSection(connection, resource);
85 closeDbConnection(connection);
90 public boolean isLocked(String resource) {
91 Connection connection = openDbConnection();
93 LockRecord lockRecord = loadLockRecord(connection,resource);
94 if(lockRecord == null){
97 if(lockRecord.getOwner() == null){
99 }else if(isLockExpired(lockRecord, connection)){
105 } catch (SQLException e) {
106 throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource));
108 closeDbConnection(connection);
113 public String getLockOwner(String resource) {
114 Connection connection=openDbConnection();
116 org.onap.appc.lockmanager.impl.sql.pessimistic.LockRecord lockRecord=loadLockRecord(connection,resource);
117 if(lockRecord == null || lockRecord.getOwner() == null ){
120 if(isLockExpired(lockRecord, connection)){
123 return lockRecord.getOwner();
126 } catch (SQLException e) {
127 throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource));
129 closeDbConnection(connection);
133 private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException {
136 LockRecord lockRecord = loadLockRecord(connection, resource);
137 if(lockRecord != null) {
138 // lock record already exists
139 String currentOwner = lockRecord.getOwner();
140 if(currentOwner != null) {
141 if(isLockExpired(lockRecord, connection)) {
143 } else if(!owner.equals(currentOwner)) {
144 throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, currentOwner));
147 // set new owner on the resource lock record
148 updateLockRecord(connection, resource, owner, timeout);
149 if(currentOwner == null) {
150 // no one locked the resource before
154 // resource record does not exist in lock table => create new record
155 addLockRecord(connection, resource, owner, timeout);
159 } catch(SQLException e) {
160 throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e);
164 private void unlockResource(Connection connection, String resource, String owner) throws LockException {
166 LockRecord lockRecord = loadLockRecord(connection, resource);
167 if(lockRecord != null) {
169 if(isLockExpired(lockRecord, connection)) {
170 // lock is expired => no lock
174 if((lockRecord == null) || (lockRecord.getOwner() == null)) {
175 // resource is not locked
176 throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource));
178 String currentOwner = lockRecord.getOwner();
179 if(!owner.equals(currentOwner)) {
180 throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner));
182 updateLockRecord(connection, resource, null, 0);
183 // TODO delete record from table on lock release?
184 // deleteLockRecord(connection, resource);
185 } catch(SQLException e) {
186 throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e);
190 protected abstract void enterCriticalSection(Connection connection, String resource);
192 protected abstract void leaveCriticalSection(Connection connection, String resource);
194 protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException {
195 LockRecord res = null;
196 if(sqlLoadLockRecord == null) {
197 sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName);
199 try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) {
200 statement.setString(1, resource);
201 try(ResultSet resultSet = statement.executeQuery()) {
202 if(resultSet.next()) {
203 res = new LockRecord(resource);
204 res.setOwner(resultSet.getString(2));
205 res.setUpdated(resultSet.getLong(3));
206 res.setTimeout(resultSet.getLong(4));
213 protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
214 if(sqlInsertLockRecord == null) {
215 sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName);
217 try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) {
218 statement.setString(1, resource);
219 statement.setString(2, owner);
220 statement.setLong(3, getCurrentTime(connection));
221 statement.setLong(4, timeout);
222 statement.executeUpdate();
226 protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
227 if(sqlUpdateLockRecord == null) {
228 sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName);
230 try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) {
231 statement.setString(1, owner);
232 statement.setLong(2, getCurrentTime(connection));
233 statement.setLong(3, timeout);
234 statement.setString(4, resource);
235 statement.executeUpdate();
239 // protected void deleteLockRecord(Connection connection, String resource) throws SQLException {
240 // if(sqlDeleteLockRecord == null) {
241 // sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName);
243 // try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) {
244 // statement.setString(1, resource);
245 // statement.executeUpdate();
249 private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException {
250 long timeout = lockRecord.getTimeout();
254 long updated = lockRecord.getUpdated();
255 long now = getCurrentTime(connection);
256 long expiration = updated + timeout;
257 return (now > expiration);
260 private long getCurrentTime(Connection connection) throws SQLException {
262 if(connection != null) {
263 try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) {
264 try(ResultSet resultSet = statement.executeQuery()) {
265 if(resultSet.next()) {
266 res = resultSet.getTimestamp(1).getTime();
272 res = System.currentTimeMillis();