Updating licenses in all files
[appc.git] / appc-dispatcher / appc-dispatcher-common / lock-manager-lib / lock-manager-impl / src / main / java / org / openecomp / appc / lockmanager / impl / sql / pessimistic / SqlLockManager.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * APPC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright (C) 2017 Amdocs
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
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
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=========================================================
20  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  */
22
23 package org.openecomp.appc.lockmanager.impl.sql.pessimistic;
24
25 import java.sql.Connection;
26 import java.sql.PreparedStatement;
27 import java.sql.ResultSet;
28 import java.sql.SQLException;
29
30 import org.openecomp.appc.lockmanager.api.LockException;
31 import org.openecomp.appc.lockmanager.api.LockRuntimeException;
32 import org.openecomp.appc.lockmanager.impl.sql.JdbcLockManager;
33 import org.openecomp.appc.lockmanager.impl.sql.Messages;
34
35 abstract class SqlLockManager extends JdbcLockManager {
36
37         private static final String SQL_LOAD_LOCK_RECORD = "SELECT * FROM %s WHERE RESOURCE_ID=?";
38         private static final String SQL_INSERT_LOCK_RECORD = "INSERT INTO %s (RESOURCE_ID, OWNER_ID, UPDATED, TIMEOUT) VALUES (?, ?, ?, ?)";
39         private static final String SQL_UPDATE_LOCK_RECORD = "UPDATE %s SET OWNER_ID=?, UPDATED=?, TIMEOUT=? WHERE RESOURCE_ID=?";
40         private static final String SQL_CURRENT_TIMESTAMP = "SELECT CURRENT_TIMESTAMP()";
41
42         private String sqlLoadLockRecord;
43         private String sqlInsertLockRecord;
44         private String sqlUpdateLockRecord;
45
46         @Override
47         public boolean acquireLock(String resource, String owner) throws LockException {
48                 return acquireLock(resource, owner, 0);
49         }
50
51         @Override
52         public boolean acquireLock(String resource, String owner, long timeout) throws LockException {
53                 if(owner == null) {
54                         throw new LockRuntimeException(Messages.ERR_NULL_LOCK_OWNER.format(resource));
55                 }
56                 boolean res = false;
57                 Connection connection = openDbConnection();
58                 try {
59                         enterCriticalSection(connection, resource);
60                         try {
61                                 res = lockResource(connection, resource, owner, timeout);
62                         } finally {
63                                 leaveCriticalSection(connection, resource);
64                         }
65                 } finally {
66                         closeDbConnection(connection);
67                 }
68                 return res;
69         }
70
71         @Override
72         public void releaseLock(String resource, String owner) throws LockException {
73                 Connection connection = openDbConnection();
74                 try {
75                         enterCriticalSection(connection, resource);
76                         try {
77                                 unlockResource(connection, resource, owner);
78                         } finally {
79                                 leaveCriticalSection(connection, resource);
80                         }
81                 } finally {
82                         closeDbConnection(connection);
83                 }
84         }
85
86         @Override
87         public boolean isLocked(String resource) {
88                 Connection connection=openDbConnection();
89                 try {
90                         LockRecord lockRecord=loadLockRecord(connection,resource);
91                         if(lockRecord==null){
92                                 return false;
93                         }else{
94                                 if(lockRecord.getOwner()==null){
95                                         return false;
96                                 }else if(isLockExpired(lockRecord, connection)){
97                                         return false;
98                                 }else{
99                                         return true;
100                                 }
101                         }
102                 } catch (SQLException e) {
103                         throw new LockRuntimeException(Messages.EXP_CHECK_LOCK.format(resource));
104                 }finally {
105                         closeDbConnection(connection);
106                 }
107         }
108
109         private boolean lockResource(Connection connection, String resource, String owner, long timeout) throws LockException {
110                 try {
111                         boolean res = false;
112                         LockRecord lockRecord = loadLockRecord(connection, resource);
113                         if(lockRecord != null) {
114                                 // lock record already exists
115                                 String currentOwner = lockRecord.getOwner();
116                                 if(currentOwner != null) {
117                                         if(isLockExpired(lockRecord, connection)) {
118                                                 currentOwner = null;
119                                         } else if(!owner.equals(currentOwner)) {
120                                                 throw new LockException(Messages.ERR_LOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner));
121                                         }
122                                 }
123                                 // set new owner on the resource lock record
124                                 updateLockRecord(connection, resource, owner, timeout);
125                                 if(currentOwner == null) {
126                                         // no one locked the resource before
127                                         res = true;
128                                 }
129                         } else {
130                                 // resource record does not exist in lock table => create new record
131                                 addLockRecord(connection, resource, owner, timeout);
132                                 res = true;
133                         }
134                         return res;
135                 } catch(SQLException e) {
136                         throw new LockRuntimeException(Messages.EXP_LOCK.format(resource), e);
137                 }
138         }
139
140         private void unlockResource(Connection connection, String resource, String owner) throws LockException {
141                 try {
142                         LockRecord lockRecord = loadLockRecord(connection, resource);
143                         if(lockRecord != null) {
144                                 // check if expired
145                                 if(isLockExpired(lockRecord, connection)) {
146                                         // lock is expired => no lock
147                                         lockRecord = null;
148                                 }
149                         }
150                         if((lockRecord == null) || (lockRecord.getOwner() == null)) {
151                                 // resource is not locked
152                                 throw new LockException(Messages.ERR_UNLOCK_NOT_LOCKED.format(resource));
153                         }
154                         String currentOwner = lockRecord.getOwner();
155                         if(!owner.equals(currentOwner)) {
156                                 throw new LockException(Messages.ERR_UNLOCK_LOCKED_BY_OTHER.format(resource, owner, currentOwner));
157                         }
158                         updateLockRecord(connection, resource, null, 0);
159                         // TODO delete record from table on lock release?
160 //                      deleteLockRecord(connection, resource);
161                 } catch(SQLException e) {
162                         throw new LockRuntimeException(Messages.EXP_UNLOCK.format(resource), e);
163                 }
164         }
165
166         protected abstract void enterCriticalSection(Connection connection, String resource);
167
168         protected abstract void leaveCriticalSection(Connection connection, String resource);
169
170         protected LockRecord loadLockRecord(Connection connection, String resource) throws SQLException {
171                 LockRecord res = null;
172                 if(sqlLoadLockRecord == null) {
173                         sqlLoadLockRecord = String.format(SQL_LOAD_LOCK_RECORD, tableName);
174                 }
175                 try(PreparedStatement statement = connection.prepareStatement(sqlLoadLockRecord)) {
176                         statement.setString(1, resource);
177                         try(ResultSet resultSet = statement.executeQuery()) {
178                                 if(resultSet.next()) {
179                                         res = new LockRecord(resource);
180                                         res.setOwner(resultSet.getString(2));
181                                         res.setUpdated(resultSet.getLong(3));
182                                         res.setTimeout(resultSet.getLong(4));
183                                 }
184                         }
185                 }
186                 return res;
187         }
188
189         protected void addLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
190                 if(sqlInsertLockRecord == null) {
191                         sqlInsertLockRecord = String.format(SQL_INSERT_LOCK_RECORD, tableName);
192                 }
193                 try(PreparedStatement statement = connection.prepareStatement(sqlInsertLockRecord)) {
194                         statement.setString(1, resource);
195                         statement.setString(2, owner);
196                         statement.setLong(3, getCurrentTime(connection));
197                         statement.setLong(4, timeout);
198                         statement.executeUpdate();
199                 }
200         }
201
202         protected void updateLockRecord(Connection connection, String resource, String owner, long timeout) throws SQLException {
203                 if(sqlUpdateLockRecord == null) {
204                         sqlUpdateLockRecord = String.format(SQL_UPDATE_LOCK_RECORD, tableName);
205                 }
206                 try(PreparedStatement statement = connection.prepareStatement(sqlUpdateLockRecord)) {
207                         statement.setString(1, owner);
208                         statement.setLong(2, getCurrentTime(connection));
209                         statement.setLong(3, timeout);
210                         statement.setString(4, resource);
211                         statement.executeUpdate();
212                 }
213         }
214
215 //      protected void deleteLockRecord(Connection connection, String resource) throws SQLException {
216 //              if(sqlDeleteLockRecord == null) {
217 //                      sqlDeleteLockRecord = String.format(SQL_DELETE_LOCK_RECORD, tableName);
218 //              }
219 //              try(PreparedStatement statement = connection.prepareStatement(sqlDeleteLockRecord)) {
220 //                      statement.setString(1, resource);
221 //                      statement.executeUpdate();
222 //              }
223 //      }
224
225         private boolean isLockExpired(LockRecord lockRecord, Connection connection) throws SQLException {
226                 long timeout = lockRecord.getTimeout();
227                 if(timeout == 0) {
228                         return false;
229                 }
230                 long updated = lockRecord.getUpdated();
231                 long now = getCurrentTime(connection);
232                 long expiration = updated + timeout;
233                 return (now > expiration);
234         }
235
236         private long getCurrentTime(Connection connection) throws SQLException {
237                 long res = -1;
238                 if(connection != null) {
239                         try(PreparedStatement statement = connection.prepareStatement(SQL_CURRENT_TIMESTAMP)) {
240                                 try(ResultSet resultSet = statement.executeQuery()) {
241                                         if(resultSet.next()) {
242                                                 res = resultSet.getTimestamp(1).getTime();
243                                         }
244                                 }
245                         }
246                 }
247                 if(res == -1) {
248                         res = System.currentTimeMillis();
249                 }
250                 return res;
251         }
252 }