package org.dcache.boot;
import com.google.common.base.Strings;
import java.io.PrintStream;
import org.dcache.util.ConfigurationProperties;
/**
* Creates a Python declaration for a class that is an oracle for
* consulting the value of dCache properties. By executing the
* output ('exec' python command) a class 'Properties' is defined
* along with an instance of this class called 'properties'.
*
* The get method of 'properties' returns the value of a property, or
* the python literal 'None' if it isn't defined. The get method takes
* one mandatory argument (the property name) and two optional ones: the
* name of a domain and the name of a service (as provided by the
* '<service>.cell.name' property).
*
* Here is a simple python script that demonstrates these features.
*
* #!/usr/bin/env python
*
* from subprocess import Popen, PIPE
* d = Popen(["dcache", "loader", "-q", "compile", "-python"], stdout=PIPE)
* exec d.communicate()[0]
*
* # Print the value of a globally defined property
* print properties.get('info-provider.se-unique-id')
*
* # Print the value of a property for a specific domain
* print properties.get('dcache.java.memory.heap', 'dCacheDomain')
*
* # Print the value of a property for a specific service-instance
* print properties.get('path', 'dCacheDomain', 'pool1')
* print properties.get('path', 'dCacheDomain', 'pool2')
*/
public class PythonOracleLayoutPrinter implements LayoutPrinter
{
private final Layout _layout;
public PythonOracleLayoutPrinter(Layout layout)
{
_layout = layout;
}
@Override
public void print(PrintStream out)
{
new Request(out).print();
}
private class Request
{
private final PrintStream _out;
public Request(PrintStream out)
{
_out = out;
}
public void print()
{
IndentPrinter base = new IndentPrinter(_out);
base.println("class Properties:");
printClass(base.indent());
base.println("properties = Properties()");
}
public void printClass(IndentPrinter out)
{
out.println("\"\"\"Allows queries against dCache configuration\"\"\"");
out.println("def __init__(self):");
printInit(out.indent());
out.println("def get(self, key, domain=None, service=None):");
printGetDomainService(out.indent());
}
private void printGetDomainService(IndentPrinter out)
{
IndentPrinter indent = out.indent();
out.println("if domain in self.service_scope and \\");
out.println(" service in self.service_scope [domain] and \\");
out.println(" key in self.service_scope [domain] [service]:");
indent.println("return self.service_scope [domain] [service] [key]");
out.println();
out.println("if domain in self.domain_scope and \\");
out.println(" key in self.domain_scope[domain]:");
indent.println("return self.domain_scope [domain] [key]");
out.println();
out.println("if key in self.global_scope:");
indent.println("return self.global_scope[key]");
out.println();
out.println("return None");
out.println();
}
private void printInit(IndentPrinter out)
{
IndentPrinter indent = out.indent();
out.println("self.global_scope = {");
printGlobalScope(indent);
indent.println("}");
out.println();
out.println("self.domain_scope = {");
printDomainScope(indent);
indent.println("}");
out.println();
out.println("self.service_scope = {");
printServiceScope(indent);
indent.println("}");
out.println();
}
private void printGlobalScope(IndentPrinter out)
{
ConfigurationProperties properties = _layout.properties();
for(String key : properties.stringPropertyNames()) {
printEntry(out, key, properties.getValue(key));
}
}
private void printDomainScope(IndentPrinter out)
{
IndentPrinter indent = out.indent();
for(Domain domain : _layout.getDomains()) {
String name = markup(domain.getName());
out.println("'" + name + "' : {");
printProperties(indent, domain.properties(),
_layout.properties());
indent.println("},");
}
}
private void printServiceScope(IndentPrinter out)
{
IndentPrinter indent = out.indent();
for(Domain domain : _layout.getDomains()) {
String name = markup(domain.getName());
out.println("'" + name + "' : {");
printDomainServices(indent, domain);
indent.println("},");
}
}
private void printDomainServices(IndentPrinter out, Domain domain)
{
IndentPrinter indent = out.indent();
for(ConfigurationProperties service : domain.getServices()) {
String name = Properties.getCellName(service);
if (!Strings.isNullOrEmpty(name)) {
out.println("'" + markup(name) + "' : {");
printProperties(indent, service, domain.properties());
indent.println("},");
}
}
}
private void printProperties(IndentPrinter out,
ConfigurationProperties properties,
ConfigurationProperties parentProperties)
{
for(String key : properties.stringPropertyNames()) {
String value = properties.getValue(key);
if(!value.equals(parentProperties.getValue(key))) {
printEntry(out, key, value);
}
}
}
private void printEntry(IndentPrinter out, String key, String value)
{
String safeKey = markup(key);
String safeValue = markup(value);
out.println("'" + safeKey + "' : '" + safeValue + "',");
}
}
private static String markup(String in)
{
StringBuilder sb = new StringBuilder(in.length());
for(char c : in.toCharArray()) {
switch(c) {
case '\n':
sb.append('\\');
c = 'n';
break;
case '\t':
sb.append('\\');
c = 't';
break;
case '\\':
case '\'':
sb.append('\\');
break;
}
sb.append(c);
}
return sb.toString();
}
/**
* Simple class to assist with printing Python code with the correct
* indentation.
*/
private static class IndentPrinter
{
private final PrintStream _inner;
private final String _indent;
public IndentPrinter(PrintStream inner)
{
this(inner, "");
}
private IndentPrinter(PrintStream inner, String indent)
{
_inner = inner;
_indent = indent;
}
public void println()
{
_inner.println();
}
public void println(String line)
{
if(line.isEmpty()) {
_inner.println();
} else {
_inner.println(_indent + line);
}
}
public IndentPrinter indent()
{
return new IndentPrinter(_inner, _indent + " ");
}
}
}