All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zeromq.ZConfig Maven / Gradle / Ivy

The newest version!
package org.zeromq;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 

Lets applications load, work with, and save configuration files. * This is a minimal implementation of the ZeroMQ Property Language, * which is a simple structured text format for configuration files.

* *

Here is an example ZPL stream and corresponding config structure:

* *
 * {@code
        context
            iothreads = 1
            verbose = 1      #   Ask for a trace
        main
            type = zqueue    #  ZMQ_DEVICE type
            frontend
                option
                    hwm = 1000
                    swap = 25000000     #  25MB
                bind = 'inproc://addr1'
                bind = 'ipc://addr2'
            backend
                bind = inproc://addr3
   }

   {@code
    root                    Down = child
    |                     Across = next
    v
    context-->main
    |         |
    |         v
    |       type=queue-->frontend-->backend
    |                      |          |
    |                      |          v
    |                      |        bind=inproc://addr3
    |                      v
    |                    option-->bind=inproc://addr1-->bind=ipc://addr2
    |                      |
    |                      v
    |                    hwm=1000-->swap=25000000
    v
    iothreads=1-->verbose=false
 }
 
* *

It can put and get values and save and load them to disk:

* *
 * {@code
 * ZConfig conf = new ZConfig("root", null);
 * conf.put("/curve/public-key","abcdef");
 * String val = conf.get("/curve/public-key","fallback-defaultkey");
 * conf.save("test.cert");
 * ZConfig loaded = ZConfig.load("test.cert");
 }
*/ public class ZConfig { private interface IVisitor { void handleNode(ZConfig node, int level) throws IOException; } private static final String LEFT = "^( *)([0-9a-zA-Z\\$\\-_@\\.&\\+\\/]+)"; private static final Pattern PTRN_CONTAINER = Pattern.compile(LEFT + "( *#.*)?$"); private static final Pattern PTRN_KEYVALUE = Pattern.compile(LEFT + " = ((\"|')(.*)(\\4)|(.*?))(#.*)?$"); private final String name; private final Map children = new HashMap<>(); private final List comments = new LinkedList<>(); private String value; public ZConfig(String name, ZConfig parent) { this.name = name; if (parent != null) { parent.children.put(name, this); } } public ZConfig getChild(String name) { return children.get(name); } public Map getValues() { Map values = new HashMap<>(); fillValues("", values); return values; } private void fillValues(String prefix, Map values) { for (Entry entry : children.entrySet()) { String key = entry.getKey(); ZConfig child = entry.getValue(); assert (child != null); if (child.value != null) { values.put(prefix + key, child.value); } child.fillValues(prefix + key + '/', values); } } public String getName() { return this.name; } public String getValue(String path) { return getValue(path, null); } public String getValue(String path, String defaultValue) { String[] pathElements = path.split("/"); ZConfig current = this; for (String pathElem : pathElements) { if (pathElem.isEmpty()) { continue; } current = current.children.get(pathElem); if (current == null) { return defaultValue; } } return current.value; } /** * check if a value-path exists * @param path * @return true if value-path exists */ public boolean pathExists(String path) { String[] pathElements = path.split("/"); ZConfig current = this; for (String pathElem : pathElements) { if (pathElem.isEmpty()) { continue; } current = current.children.get(pathElem); if (current == null) { return false; } } return true; } /** * add comment * @param comment */ public void addComment(String comment) { comments.add(comment); } /** * @param path * @param value set value of config item */ public ZConfig putValue(String path, String value) { String[] pathElements = path.split("/"); ZConfig current = this; for (String pathElement : pathElements) { if (pathElement.isEmpty()) { // ignore leading slashes continue; } ZConfig container = current.children.get(pathElement); if (container == null) { container = new ZConfig(pathElement, current); } current = container; } current.value = value; return current; } public void putValues(ZConfig src) { for (Entry entry : src.getValues().entrySet()) { putValue(entry .getKey(), entry.getValue()); } } private void visit(ZConfig startNode, IVisitor handler, int level) throws IOException { handler.handleNode(startNode, level); for (ZConfig node : startNode.children.values()) { visit(node, handler, level + 1); } } /** * Saves the configuration to a file. *

* This method will overwrite contents of existing file * @param filename the path of the file to save the configuration into, or "-" to dump it to standard output * @return the saved file or null if dumped to the standard output * @throws IOException if unable to save the file. */ public File save(String filename) throws IOException { if ("-".equals(filename)) { // print to console try (Writer writer = new PrintWriter(System.out)) { save(writer); } return null; } else { // write to file final File file = new File(filename); if (file.exists()) { file.delete(); } else { // create necessary directories; file.getParentFile().mkdirs(); } try (Writer writer = new FileWriter(file)) { save(writer); } return file; } } public void save(final Writer writer) throws IOException { visit(this, (node, level) -> { // First print comments if (!node.comments.isEmpty()) { for (String comment : node.comments) { writer.append("# ").append(comment).append('\n'); } writer.append("\n"); } // now the values if (level > 0) { String prefix = level > 1 ? String.format("%" + ((level - 1) * 4) + "s", " ") : ""; writer.append(prefix); if (node.value == null) { writer.append(node.name).append("\n"); } else { writer.append(String.format("%s = \"%s\"\n", node.name, node.value)); } } }, 0); } public static ZConfig load(String filename) throws IOException { try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { List content = new ArrayList<>(); String line = reader.readLine(); while (line != null) { boolean irrelevant = line.matches("^ *#.*|^ *[0-9]+.*") // ignore comments || line.trim().isEmpty(); // ignore empty lines; if (!irrelevant) { content.add(line); } line = reader.readLine(); } return load(new ZConfig("root", null), content, 0, new AtomicInteger()); } } private static ZConfig load(ZConfig parent, List content, int currentLevel, AtomicInteger lineNumber) { while (lineNumber.get() < content.size()) { String currentLine = content.get(lineNumber.get()); Matcher container = PTRN_CONTAINER.matcher(currentLine); if (container.find()) { ZConfig child = child(parent, container, currentLevel, currentLine, lineNumber); if (child == null) { // jump back; break; } load(child, content, currentLevel + 1, lineNumber); } else { Matcher keyvalue = PTRN_KEYVALUE.matcher(currentLine); if (keyvalue.find()) { ZConfig child = child(parent, keyvalue, currentLevel, currentLine, lineNumber); if (child == null) { // jump back; break; } String value = keyvalue.group(5); if (value == null) { value = keyvalue.group(7); } if (value != null) { value = value.trim(); } child.value = value; } else { throw new ReadException("Couldn't process line", currentLine, lineNumber); } } } return parent; } private static ZConfig child(ZConfig parent, Matcher matcher, int currentLevel, String currentLine, AtomicInteger lineNumber) { int level = matcher.group(1).length() / 4; if (level > currentLevel) { throw new ReadException("Level mismatch in line", currentLine, lineNumber); } else if (level < currentLevel) { // jump back; return null; } lineNumber.incrementAndGet(); return new ZConfig(matcher.group(2), parent); } public static class ReadException extends RuntimeException { private static final long serialVersionUID = 1L; public final int currentLineNumber; public final String currentLine; public ReadException(String message, String currentLine, AtomicInteger currentLineNumber) { super(String.format("%s %s: %s", message, currentLineNumber, currentLine)); this.currentLine = currentLine; this.currentLineNumber = currentLineNumber.get(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy