package org.dcache.boot; import com.google.common.base.Strings; import java.io.PrintStream; import org.dcache.util.ConfigurationProperties; /** * Generates a shell function {@code getProperty} which serves as * an oracle for property values. The function takes three * arguments: property key, domain name, cell name. The latter two * are optional. * * For undefined cells the function calls {@code * undefinedCell}. For undefined domains the function calls {@code * undefinedDomain}. For undefined properties the function calls * {@code undefinedProperties}. If those functions return then * processing falls through to the enclosing configuration * context. */ public class ShellOracleLayoutPrinter implements LayoutPrinter { private final Layout _layout; public ShellOracleLayoutPrinter(Layout layout) { _layout = layout; } @Override public void print(PrintStream out) { out.println("getProperty()"); out.println("{"); // Logic for per service parameters out.println(" case \"$2\" in"); out.println(" \"\")"); out.println(" ;;"); // Fall through for (Domain domain: _layout.getDomains()) { out.append(" ").append(quoteForCase(domain.getName())).println(")"); out.println(" case \"$3\" in"); out.println(" \"\")"); out.println(" ;;"); // Fall through for (ConfigurationProperties service: domain.getServices()) { String cellName = Properties.getCellName(service); if (!Strings.isNullOrEmpty(cellName)) { out.append(" ").append(quoteForCase(cellName)).println(")"); compile(out, " ", service, domain.properties()); out.println(" ;;"); } } out.println(" *)"); out.println(" undefinedCell \"$@\""); out.println(" ;;"); out.println(" esac"); out.println(" ;;"); } out.println(" *)"); out.println(" undefinedDomain \"$@\""); out.println(" ;;"); out.println(" esac"); out.println(); // Logic for per domain parameters out.println(" case \"$2\" in"); for (Domain domain: _layout.getDomains()) { out.append(" ").append(quoteForCase(domain.getName())).println(")"); compile(out, " ", domain.properties(), _layout.properties()); out.println(" ;;"); } out.println(" esac"); out.println(); // Logic for global properties compile(out, " ", _layout.properties(), new ConfigurationProperties()); out.println(); // Global fallback out.println(" undefinedProperty \"$@\""); out.println("}"); } private static String quote(String s) { char[] output = new char[2 * s.length()]; int len = 0; for (char c: s.toCharArray()) { switch (c) { case '\\': case '$': case '`': case '"': output[len++] = '\\'; break; } output[len++] = c; } return new String(output, 0, len); } private static String quoteForCase(String s) { char[] output = new char[2 * s.length()]; int len = 0; for (char c: s.toCharArray()) { switch (c) { case '\\': case '$': case '`': case '"': case ')': case '?': case '*': case '[': case ' ': output[len++] = '\\'; break; } output[len++] = c; } return new String(output, 0, len); } /** * Generates a shell case statement for value in {@code * properties} not defined in {@code parentProperties}. */ private static void compile(PrintStream out, String indent, ConfigurationProperties properties, ConfigurationProperties parentProperties) { out.append(indent).println("case \"$1\" in"); for (String key: properties.stringPropertyNames()) { ConfigurationProperties.AnnotatedKey annotatedKey = properties.getAnnotatedKey(key); if (annotatedKey == null || !annotatedKey.hasAnnotation(ConfigurationProperties.Annotation.DEPRECATED)) { String value = properties.getValue(key); if (!value.equals(parentProperties.getValue(key))) { out.append(indent).append(" "); out.append(quoteForCase(key)).append(") echo \""); out.append(quote(value.trim())); out.println("\"; return;;"); } } } out.append(indent).println("esac"); } }