package thito.nodeflow.config; import org.yaml.snakeyaml.*; import java.io.*; import java.util.*; import java.util.regex.*; public interface Section { String SEPARATOR = "."; static Object wrap(Object o) { if (o instanceof Section) return o; if (o instanceof List) { return new ListSection((List) o); } if (o instanceof Map) { return new MapSection((Map) o); } return o; } static String getName(String path) { String[] split = path.split(Pattern.quote(SEPARATOR)); return split[split.length - 1]; } static Section wrapParent(Section parent, String name, Section current) { if (current.getParent() != null && current.getParent() != parent) { if (current instanceof MapSection) { MapSection mapSection = new MapSection((MapSection) current); mapSection.setParent(parent, name); return mapSection; } if (current instanceof ListSection) { ListSection objects = new ListSection((ListSection) current); objects.setParent(parent, name); return objects; } } else { if (current instanceof MapSection) { ((MapSection) current).setParent(parent, name); } if (current instanceof ListSection) { ((ListSection) current).setParent(parent, name); } } return current; } static String toString(Section section) { DumperOptions options = new DumperOptions(); options.setIndent(4); options.setAllowUnicode(true); options.setPrettyFlow(true); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); Yaml yaml = new Yaml(options); return yaml.dumpAsMap(section); } static MapSection parseToMap(Reader reader) { Yaml yaml = new Yaml(); return new MapSection(yaml.loadAs(reader, Map.class)); } Set getKeys(); default Set getPaths() { Set paths = new HashSet<>(); for (String k : getKeys()) { Object lookup = getInScope(k).orElse(null); if (lookup instanceof Section) { for (String p : ((Section) lookup).getPaths()) { paths.add(k + "." + p); } } } return paths; } String getName(); default String getPath() { StringBuilder path = new StringBuilder(getName()); Section parent; while ((parent = getParent()) != null) { path.insert(0, parent.getName() + SEPARATOR); } return path.toString(); } Section getParent(); Optional getInScope(String key); void setInScope(String key, Object value); default void set(String path, Object value) { String[] paths = path.split(Pattern.quote(SEPARATOR)); Object lookup = this; for (int i = 0; i < paths.length - 1; i++) { Section oldLookup = (Section) lookup; lookup = oldLookup.getInScope(paths[i]).orElse(null); if (!(lookup instanceof Section)) { oldLookup.setInScope(paths[i], lookup = new MapSection()); } } if (paths.length > 0) { ((Section) lookup).setInScope(paths[paths.length - 1], value); } } default Optional getObject(String path) { String[] paths = path.split(Pattern.quote(SEPARATOR)); Object lookup = this; for (String s : paths) { if (lookup instanceof Section) { lookup = ((Section) lookup).getInScope(s).orElse(null); } else { return Optional.empty(); } } return Optional.ofNullable(lookup); } default > Optional getEnum(String path, Class clz) { return getObject(path).map(o -> { try { return Enum.valueOf(clz, String.valueOf(o)); } catch (Throwable t) { return null; } }); } default Optional getString(String path) { return getObject(path).map(String::valueOf); } default Optional getInteger(String path) { return getObject(path).map(o -> { try { return Integer.valueOf(String.valueOf(o)); } catch (Throwable t) { return null; } }); } default Optional getDouble(String path) { return getObject(path).map(o -> { try { return Double.valueOf(String.valueOf(o)); } catch (Throwable t) { return null; } }); } default Optional getLong(String path) { return getObject(path).map(o -> { try { return Long.valueOf(String.valueOf(o)); } catch (Throwable t) { return null; } }); } default Optional getFloat(String path) { return getObject(path).map(o -> { try { return Float.valueOf(String.valueOf(o)); } catch (Throwable t) { return null; } }); } default Optional getShort(String path) { return getObject(path).map(o -> { try { return Short.valueOf(String.valueOf(o)); } catch (Throwable t) { return null; } }); } default Optional getByte(String path) { return getObject(path).map(o -> { try { return Byte.valueOf(String.valueOf(o)); } catch (Throwable t) { return null; } }); } default Optional getCharacter(String path) { return getObject(path).map(o -> { String text = String.valueOf(o); return text.isEmpty() ? null : text.charAt(0); }); } default Optional getBoolean(String path) { return getObject(path).map(o -> { String text = String.valueOf(o); return text.equals("true") ? Boolean.TRUE : text.equals("false") ? Boolean.FALSE : null; }); } default Optional getMap(String path) { return getObject(path).map(o -> { if (o instanceof Map) { if (o instanceof MapSection) return (MapSection) o; MapSection mapSection = new MapSection((Map) o); mapSection.setParent(this, Section.getName(path)); return mapSection; } return null; }); } default Optional getList(String path) { return getObject(path).map(o -> { if (o instanceof List) { if (o instanceof ListSection) { return (ListSection) o; } ListSection list = new ListSection((List) o); list.setParent(this, Section.getName(path)); return list; } ListSection list = new ListSection(Collections.singleton(o)); list.setParent(this, Section.getName(path)); return list; }); } }