2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ============LICENSE_END=========================================================
24 package org.onap.appc.lockmanager.impl.sql.pessimistic;
26 import java.sql.Connection;
27 import java.sql.PreparedStatement;
28 import java.sql.ResultSet;
29 import java.sql.SQLException;
31 import org.onap.appc.lockmanager.api.LockException;
32 import org.onap.appc.lockmanager.api.LockRuntimeException;
33 import org.onap.appc.lockmanager.impl.sql.JdbcLockManager;
34 import org.onap.appc.lockmanager.impl.sql.Messages;
36 abstract class SqlLockManager extends JdbcLockManager {
38 private static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?";
39 private static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT) VALUES (?, ?, ?, ?)";
40 private static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=? WHERE RESOURCE_ID=?";
41 private static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()";
43 private String sqlLoadLockRecord;
44 private String sqlInsertLockRecord;
45 private String sqlUpdateLockRecord;
48 public boolean acquireLock(String resource, String owner) throws LockException {
49 return acquireLock(resource, owner, 0);
53 public boolean acquireLock(String resource, String owner, long timeout) throws LockException {
55 throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource));
58 Connection connection = openDbConnection();
60 enterCriticalSection(connection, resource);
62 res = lockResource(connection, resource, owner, timeout);
64 leaveCriticalSection(connection, resource);
67 closeDbConnection(connection);
73 public void releaseLock(String resource, String owner) throws LockException {
74 Connection connection = openDbConnection();
76 enterCriticalSection(connection, resource);
78 unlockResource(connection, resource, owner);
80 leaveCriticalSection(connection, resource);
83 closeDbConnection(connection);
88 public boolean isLocked(String resource) {
89 Connection connection=openDbConnection();
91 LockRecord lockRecord=loadLockRecord(connection,resource);
95 if(lockRecord.getOwner()==null){
97 }else if(isLockExpired(lockRecord, connection)){
103 } catch (SQLException e) {
104 throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource));
106 closeDbConnection(connection);
111 public String getLockOwner(String resource) {
112 Connection connection=openDbConnection();
114 org.onap.appc.lockmanager.impl.sql.pessimistic.LockRecord lockRecord=loadLockRecord(connection,resource);
115 if(lockRecord==null || lockRecord.getOwner() ==null ){
118 if(isLockExpired(lockRecord, connection)){
121 return lockRecord.getOwner();
124 } catch (SQLException e) {
125 throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource));
127 closeDbConnection(connection);
131 private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException {
134 LockRecord lockRecord = loadLockRecord(connection, resource);
135 if(lockRecord != null) {
136 // lock record already exists
137 String currentOwner = lockRecord.getOwner();
138 if(currentOwner != null) {
139 if(isLockExpired(lockRecord, connection)) {
141 } else if(!owner.equals(currentOwner)) {
142 throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, currentOwner));
145 // set new owner on the resource lock record
146 updateLockRecord(connection, resource, owner, timeout);
147 if(currentOwner == null) {
148 // no one locked the resource before
152 // resource record does not exist in lock table => create new record
153 addLockRecord(connection, resource, owner, timeout);
157 } catch(SQLException e) {
158 throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e);
162 private void unlockResource(Connection connection, String resource, String owner) throws LockException {
164 LockRecord lockRecord = loadLockRecord(connection, resource);
165 if(lockRecord != null) {
167 if(isLockExpired(lockRecord, connection)) {
168 // lock is expired => no lock
172 if((lockRecord == null) || (lockRecord.getOwner() == null)) {
173 // resource is not locked
174 throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource));
176 String currentOwner = lockRecord.getOwner();
177 if(!owner.equals(currentOwner)) {
178 throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner));
180 updateLockRecord(connection, resource, null, 0);
181 // TODO delete record from table on lock release?
182 // deleteLockRecord(connection, resource);
183 } catch(SQLException e) {
184 throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e);
188 protected abstract void enterCriticalSection(Connection connection, String resource);
190 protected abstract void leaveCriticalSection(Connection connection, String resource);
192 protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException {
193 LockRecord res = null;
194 if(sqlLoadLockRecord == null) {
195 sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName);
197 try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) {
198 statement.setString(1, resource);
199 try(ResultSet resultSet = statement.executeQuery()) {
200 if(resultSet.next()) {
201 res = new LockRecord(resource);
202 res.setOwner(resultSet.getString(2));
203 res.setUpdated(resultSet.getLong(3));
204 res.setTimeout(resultSet.getLong(4));
211 protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
212 if(sqlInsertLockRecord == null) {
213 sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName);
215 try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) {
216 statement.setString(1, resource);
217 statement.setString(2, owner);
218 statement.setLong(3, getCurrentTime(connection));
219 statement.setLong(4, timeout);
220 statement.executeUpdate();
224 protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
225 if(sqlUpdateLockRecord == null) {
226 sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName);
228 try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) {
229 statement.setString(1, owner);
230 statement.setLong(2, getCurrentTime(connection));
231 statement.setLong(3, timeout);
232 statement.setString(4, resource);
233 statement.executeUpdate();
237 // protected void deleteLockRecord(Connection connection, String resource) throws SQLException {
238 // if(sqlDeleteLockRecord == null) {
239 // sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName);
241 // try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) {
242 // statement.setString(1, resource);
243 // statement.executeUpdate();
247 private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException {
248 long timeout = lockRecord.getTimeout();
252 long updated = lockRecord.getUpdated();
253 long now = getCurrentTime(connection);
254 long expiration = updated + timeout;
255 return (now > expiration);
258 private long getCurrentTime(Connection connection) throws SQLException {
260 if(connection != null) {
261 try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) {
262 try(ResultSet resultSet = statement.executeQuery()) {
263 if(resultSet.next()) {
264 res = resultSet.getTimestamp(1).getTime();
270 res = System.currentTimeMillis();