/*
* 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.hadoop.registry.client.impl.zk;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.GetChildrenBuilder;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import java.util.List;
/**
* This class dumps a registry tree to a string.
* It does this in the <code>toString()</code> method, so it
* can be used in a log statement -the operation
* will only take place if the method is evaluated.
*
*/
@VisibleForTesting
public class ZKPathDumper {
public static final int INDENT = 2;
private final CuratorFramework curator;
private final String root;
private final boolean verbose;
/**
* Create a path dumper -but do not dump the path until asked
* @param curator curator instance
* @param root root
* @param verbose verbose flag - includes more details (such as ACLs)
*/
public ZKPathDumper(CuratorFramework curator,
String root,
boolean verbose) {
Preconditions.checkArgument(curator != null);
Preconditions.checkArgument(root != null);
this.curator = curator;
this.root = root;
this.verbose = verbose;
}
/**
* Trigger the recursive registry dump.
* @return a string view of the registry
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ZK tree for ").append(root).append('\n');
expand(builder, root, 1);
return builder.toString();
}
/**
* Recursively expand the path into the supplied string builder, increasing
* the indentation by {@link #INDENT} as it proceeds (depth first) down
* the tree
* @param builder string build to append to
* @param path path to examine
* @param indent current indentation
*/
private void expand(StringBuilder builder,
String path,
int indent) {
try {
GetChildrenBuilder childrenBuilder = curator.getChildren();
List<String> children = childrenBuilder.forPath(path);
for (String child : children) {
String childPath = path + "/" + child;
String body;
Stat stat = curator.checkExists().forPath(childPath);
StringBuilder bodyBuilder = new StringBuilder(256);
bodyBuilder.append(" [")
.append(stat.getDataLength())
.append("]");
if (stat.getEphemeralOwner() > 0) {
bodyBuilder.append("*");
}
if (verbose) {
// verbose: extract ACLs
builder.append(" -- ");
List<ACL> acls =
curator.getACL().forPath(childPath);
for (ACL acl : acls) {
builder.append(RegistrySecurity.aclToString(acl));
builder.append(" ");
}
}
body = bodyBuilder.toString();
// print each child
append(builder, indent, ' ');
builder.append('/').append(child);
builder.append(body);
builder.append('\n');
// recurse
expand(builder, childPath, indent + INDENT);
}
} catch (Exception e) {
builder.append(e.toString()).append("\n");
}
}
/**
* Append the specified indentation to a builder
* @param builder string build to append to
* @param indent current indentation
* @param c charactor to use for indentation
*/
private void append(StringBuilder builder, int indent, char c) {
for (int i = 0; i < indent; i++) {
builder.append(c);
}
}
}