/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.twill.internal.zookeeper; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import org.apache.twill.common.Threads; import org.apache.twill.zookeeper.ForwardingZKClient; import org.apache.twill.zookeeper.NodeChildren; import org.apache.twill.zookeeper.NodeData; import org.apache.twill.zookeeper.OperationFuture; import org.apache.twill.zookeeper.ZKClient; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.data.Stat; import javax.annotation.Nullable; /** * A {@link ZKClient} that namespace every paths. */ public final class NamespaceZKClient extends ForwardingZKClient { // This class extends from ForwardingZKClient but overrides every method is for letting the // ZKClientServices delegate logic works. private final String namespace; private final ZKClient delegate; private final String connectString; public NamespaceZKClient(ZKClient delegate, String namespace) { super(delegate); this.namespace = namespace; this.delegate = delegate; this.connectString = delegate.getConnectString() + namespace; } @Override public Long getSessionId() { return delegate.getSessionId(); } @Override public String getConnectString() { return connectString; } @Override public void addConnectionWatcher(Watcher watcher) { delegate.addConnectionWatcher(watcher); } @Override public OperationFuture<String> create(String path, @Nullable byte[] data, CreateMode createMode) { return relayPath(delegate.create(namespace + path, data, createMode), this.<String>createFuture(path)); } @Override public OperationFuture<String> create(String path, @Nullable byte[] data, CreateMode createMode, boolean createParent) { return relayPath(delegate.create(namespace + path, data, createMode, createParent), this.<String>createFuture(path)); } @Override public OperationFuture<Stat> exists(String path) { return relayFuture(delegate.exists(namespace + path), this.<Stat>createFuture(path)); } @Override public OperationFuture<Stat> exists(String path, @Nullable Watcher watcher) { return relayFuture(delegate.exists(namespace + path, watcher), this.<Stat>createFuture(path)); } @Override public OperationFuture<NodeChildren> getChildren(String path) { return relayFuture(delegate.getChildren(namespace + path), this.<NodeChildren>createFuture(path)); } @Override public OperationFuture<NodeChildren> getChildren(String path, @Nullable Watcher watcher) { return relayFuture(delegate.getChildren(namespace + path, watcher), this.<NodeChildren>createFuture(path)); } @Override public OperationFuture<NodeData> getData(String path) { return relayFuture(delegate.getData(namespace + path), this.<NodeData>createFuture(path)); } @Override public OperationFuture<NodeData> getData(String path, @Nullable Watcher watcher) { return relayFuture(delegate.getData(namespace + path, watcher), this.<NodeData>createFuture(path)); } @Override public OperationFuture<Stat> setData(String path, byte[] data) { return relayFuture(delegate.setData(namespace + path, data), this.<Stat>createFuture(path)); } @Override public OperationFuture<Stat> setData(String dataPath, byte[] data, int version) { return relayFuture(delegate.setData(namespace + dataPath, data, version), this.<Stat>createFuture(dataPath)); } @Override public OperationFuture<String> delete(String path) { return relayPath(delegate.delete(namespace + path), this.<String>createFuture(path)); } @Override public OperationFuture<String> delete(String deletePath, int version) { return relayPath(delegate.delete(namespace + deletePath, version), this.<String>createFuture(deletePath)); } private <V> SettableOperationFuture<V> createFuture(String path) { return SettableOperationFuture.create(namespace + path, Threads.SAME_THREAD_EXECUTOR); } private <V> OperationFuture<V> relayFuture(final OperationFuture<V> from, final SettableOperationFuture<V> to) { Futures.addCallback(from, new FutureCallback<V>() { @Override public void onSuccess(V result) { to.set(result); } @Override public void onFailure(Throwable t) { to.setException(t); } }); return to; } private OperationFuture<String> relayPath(final OperationFuture<String> from, final SettableOperationFuture<String> to) { from.addListener(new Runnable() { @Override public void run() { try { String path = from.get(); to.set(path.substring(namespace.length())); } catch (Exception e) { to.setException(e.getCause()); } } }, Threads.SAME_THREAD_EXECUTOR); return to; } }