
io.amient.affinity.core.config.CfgStruct Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of api Show documentation
Show all versions of api Show documentation
Library for building fast, scalable, fault-tolerant Data APIs based on Akka, ZooKeeper and Kafka.
The newest version!
/*
* Copyright 2016-2018 Michal Harish, [email protected]
*
* 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 io.amient.affinity.core.config;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import java.net.URL;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
public class CfgStruct extends Cfg implements CfgNested {
public final List options;
protected List>> properties = new LinkedList<>();
protected List> externalProperties = new LinkedList<>();
private Config config;
protected CfgStruct> parent = null;
private List> children = new LinkedList<>();
Set extensions = new HashSet() {{
addAll(specializations());
}};
protected Set specializations() {
return Collections.emptySet();
}
protected void addChild(CfgStruct> child) {
children.add(child);
}
@Override
public CfgStruct doc(String description) {
super.doc(description);
return this;
}
@Override
public boolean isDefined() {
return properties.stream().filter(p -> p.getValue().isRequired() && !p.getValue().isDefined()).count() == 0;
}
public CfgStruct(Class extends CfgStruct>> inheritFrom, Options... options) {
this.options = Arrays.asList(options);
try {
CfgStruct> inheritedCfg = inheritFrom.newInstance();
inheritedCfg.properties.forEach(p -> extensions.add(p.getKey()));
inheritedCfg.extensions.forEach(e -> extensions.add(e));
} catch (Exception e) {
throw new RuntimeException(e);
}
setValue((T) this);
}
public CfgStruct() {
this(Options.STRICT);
}
public CfgStruct(Options... options) {
this.options = Arrays.asList(options);
setValue((T) this);
}
@Override
public void setPath(String path) {
super.setPath(path);
properties.forEach(entry -> entry.getValue().setPath(path(entry.getKey())));
}
public final T apply(CfgStruct> conf) throws IllegalArgumentException {
if (conf.path() == null) throw new IllegalArgumentException();
if (conf.parent != null && conf.parent.getClass().isAssignableFrom(this.getClass())) {
return (T) conf.parent;
} else {
T z = apply(conf.config());
final AtomicReference self = new AtomicReference<>(z);
self.get().setPath(conf.path());
conf.children.forEach(x -> {
if (self.get().getClass().isAssignableFrom(x.getClass())) {
self.set((T) x);
}
});
T result = self.get();
result.parent = conf;
// result.externalProperties = conf.externalProperties;
if (result == z) conf.addChild(result);
return result;
}
}
public final T apply(Map config) {
return apply(ConfigFactory.parseMap(config));
}
@Override
public T apply(Config config) throws IllegalArgumentException {
if (config != null) {
this.config = path().isEmpty() ? config : listPos > -1
? config.getConfigList(relPath).get(listPos) : config.getConfig(relPath);
final StringBuilder errors = new StringBuilder();
properties.forEach(entry -> {
String propPath = entry.getKey();
Cfg> cfg = entry.getValue();
try {
if (propPath == null || propPath.isEmpty()) {
cfg.apply(this.config);
} else if (this.config.hasPath(propPath)) {
cfg.apply(this.config);
}
if (cfg.required && !cfg.isDefined()) {
throw new IllegalArgumentException(propPath + " is required" + (path().isEmpty() ? "" : " in " + path()));
}
} catch (IllegalArgumentException e) {
errors.append(e.getMessage() + "\n");
}
});
externalProperties.clear();
//if (!options.contains(Options.IGNORE_UNKNOWN)) {
this.config.entrySet().forEach(entry -> {
boolean existingProperty = properties.stream().filter((p) ->
p.getKey().equals(entry.getKey())
|| (p.getValue() instanceof CfgNested && entry.getKey().startsWith(p.getKey() + "."))
).count() > 0;
boolean allowedViaExtensions = extensions.stream().filter((s) ->
s.equals(entry.getKey()) || entry.getKey().startsWith(s + ".")
).count() > 0;
if (!existingProperty && !allowedViaExtensions) {
if (!options.contains(Options.IGNORE_UNKNOWN)) {
errors.append(entry.getKey() + " is not a known property" + (path().isEmpty() ? "" : " of " + path()) + "\n");
} else {
CfgString c = new CfgString();
c.setValue(entry.getValue().unwrapped().toString());
externalProperties.add(new AbstractMap.SimpleEntry(entry.getKey(), c));
}
}
});
String errorMessage = errors.toString();
if (!errorMessage.isEmpty()) {
throw new IllegalArgumentException(errorMessage);
}
return (T) this;
}
return (T) this;
}
@Override
public String parameterInfo() {
return "";
}
Config config() {
return config;
}
public CfgString string(String path, boolean required) {
return add(path, new CfgString(), required, Optional.empty());
}
public CfgString string(String path, String defaultValue) {
return add(path, new CfgString(), true, Optional.of(defaultValue));
}
public CfgStringList stringlist(String path, List defaultValue) {
return add(path, new CfgStringList(), true, Optional.of(defaultValue));
}
public CfgStringList stringlist(String path, boolean required) {
return add(path, new CfgStringList(), required, Optional.empty());
}
public CfgLong longint(String path, boolean required) {
return add(path, new CfgLong(), required, Optional.empty());
}
public CfgLong longint(String path, long defaultValue) {
return add(path, new CfgLong(), true, Optional.of(defaultValue));
}
public CfgBool bool(String path, boolean required) {
return add(path, new CfgBool(), required, Optional.empty());
}
public CfgBool bool(String path, boolean required, boolean defaultValue) {
return add(path, new CfgBool(), required, Optional.of(defaultValue));
}
public CfgInt integer(String path, boolean required) {
return add(path, new CfgInt(), required, Optional.empty());
}
public CfgInt integer(String path, Integer defaultValue) {
return add(path, new CfgInt(), true, Optional.of(defaultValue));
}
public CfgIntList intlist(String path, boolean required) {
return add(path, new CfgIntList(), required, Optional.empty());
}
public CfgIntList intlist(String path, List defaultValue) {
return add(path, new CfgIntList(), true, Optional.of(defaultValue));
}
public CfgUrl url(String path, boolean required) {
return add(path, new CfgUrl(), required, Optional.empty());
}
public CfgUrl url(String path, URL defaultVal) {
return add(path, new CfgUrl(), true, Optional.of(defaultVal));
}
public CfgPath filepath(String path, boolean required) {
return add(path, new CfgPath(), required, Optional.empty());
}
public CfgPath filepath(String path, Path defaultVal) {
return add(path, new CfgPath(), true, Optional.of(defaultVal));
}
public CfgCls cls(String path, Class c, boolean required) {
return add(path, new CfgCls<>(c), required, Optional.empty());
}
public CfgCls cls(String path, Class c, Class extends X> defaultVal) {
return add(path, new CfgCls<>(c), true, Optional.of(defaultVal));
}
public > X struct(String path, X obj, boolean required) {
X x = add(path, obj, required, Optional.empty());
obj.setValue(obj);
return x;
}
public > X ref(X obj, boolean required) {
return add(null, obj, required, Optional.empty());
}
public > CfgGroup group(String path, Class c, boolean required) {
return add(path, new CfgGroup<>(c), required, Optional.empty());
}
public > CfgGroup group(String path, CfgGroup obj, boolean required) {
return add(path, obj, required, Optional.empty());
}
public CfgList list(String path, Class c, boolean required) {
return add(path, new CfgList(c), required, Optional.empty());
}
private > X add(String itemRelPath, X cfg, boolean required, Optional defaultValue) {
cfg.setRelPath(itemRelPath);
cfg.setPath(path() + itemRelPath);
if (defaultValue.isPresent()) cfg.setDefaultValue(defaultValue.get());
if (!required) cfg.setOptional();
properties.add(new AbstractMap.SimpleEntry<>(itemRelPath, cfg));
return cfg;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof CfgStruct)) {
return false;
} else {
CfgStruct that = (CfgStruct) other;
if (this.properties.size() != that.properties.size()) return false;
for (int i = 0; i < this.properties.size(); i++) {
Map.Entry> left = this.properties.get(i);
Map.Entry> right = that.properties.get(i);
boolean same = left.getKey().equals(right.getKey()) && left.getValue().equals(right.getValue());
if (!same) return false;
}
return true;
}
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
result.append("{");
properties.forEach(entry -> {
if (result.length() > 1) result.append(", ");
result.append(entry.getKey());
result.append(": ");
result.append(entry.getValue());
});
result.append("}");
return result.toString();
}
public Map> toMap() {
TreeMap> result = new TreeMap<>();
properties.forEach(prop -> result.put(prop.getKey(), prop.getValue()));
externalProperties.forEach(prop -> result.put(prop.getKey(), prop.getValue()));
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy