/*******************************************************************************
* Copyright (c) 2011, 2012 AGETO Service GmbH and others.
* All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Gunnar Wagenknecht - initial API and implementation
*******************************************************************************/
package org.eclipse.gyrex.admin.ui.cloud.internal.zookeeper;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.eclipse.gyrex.cloud.internal.zk.IZooKeeperLayout;
import org.eclipse.gyrex.cloud.internal.zk.ZooKeeperGate;
import org.eclipse.core.runtime.IPath;
import org.apache.commons.lang.CharEncoding;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.zookeeper.data.Stat;
/**
*
*/
public class ZooKeeperData {
private static final Object PROP_PATH = new Object();
private static final Object PROP_VERSION = new Object();
private static final Object PROP_CVERSION = new Object();
private static final Object PROP_DATA_LENGTH = new Object();
private static final Object PROP_EPHEMERAL_OWNER = new Object();
private static final Object PROP_DATA = new Object();
private final IPath path;
private Stat stat;
private Object[] children;
private final ZooKeeperData parent;
/**
* Creates a new instance.
*
* @param append
*/
public ZooKeeperData(final IPath path, final ZooKeeperData parent) {
this.path = path;
this.parent = parent;
}
private String asString(final byte[] data) {
if (null == data)
return StringUtils.EMPTY;
try {
return new String(data, CharEncoding.UTF_8);
} catch (final UnsupportedEncodingException e) {
return ExceptionUtils.getRootCauseMessage(e);
}
}
/**
* Returns the children.
*
* @return the children
*/
public Object[] getChildren() {
if (null == children) {
load();
}
return children;
}
private Object getData() {
if (null == stat) {
load();
}
try {
final byte[] data = ZooKeeperGate.get().readRecord(path, stat);
if (null == data)
return null;
// read known paths as properties
if (isPropertiesBased()) {
final Properties prop = new Properties();
prop.load(new ByteArrayInputStream(data));
return prop;
}
return WordUtils.wrap(asString(data), 80);
} catch (final Exception e) {
return ExceptionUtils.getRootCauseMessage(e);
}
}
public String getLabel() {
final Stat stat = getStat();
// print the first few chars if string based
if ((stat.getDataLength() > 0) && isStringBased()) {
final String data = StringUtils.left(String.valueOf(getData()), 70);
if (stat.getEphemeralOwner() != 0)
return String.format("%s (ephemeral, v%d) [%s]", path.segmentCount() > 0 ? path.lastSegment() : "/", stat.getVersion(), data);
else
return String.format("%s (v%d) [%s]", path.segmentCount() > 0 ? path.lastSegment() : "/", stat.getVersion(), data);
}
if (stat.getEphemeralOwner() != 0)
return String.format("%s (ephemeral, v%d)", path.segmentCount() > 0 ? path.lastSegment() : "/", stat.getVersion());
else if (stat.getDataLength() > 0)
return String.format("%s (v%d, c%d, %d bytes)", path.segmentCount() > 0 ? path.lastSegment() : "/", stat.getVersion(), stat.getCversion(), stat.getDataLength());
else
return String.format("%s (v%d, c%d)", path.segmentCount() > 0 ? path.lastSegment() : "/", stat.getVersion(), stat.getCversion());
}
/**
* Returns the parent.
*
* @return the parent
*/
public ZooKeeperData getParent() {
return parent;
}
public Object getPropertyValue(final Object id) {
if (id == PROP_PATH)
return path;
if (id == PROP_VERSION)
return getStat().getVersion();
if (id == PROP_CVERSION)
return getStat().getCversion();
if (id == PROP_EPHEMERAL_OWNER)
return "0x" + Long.toHexString(getStat().getEphemeralOwner());
if (id == PROP_DATA_LENGTH)
return getStat().getDataLength();
if (id == PROP_DATA)
return getData();
return null;
}
public Stat getStat() {
if (null == stat) {
load();
}
return stat;
}
public boolean hasChildren() {
return getChildren().length > 0;
}
private boolean isPropertiesBased() {
return IZooKeeperLayout.PATH_PREFERENCES_ROOT.isPrefixOf(path) || IZooKeeperLayout.PATH_NODES_APPROVED.isPrefixOf(path) || IZooKeeperLayout.PATH_NODES_PENDING.isPrefixOf(path);
}
private boolean isStringBased() {
return IZooKeeperLayout.PATH_LOCKS_ROOT.isPrefixOf(path) || IZooKeeperLayout.PATH_NODES_ALL.isPrefixOf(path) || IZooKeeperLayout.PATH_NODES_ONLINE.isPrefixOf(path) || IZooKeeperLayout.PATH_JOBS_ROOT.isPrefixOf(path);
}
private void load() {
stat = new Stat();
try {
final Collection<String> names = ZooKeeperGate.get().readChildrenNames(path, stat);
final List<Object> children = new ArrayList<Object>();
if (names.size() > 0) {
// use children
for (final String name : names) {
children.add(new ZooKeeperData(path.append(name), this));
}
}
// append properties for well known paths
if (isPropertiesBased()) {
final byte[] data = ZooKeeperGate.get().readRecord(path, stat);
if (null != data) {
final Properties prop = new Properties();
prop.load(new ByteArrayInputStream(data));
final Set<Entry<Object, Object>> entrySet = prop.entrySet();
for (final Entry<Object, Object> e : entrySet) {
children.add(String.format("%s=%s", e.getKey(), e.getValue()));
}
}
}
this.children = children.toArray();
} catch (final Exception e) {
children = new String[] { ExceptionUtils.getRootCauseMessage(e) };
}
}
}