/*
* Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
* http://www.griddynamics.com
*
* This library is free software; you can redistribute it and/or modify it under the terms of
* the Apache License; either
* version 2.0 of the License, or any later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.griddynamics.jagger.coordinator.zookeeper;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.griddynamics.jagger.util.SerializationUtils.deserialize;
import static com.griddynamics.jagger.util.SerializationUtils.serialize;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import java.util.LinkedList;
import java.util.List;
/**
* Default implementation of {@link ZNode}
*/
public class ZNodeImpl implements ZNode {
private final IZookeeper zooKeeper;
private final String path;
private Logger logger = LoggerFactory.getLogger(ZNodeImpl.class);
public ZNodeImpl(IZookeeper zooKeeper, String path) {
this.zooKeeper = zooKeeper;
this.path = path;
}
@Override
public void addNodeWatcher(Watcher watcher) {
try {
zooKeeper.exists(path, watcher);
} catch (KeeperException e) {
throw new ZooException("Exception during watcher add", e);
} catch (InterruptedException e) {
throw new ZooException("Exception during watcher add", e);
}
}
@Override
public <T> T getObject(Class<T> clazz) {
return getObject(clazz, null);
}
@Override
public <T> T getObject(final Class<T> clazz, ClassLoader classLoader) {
if (classLoader == null) {
classLoader = this.getClass().getClassLoader();
}
Object object = deserialize(getData(), classLoader);
if (!clazz.isInstance(object)) {
logger.warn("getObject returns {} instead of {}", object != null ? object.getClass().getName() : "NULL", clazz.getName());
throw new IllegalStateException(object + " is not a type of " + clazz);
}
return clazz.cast(object);
}
@Override
public String getString() {
return new String(getData());
}
private byte[] getData() {
try {
return zooKeeper.getData(path, false, null);
} catch (KeeperException e) {
throw new ZooException("Exception during data retrieving", e);
} catch (InterruptedException e) {
throw new ZooException("Exception during data retrieving", e);
}
}
@Override
public void setString(String data) {
setData(data.getBytes());
}
@Override
public void setData(byte[] data) {
try {
zooKeeper.setData(path, data, -1);
} catch (KeeperException e) {
throw new ZooException("Exception during data filling", e);
} catch (InterruptedException e) {
throw new ZooException("Exception during data filling", e);
}
}
@Override
public void setObject(Object object) {
setData(serialize(object));
}
@Override
public boolean hasChild(String path, Watcher watcher) {
try {
return zooKeeper.exists(this.path + "/" + path, watcher) != null;
} catch (KeeperException e) {
throw new ZooException("Exception during existence check", e);
} catch (InterruptedException e) {
throw new ZooException("Exception during existence check", e);
}
}
@Override
public ZNode createChild(ZNodeParameters parameters) {
String path = checkNotNull(parameters.getPath());
parameters.withPath(this.path + "/" + path);
return ZNodeCreator.of(zooKeeper).create(parameters);
}
@Override
public ZNode child(String path) {
return new ZNodeImpl(zooKeeper, this.path + "/" + path);
}
@Override
public void removeChild(String path) {
try {
zooKeeper.delete(this.path + "/" + path, -1);
} catch (InterruptedException e) {
throw new ZooException("Exception during existence check", e);
} catch (KeeperException e) {
throw new ZooException("Exception during existence check", e);
}
}
@Override
public List<ZNode> children() {
return children(null);
}
@Override
public List<ZNode> children(Watcher watcher) {
try {
List<ZNode> result = new LinkedList<ZNode>();
String nodePath = path;
if (nodePath.length() == 0) {
nodePath = "/";
}
List<String> children = zooKeeper.getChildren(nodePath, watcher);
for (String child : children) {
result.add(new ZNodeImpl(zooKeeper, path + "/" + child));
}
return result;
} catch (KeeperException e) {
throw new ZooException("Exception during children checking", e);
} catch (InterruptedException e) {
throw new ZooException("Exception during children checking", e);
}
}
@Override
public List<ZNode> firstLevelChildren() {
return filterFirstLevel(children());
}
private List<ZNode> filterFirstLevel(List<ZNode> children) {
List<ZNode> result = Lists.newArrayList();
int rootCount = getPath().split("/").length;
for (ZNode child : children) {
if (child.getPath().split("/").length == (rootCount + 1)) {
result.add(child);
}
}
return result;
}
@Override
public List<ZNode> firstLevelChildren(Watcher watcher) {
return filterFirstLevel(children(watcher));
}
// not the best solution!
@Override
public void remove() {
try {
zooKeeper.delete(this.path, -1);
} catch (InterruptedException e) {
throw new ZooException("Exception during node removal", e);
} catch (KeeperException e) {
throw new ZooException("Exception during node removal", e);
}
}
@Override
public void removeWithChildren() {
for (ZNode zNode : children()) {
zNode.removeWithChildren();
}
remove();
}
@Override
public boolean hasChild(String childPath) {
try {
return zooKeeper.exists(this.path + "/" + childPath, false) != null;
} catch (KeeperException e) {
throw new ZooException("Exception child retrieval", e);
} catch (InterruptedException e) {
throw new ZooException("Exception child retrieval", e);
}
}
@Override
public String getPath() {
return path;
}
@Override
public String getShortPath() {
int index = path.lastIndexOf("/");
return path.substring(index + 1);
}
@Override
public ZNodeLock obtainLock() {
ZNodeLock lock = new DefaultZNodeLock(this);
if (!lock.isLockable()) {
lock.makeLockable();
}
return lock;
}
@Override
public void addChildrenWatcher(Watcher watcher) {
children(watcher);
}
@Override
public boolean exists() {
try {
return zooKeeper.exists(this.path, false) != null;
} catch (Exception e) {
throw new ZooException("Exception during watcher add", e);
}
}
@Override
public String toString() {
return "ZNodeImpl [path=" + path + "]";
}
}