io.engineblock.activityimpl.ParameterMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eb-api Show documentation
Show all versions of eb-api Show documentation
The driver API for engineblock;
Provides the interfaces needed to build drivers that can be loaded by engineblock core
/*
* Copyright 2015 jshook
* Licensed 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.engineblock.activityimpl;
import io.engineblock.activityimpl.motor.ParamsParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.Bindings;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* A concurrently accessible parameter map which holds both keys and values as strings.
* An atomic change counter tracks updates, to allow interested consumers to determine
* when to re-read values across threads. The basic format is
* <paramname>=<paramvalue>;...
*
* To create a parameter map, use one of the static parse... methods.
*
* No non-String types are used internally. Everything is encoded as a String, even though the
* generic type is parameterized for Bindings support.
*/
public class ParameterMap extends ConcurrentHashMap implements Bindings {
private final static Logger logger = LoggerFactory.getLogger(ParameterMap.class);
// private final ConcurrentHashMap paramMap = new ConcurrentHashMap<>(10);
private final AtomicLong changeCounter = new AtomicLong(0L);
private final LinkedList listeners = new LinkedList<>();
public ParameterMap(Map valueMap) {
logger.trace("new parameter map:" + valueMap.toString());
super.putAll(valueMap);
}
public long getLongOrDefault(String paramName, long defaultLongValue) {
Optional l = Optional.ofNullable(super.get(paramName)).map(String::valueOf);
return l.map(Long::valueOf).orElse(defaultLongValue);
}
public double getDoubleOrDefault(String paramName, double defaultDoubleValue) {
Optional d = Optional.ofNullable(super.get(paramName)).map(String::valueOf);
return d.map(Double::valueOf).orElse(defaultDoubleValue);
}
public String getStringOrDefault(String paramName, String defaultStringValue) {
Optional s = Optional.ofNullable(super.get(paramName)).map(String::valueOf);
return s.orElse(defaultStringValue);
}
public Optional getOptionalString(String paramName) {
return Optional.ofNullable(super.get(paramName)).map(String::valueOf);
}
public Optional getOptionalLong(String paramName) {
return Optional.ofNullable(super.get(paramName)).map(String::valueOf).map(Long::valueOf);
}
public Optional getOptionalDouble(String paramName) {
return Optional.ofNullable(super.get(paramName)).map(String::valueOf).map(Double::valueOf);
}
public Optional getOptionalBoolean(String paramName) {
return Optional.ofNullable(super.get(paramName)).map(String::valueOf).map(Boolean::valueOf);
}
public int getIntOrDefault(String paramName, int defaultIntValue) {
Optional i = Optional.ofNullable(super.get(paramName)).map(String::valueOf);
return i.map(Integer::valueOf).orElse(defaultIntValue);
}
public boolean getBoolOrDefault(String paramName, boolean defaultBoolValue) {
Optional b = Optional.ofNullable(super.get(paramName)).map(String::valueOf);
return b.map(Boolean::valueOf).orElse(defaultBoolValue);
}
public Long takeLongOrDefault(String paramName, Long defaultLongValue) {
Optional l = Optional.ofNullable(super.remove(paramName)).map(String::valueOf);
Long lval = l.map(Long::valueOf).orElse(defaultLongValue);
markMutation();
return lval;
}
public Double takeDoubleOrDefault(String paramName, double defaultDoubleValue) {
Optional d = Optional.ofNullable(super.remove(paramName)).map(String::valueOf);
Double dval = d.map(Double::valueOf).orElse(defaultDoubleValue);
markMutation();
return dval;
}
public String takeStringOrDefault(String paramName, String defaultStringValue) {
Optional s = Optional.ofNullable(super.remove(paramName)).map(String::valueOf);
String sval = s.orElse(defaultStringValue);
markMutation();
return sval;
}
public int takeIntOrDefault(String paramName, int paramDefault) {
Optional i = Optional.ofNullable(super.remove(paramName)).map(String::valueOf);
int ival = i.map(Integer::valueOf).orElse(paramDefault);
markMutation();
return ival;
}
public boolean takeBoolOrDefault(String paramName, boolean defaultBoolValue) {
Optional b = Optional.ofNullable(super.remove(paramName)).map(String::valueOf);
boolean bval = b.map(Boolean::valueOf).orElse(defaultBoolValue);
markMutation();
return bval;
}
@Override
public Object get(Object key) {
logger.info("getting parameter " + key);
return super.get(key);
}
public void set(String paramName, Object newValue) {
super.put(paramName, String.valueOf(newValue));
logger.info("parameter " + paramName + " set to " + newValue);
markMutation();
}
private static Pattern encodedParamsSquote = Pattern.compile("(?\\w+?)='(?[^']+?);");
private static Pattern encodedParamsDquote = Pattern.compile("(?\\w+?)=\"(?[^\"]+?);");
private static Pattern encodedParamsPattern = Pattern.compile("(?\\w+?)=(?.+?);");
@Override
public Object put(String name, Object value) {
Object oldVal = super.put(name, String.valueOf(value));
logger.info("parameter " + name + " put to " + value);
markMutation();
return oldVal;
}
@Override
public void putAll(Map extends String, ? extends Object> toMerge) {
for (Entry extends String, ? extends Object> entry : toMerge.entrySet()) {
super.put(entry.getKey(),String.valueOf(entry.getValue()));
}
markMutation();
}
@Override
public Object remove(Object key) {
Object removed = super.remove(key);
logger.info("parameter " + key + " removed");
markMutation();
return removed;
}
@Override
public void clear() {
logger.info("parameter map cleared:" + toString());
super.clear();
markMutation();
}
@Override
public Set> entrySet() {
logger.info("getting entry set for " + toString());
return super.entrySet()
.stream()
.map(e -> new AbstractMap.SimpleEntry(e.getKey(), e.getValue()) {})
.collect(Collectors.toCollection(HashSet::new));
}
private void markMutation() {
changeCounter.incrementAndGet();
logger.debug("calling " + listeners.size() + " listeners.");
callListeners();
}
/**
* Get the atomic change counter for this parameter map.
* It getes incremented whenever any changes are made to the map.
*
* @return the atomic long change counter
*/
public AtomicLong getChangeCounter() {
return changeCounter;
}
public String toString() {
return "(" + this.changeCounter.get() + ")/" + super.toString();
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void removeListener(Listener listener) {
listeners.remove(listener);
}
private void callListeners() {
for (Listener listener : listeners) {
logger.info("calling listener:" + listener);
listener.handleParameterMapUpdate(this);
}
}
public int getSize() {
return super.size();
}
public static ParameterMap parseOrException(String encodedParams) {
if (encodedParams == null) {
throw new RuntimeException("Must provide a non-null String to parse parameters.");
}
Map parsedMap = ParamsParser.parse(encodedParams);
return new ParameterMap(parsedMap);
}
// static Optional parseOptionalParams(Optional optionalEncodedParams) {
// if (optionalEncodedParams.isPresent()) {
// return parseParams(optionalEncodedParams.get());
// }
// return Optional.empty();
// }
public static Optional parseParams(String encodedParams) {
try {
return Optional.ofNullable(parseOrException(encodedParams));
} catch (Exception e) {
return Optional.empty();
}
}
// /**
// * Parse positional parameters, each suffixed with the ';' terminator.
// * This form simply allows for the initial parameter names to be elided, so long as they
// * are sure to match up with a well-known order. This method cleans up the input, injecting
// * the field names as necessary, and then calls the normal parsing logic.
// *
// * @param encodedParams parameter string
// * @param defaultFieldNames the well-known field ordering
// * @return a new ParameterMap, if parsing was successful
// */
// public static ParameterMap parsePositional(String encodedParams, String[] defaultFieldNames) {
//
// String[] splitAtSemi = encodedParams.split(";");
//
// for (int wordidx = 0; wordidx < splitAtSemi.length; wordidx++) {
//
// if (!splitAtSemi[wordidx].contains("=")) {
//
// if (wordidx > (defaultFieldNames.length - 1)) {
// throw new RuntimeException("positional param (without var=val; format) ran out of "
// + "positional field names:"
// + " names:" + Arrays.toString(defaultFieldNames)
// + ", values: " + Arrays.toString(splitAtSemi)
// + ", original: " + encodedParams
// );
// }
//
// splitAtSemi[wordidx] = defaultFieldNames[wordidx] + "=" + splitAtSemi[wordidx] + ";";
// }
// if (!splitAtSemi[wordidx].endsWith(";")) {
// splitAtSemi[wordidx] = splitAtSemi[wordidx] + ";";
// }
// }
//
// String allArgs = Arrays.asList(splitAtSemi).stream().collect(Collectors.joining());
// ParameterMap parameterMap = ParameterMap.parseOrException(allArgs);
// return parameterMap;
// }
public static interface Listener {
void handleParameterMapUpdate(ParameterMap parameterMap);
}
public Map getStringStringMap() {
return new HashMap() {{
for (Entry entry : ParameterMap.this.entrySet()) {
put(entry.getKey().toString(),entry.getValue().toString());
}
}};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy