Some Sonar and CLM issues resolved.
[music.git] / src / main / java / org / onap / music / lockingservice / ProtocolSupport.java
1 /*
2  * ============LICENSE_START==========================================
3  * org.onap.music
4  * ===================================================================
5  *  Copyright (c) 2017 AT&T Intellectual Property
6  * ===================================================================
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  * 
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  * 
19  * ============LICENSE_END=============================================
20  * ====================================================================
21  */
22 package org.onap.music.lockingservice;
23
24 import org.apache.zookeeper.CreateMode;
25 import org.apache.zookeeper.KeeperException;
26 import org.apache.zookeeper.ZooDefs;
27 import org.apache.zookeeper.ZooKeeper;
28 import org.apache.zookeeper.data.ACL;
29 import org.apache.zookeeper.data.Stat;
30 import org.onap.music.eelf.logging.EELFLoggerDelegate;
31 import org.onap.music.lockingservice.ZooKeeperOperation;
32 import java.util.List;
33 import java.util.concurrent.atomic.AtomicBoolean;
34
35 /**
36  * A base class for protocol implementations which provides a number of higher level helper methods
37  * for working with ZooKeeper along with retrying synchronous operations if the connection to
38  * ZooKeeper closes such as {@link #retryOperation(ZooKeeperOperation)}
39  *
40  */
41 class ProtocolSupport {
42     private EELFLoggerDelegate LOG = EELFLoggerDelegate.getLogger(ProtocolSupport.class);
43
44     protected ZooKeeper zookeeper;
45     private AtomicBoolean closed = new AtomicBoolean(false);
46     private long retryDelay = 500L;
47     private int retryCount = 10;
48     private List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;
49
50     /**
51      * Closes this strategy and releases any ZooKeeper resources; but keeps the ZooKeeper instance
52      * open
53      */
54     public void close() {
55         if (closed.compareAndSet(false, true)) {
56             doClose();
57         }
58     }
59
60     /**
61      * return zookeeper client instance
62      * 
63      * @return zookeeper client instance
64      */
65     public ZooKeeper getZookeeper() {
66         return zookeeper;
67     }
68
69     /**
70      * return the acl its using
71      * 
72      * @return the acl.
73      */
74     public List<ACL> getAcl() {
75         return acl;
76     }
77
78     /**
79      * set the acl
80      * 
81      * @param acl the acl to set to
82      */
83     public void setAcl(List<ACL> acl) {
84         this.acl = acl;
85     }
86
87     /**
88      * get the retry delay in milliseconds
89      * 
90      * @return the retry delay
91      */
92     public long getRetryDelay() {
93         return retryDelay;
94     }
95
96     /**
97      * Sets the time waited between retry delays
98      * 
99      * @param retryDelay the retry delay
100      */
101     public void setRetryDelay(long retryDelay) {
102         this.retryDelay = retryDelay;
103     }
104
105     /**
106      * Allow derived classes to perform some custom closing operations to release resources
107      */
108     protected void doClose() {
109         throw new UnsupportedOperationException();
110     }
111
112
113     /**
114      * Perform the given operation, retrying if the connection fails
115      * 
116      * @return object. it needs to be cast to the callee's expected return type.
117      * @param operation FILL IN
118      * @throws KeeperException FILL IN
119      * @throws InterruptedException FILL IN
120      */
121     protected Object retryOperation(ZooKeeperOperation operation)
122                     throws KeeperException, InterruptedException {
123         KeeperException exception = null;
124         for (int i = 0; i < retryCount; i++) {
125             try {
126                 return operation.execute();
127             } catch (KeeperException.SessionExpiredException e) {
128                 LOG.debug("Session expired for: " + zookeeper + " so reconnecting due to: " + e, e);
129                 throw e;
130             } catch (KeeperException.ConnectionLossException e) {
131                 if (exception == null) {
132                     exception = e;
133                 }
134                 LOG.debug("Attempt " + i + " failed with connection loss so "
135                                 + "attempting to reconnect: " + e, e);
136                 retryDelay(i);
137             }
138         }
139         throw exception;
140     }
141
142     /**
143      * Ensures that the given path exists with no data, the current ACL and no flags
144      * 
145      * @param path the lock path
146      */
147     protected void ensurePathExists(String path) {
148         ensureExists(path, null, acl, CreateMode.PERSISTENT);
149     }
150
151     /**
152      * Ensures that the given path exists with the given data, ACL and flags
153      * 
154      * @param path the lock path
155      * @param data the data
156      * @param acl list of ACLs applying to the path
157      * @param flags create mode flags
158      */
159     protected void ensureExists(final String path, final byte[] data, final List<ACL> acl,
160                     final CreateMode flags) {
161         try {
162             retryOperation(new ZooKeeperOperation() {
163                 public boolean execute() throws KeeperException, InterruptedException {
164                     Stat stat = zookeeper.exists(path, false);
165                     if (stat != null) {
166                         return true;
167                     }
168                     zookeeper.create(path, data, acl, flags);
169                     return true;
170                 }
171             });
172         } catch (InterruptedException|KeeperException e) {
173             LOG.error(EELFLoggerDelegate.errorLogger,"Caught: " + e, e);
174         }
175     }
176
177     /**
178      * Returns true if this protocol has been closed
179      * 
180      * @return true if this protocol is closed
181      */
182     protected boolean isClosed() {
183         return closed.get();
184     }
185
186     /**
187      * Performs a retry delay if this is not the first attempt
188      * 
189      * @param attemptCount the number of the attempts performed so far
190      */
191     protected void retryDelay(int attemptCount) {
192         if (attemptCount > 0) {
193             try {
194                 Thread.sleep(attemptCount * retryDelay);
195             } catch (InterruptedException e) {
196                 LOG.error(EELFLoggerDelegate.errorLogger,"Failed to sleep: " + e, e);
197                 Thread.currentThread().interrupt();
198             }
199         }
200     }
201 }