/**
* Copyright 2012 LiveRamp
*
* Licensed 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 com.liveramp.hank.coordinator.zk;
import com.liveramp.hank.coordinator.*;
import com.liveramp.hank.generated.DomainGroupMetadata;
import com.liveramp.hank.zookeeper.WatchedNodeListener;
import com.liveramp.hank.zookeeper.WatchedThriftNode;
import com.liveramp.hank.zookeeper.ZkPath;
import com.liveramp.hank.zookeeper.ZooKeeperPlus;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ZkDomainGroup extends AbstractDomainGroup implements DomainGroup {
private final ZooKeeperPlus zk;
private final Coordinator coordinator;
private final String name;
private final String path;
private final WatchedThriftNode<DomainGroupMetadata> metadata;
private final Set<DomainGroupListener> listeners = new HashSet<DomainGroupListener>();
public static ZkDomainGroup create(final ZooKeeperPlus zk,
final Coordinator coordinator,
final String rootPath,
final String name) throws InterruptedException, KeeperException, IOException {
String path = ZkPath.append(rootPath, name);
DomainGroupMetadata initialMetadata = new DomainGroupMetadata();
initialMetadata.set_domain_versions(new HashMap<Integer, Integer>());
return new ZkDomainGroup(zk, coordinator, path, true, initialMetadata);
}
public ZkDomainGroup(final ZooKeeperPlus zk,
final Coordinator coordinator,
final String path) throws IOException, InterruptedException, KeeperException {
this(zk, coordinator, path, false, null);
}
public ZkDomainGroup(final ZooKeeperPlus zk,
final Coordinator coordinator,
final String path,
final boolean create,
final DomainGroupMetadata initialMetadata)
throws InterruptedException, KeeperException, IOException {
this.zk = zk;
this.coordinator = coordinator;
this.path = path;
this.name = ZkPath.getFilename(path);
this.metadata = new WatchedThriftNode<DomainGroupMetadata>(zk, path, true, create ? CreateMode.PERSISTENT : null, initialMetadata, new DomainGroupMetadata());
this.metadata.addListener(new WatchedNodeListener<DomainGroupMetadata>() {
@Override
public void onWatchedNodeChange(DomainGroupMetadata value) {
synchronized (listeners) {
for (DomainGroupListener listener : listeners) {
listener.onDomainGroupChange(ZkDomainGroup.this);
}
}
}
});
}
@Override
public String getName() {
return name;
}
@Override
public Set<DomainAndVersion> getDomainVersions() throws IOException {
Set<DomainAndVersion> result = new HashSet<DomainAndVersion>();
for (Map.Entry<Integer, Integer> entry : metadata.get().get_domain_versions().entrySet()) {
result.add(new DomainAndVersion(coordinator.getDomainById(entry.getKey()), entry.getValue()));
}
return result;
}
@Override
public void setDomainVersions(final Map<Domain, Integer> domainVersions) throws IOException {
try {
metadata.update(metadata.new Updater() {
@Override
public void updateCopy(DomainGroupMetadata currentCopy) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Map.Entry<Domain, Integer> entry : domainVersions.entrySet()) {
map.put(entry.getKey().getId(), entry.getValue());
}
currentCopy.set_domain_versions(map);
}
});
} catch (InterruptedException e) {
throw new IOException(e);
} catch (KeeperException e) {
throw new IOException(e);
}
}
@Override
public void setDomainVersion(final Domain domain, final int versionNumber) throws IOException {
try {
metadata.update(metadata.new Updater() {
@Override
public void updateCopy(DomainGroupMetadata currentCopy) {
currentCopy.get_domain_versions().put(domain.getId(), versionNumber);
}
});
} catch (InterruptedException e) {
throw new IOException(e);
} catch (KeeperException e) {
throw new IOException(e);
}
}
@Override
public void mergeDomainVersions(final Map<Domain, Integer> domainVersions) throws IOException {
try {
metadata.update(metadata.new Updater() {
@Override
public void updateCopy(DomainGroupMetadata currentCopy) {
Map<Integer, Integer> map = currentCopy.get_domain_versions();
for (Map.Entry<Domain, Integer> entry : domainVersions.entrySet()) {
map.put(entry.getKey().getId(), entry.getValue());
}
}
});
} catch (InterruptedException e) {
throw new IOException(e);
} catch (KeeperException e) {
throw new IOException(e);
}
}
@Override
public void removeDomain(final Domain domain) throws IOException {
try {
metadata.update(metadata.new Updater() {
@Override
public void updateCopy(DomainGroupMetadata currentCopy) {
currentCopy.get_domain_versions().remove(domain.getId());
}
});
} catch (InterruptedException e) {
throw new IOException(e);
} catch (KeeperException e) {
throw new IOException(e);
}
}
@Override
public void addListener(final DomainGroupListener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
@Override
public void removeListener(DomainGroupListener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
public boolean delete() throws IOException {
try {
zk.deleteNodeRecursively(path);
return true;
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
public String toString() {
return "ZkDomainGroup [name=" + getName() + "]";
}
public String getPath() {
return path;
}
}