Autopsy  4.4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
CoordinationService.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2017 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
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 package org.sleuthkit.autopsy.coordinationservice;
20 
21 import java.io.IOException;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.TimeUnit;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30 import javax.annotation.concurrent.GuardedBy;
31 import javax.annotation.concurrent.ThreadSafe;
32 import org.apache.curator.RetryPolicy;
33 import org.apache.curator.framework.CuratorFramework;
34 import org.apache.curator.framework.CuratorFrameworkFactory;
35 import org.apache.curator.framework.recipes.locks.InterProcessMutex;
36 import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
37 import org.apache.curator.retry.ExponentialBackoffRetry;
38 import org.apache.zookeeper.CreateMode;
39 import org.apache.zookeeper.KeeperException;
40 import org.apache.zookeeper.KeeperException.NoNodeException;
41 import org.apache.zookeeper.WatchedEvent;
42 import org.apache.zookeeper.ZooDefs;
43 import org.apache.zookeeper.ZooKeeper;
44 import org.openide.util.Lookup;
46 
52 @ThreadSafe
53 public final class CoordinationService {
54 
55  private static final int SESSION_TIMEOUT_MILLISECONDS = 300000;
56  private static final int CONNECTION_TIMEOUT_MILLISECONDS = 300000;
57  private static final int ZOOKEEPER_SESSION_TIMEOUT_MILLIS = 3000;
58  private static final int ZOOKEEPER_CONNECTION_TIMEOUT_MILLIS = 15000;
59  private static final int PORT_OFFSET = 1000; // When run in Solr, ZooKeeper defaults to Solr port + 1000
60  private static final String DEFAULT_NAMESPACE_ROOT = "autopsy";
61  @GuardedBy("CoordinationService.class")
62  private static CoordinationService instance;
63  private final CuratorFramework curator;
64  @GuardedBy("categoryNodeToPath")
65  private final Map<String, String> categoryNodeToPath;
66 
76  private static boolean isZooKeeperAccessible() throws InterruptedException, IOException {
77  boolean result = false;
78  Object workerThreadWaitNotifyLock = new Object();
79  int zooKeeperServerPort = Integer.valueOf(UserPreferences.getIndexingServerPort()) + PORT_OFFSET;
80  String connectString = UserPreferences.getIndexingServerHost() + ":" + zooKeeperServerPort;
81  ZooKeeper zooKeeper = new ZooKeeper(connectString, ZOOKEEPER_SESSION_TIMEOUT_MILLIS,
82  (WatchedEvent event) -> {
83  synchronized (workerThreadWaitNotifyLock) {
84  workerThreadWaitNotifyLock.notify();
85  }
86  });
87  synchronized (workerThreadWaitNotifyLock) {
88  workerThreadWaitNotifyLock.wait(ZOOKEEPER_CONNECTION_TIMEOUT_MILLIS);
89  }
90  ZooKeeper.States state = zooKeeper.getState();
91  if (state == ZooKeeper.States.CONNECTED || state == ZooKeeper.States.CONNECTEDREADONLY) {
92  result = true;
93  }
94  zooKeeper.close();
95  return result;
96  }
97 
107  public synchronized static CoordinationService getInstance() throws CoordinationServiceException {
108  if (null == instance) {
109  String rootNode;
110  Collection<? extends CoordinationServiceNamespace> providers = Lookup.getDefault().lookupAll(CoordinationServiceNamespace.class);
111  Iterator<? extends CoordinationServiceNamespace> it = providers.iterator();
112  if (it.hasNext()) {
113  rootNode = it.next().getNamespaceRoot();
114  } else {
115  rootNode = DEFAULT_NAMESPACE_ROOT;
116  }
117  try {
118  instance = new CoordinationService(rootNode);
119  } catch (IOException | InterruptedException | KeeperException | CoordinationServiceException ex) {
120  throw new CoordinationServiceException("Failed to create coordination service", ex);
121  }
122  }
123  return instance;
124  }
125 
135  private CoordinationService(String rootNodeName) throws InterruptedException, IOException, KeeperException, CoordinationServiceException {
136 
137  if (false == isZooKeeperAccessible()) {
138  throw new CoordinationServiceException("Unable to access ZooKeeper");
139  }
140 
141  /*
142  * Connect to ZooKeeper via Curator.
143  */
144  RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
145  int zooKeeperServerPort = Integer.valueOf(UserPreferences.getIndexingServerPort()) + PORT_OFFSET;
146  String connectString = UserPreferences.getIndexingServerHost() + ":" + zooKeeperServerPort;
147  curator = CuratorFrameworkFactory.newClient(connectString, SESSION_TIMEOUT_MILLISECONDS, CONNECTION_TIMEOUT_MILLISECONDS, retryPolicy);
148  curator.start();
149 
150  /*
151  * Create the top-level root and category nodes.
152  */
153  String rootNode = rootNodeName;
154 
155  if (!rootNode.startsWith("/")) {
156  rootNode = "/" + rootNode;
157  }
158  categoryNodeToPath = new ConcurrentHashMap<>();
159  for (CategoryNode node : CategoryNode.values()) {
160  String nodePath = rootNode + "/" + node.getDisplayName();
161  try {
162  curator.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE).forPath(nodePath);
163  } catch (KeeperException ex) {
164  if (ex.code() != KeeperException.Code.NODEEXISTS) {
165  throw ex;
166  }
167  } catch (Exception ex) {
168  throw new CoordinationServiceException("Curator experienced an error", ex);
169  }
170  categoryNodeToPath.put(node.getDisplayName(), nodePath);
171  }
172  }
173 
194  public Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit) throws CoordinationServiceException, InterruptedException {
195  String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
196  try {
197  InterProcessReadWriteLock lock = new InterProcessReadWriteLock(curator, fullNodePath);
198  if (lock.writeLock().acquire(timeOut, timeUnit)) {
199  return new Lock(nodePath, lock.writeLock());
200  } else {
201  return null;
202  }
203  } catch (Exception ex) {
204  if (ex instanceof InterruptedException) {
205  throw (InterruptedException) ex;
206  } else {
207  throw new CoordinationServiceException(String.format("Failed to get exclusive lock for %s", fullNodePath), ex);
208  }
209  }
210  }
211 
228  public Lock tryGetExclusiveLock(CategoryNode category, String nodePath) throws CoordinationServiceException {
229  String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
230  try {
231  InterProcessReadWriteLock lock = new InterProcessReadWriteLock(curator, fullNodePath);
232  if (!lock.writeLock().acquire(0, TimeUnit.SECONDS)) {
233  return null;
234  }
235  return new Lock(nodePath, lock.writeLock());
236  } catch (Exception ex) {
237  throw new CoordinationServiceException(String.format("Failed to get exclusive lock for %s", fullNodePath), ex);
238  }
239  }
240 
261  public Lock tryGetSharedLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit) throws CoordinationServiceException, InterruptedException {
262  String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
263  try {
264  InterProcessReadWriteLock lock = new InterProcessReadWriteLock(curator, fullNodePath);
265  if (lock.readLock().acquire(timeOut, timeUnit)) {
266  return new Lock(nodePath, lock.readLock());
267  } else {
268  return null;
269  }
270  } catch (Exception ex) {
271  if (ex instanceof InterruptedException) {
272  throw (InterruptedException) ex;
273  } else {
274  throw new CoordinationServiceException(String.format("Failed to get shared lock for %s", fullNodePath), ex);
275  }
276  }
277  }
278 
295  public Lock tryGetSharedLock(CategoryNode category, String nodePath) throws CoordinationServiceException {
296  String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
297  try {
298  InterProcessReadWriteLock lock = new InterProcessReadWriteLock(curator, fullNodePath);
299  if (!lock.readLock().acquire(0, TimeUnit.SECONDS)) {
300  return null;
301  }
302  return new Lock(nodePath, lock.readLock());
303  } catch (Exception ex) {
304  throw new CoordinationServiceException(String.format("Failed to get shared lock for %s", fullNodePath), ex);
305  }
306  }
307 
322  public byte[] getNodeData(CategoryNode category, String nodePath) throws CoordinationServiceException, InterruptedException {
323  String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
324  try {
325  return curator.getData().forPath(fullNodePath);
326  } catch (NoNodeException ex) {
327  return null;
328  } catch (Exception ex) {
329  if (ex instanceof InterruptedException) {
330  throw (InterruptedException) ex;
331  } else {
332  throw new CoordinationServiceException(String.format("Failed to get data for %s", fullNodePath), ex);
333  }
334  }
335  }
336 
349  public void setNodeData(CategoryNode category, String nodePath, byte[] data) throws CoordinationServiceException, InterruptedException {
350  String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
351  try {
352  curator.setData().forPath(fullNodePath, data);
353  } catch (Exception ex) {
354  if (ex instanceof InterruptedException) {
355  throw (InterruptedException) ex;
356  } else {
357  throw new CoordinationServiceException(String.format("Failed to set data for %s", fullNodePath), ex);
358  }
359  }
360  }
361 
372  public List<String> getNodeList(CategoryNode category) throws CoordinationServiceException {
373  try {
374  List<String> list = curator.getChildren().forPath(categoryNodeToPath.get(category.getDisplayName()));
375  return list;
376  } catch (Exception ex) {
377  throw new CoordinationServiceException(String.format("Failed to get node list for %s", category.getDisplayName()), ex);
378  }
379  }
380 
389  private String getFullyQualifiedNodePath(CategoryNode category, String nodePath) {
390  return categoryNodeToPath.get(category.getDisplayName()) + "/" + nodePath.toUpperCase();
391  }
392 
396  public final static class CoordinationServiceException extends Exception {
397 
398  private static final long serialVersionUID = 1L;
399 
400  private CoordinationServiceException(String message) {
401  super(message);
402  }
403 
404  private CoordinationServiceException(String message, Throwable cause) {
405  super(message, cause);
406  }
407  }
408 
414  public static class Lock implements AutoCloseable {
415 
420  private final InterProcessMutex interProcessLock;
421  private final String nodePath;
422 
423  private Lock(String nodePath, InterProcessMutex lock) {
424  this.nodePath = nodePath;
425  this.interProcessLock = lock;
426  }
427 
428  public String getNodePath() {
429  return nodePath;
430  }
431 
432  public void release() throws CoordinationServiceException {
433  try {
434  this.interProcessLock.release();
435  } catch (Exception ex) {
436  throw new CoordinationServiceException(String.format("Failed to release the lock on %s", nodePath), ex);
437  }
438  }
439 
440  @Override
441  public void close() throws CoordinationServiceException {
442  release();
443  }
444  }
445 
450  public enum CategoryNode {
451 
452  CASES("cases"),
453  MANIFESTS("manifests"),
454  CONFIG("config");
455 
456  private final String displayName;
457 
458  private CategoryNode(String displayName) {
459  this.displayName = displayName;
460  }
461 
462  public String getDisplayName() {
463  return displayName;
464  }
465  }
466 }
Lock tryGetExclusiveLock(CategoryNode category, String nodePath)
byte[] getNodeData(CategoryNode category, String nodePath)
String getFullyQualifiedNodePath(CategoryNode category, String nodePath)
Lock tryGetSharedLock(CategoryNode category, String nodePath)
Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
void setNodeData(CategoryNode category, String nodePath, byte[] data)
Lock tryGetSharedLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)

Copyright © 2012-2016 Basis Technology. Generated on: Fri Sep 29 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.