/*
* Copyright 2012 Jason Miller
*
* 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 jj.configuration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.inject.Singleton;
import jj.conversion.Converters;
import jj.script.CurrentScriptEnvironment;
/**
* server component used to implement the configuration API. it's
* really just a set of hash maps and a facade to the conversion
* system
*
* @author jason
*
*/
@Singleton
public class ConfigurationCollector {
private final AtomicReference<Map<String, Object>> current = new AtomicReference<>();
private LinkedHashMap<String, List<String>> errors = new LinkedHashMap<>(0);
private HashMap<String, Object> inProgress = new HashMap<>();
private final Converters converters;
private final CurrentScriptEnvironment env;
@Inject
ConfigurationCollector(final Converters converters, final CurrentScriptEnvironment env) {
this.converters = converters;
this.env = env;
}
private void assertConfig() {
assert isConfig() : "only available from a config script";
}
public boolean isConfig() {
return env.currentRootScriptEnvironment() instanceof ConfigurationScriptEnvironment;
}
/**
* This is the interface for the API modules
*/
public void addConfigurationElement(String name, Object value) {
assertConfig();
inProgress.put(name, value);
}
public void addConfigurationMultiElement(String name, Object value) {
assertConfig();
if (!inProgress.containsKey(name)) {
inProgress.put(name, new ArrayList<>());
}
@SuppressWarnings("unchecked")
ArrayList<Object> list = ((ArrayList<Object>)inProgress.get(name));
list.add(value);
}
public void addConfigurationMappedElement(String name, Object key, Object value) {
assertConfig();
if (!inProgress.containsKey(name)) {
inProgress.put(name, new HashMap<>());
}
@SuppressWarnings("unchecked")
HashMap<Object, Object> map = ((HashMap<Object, Object>)inProgress.get(name));
map.put(key, value);
}
public void accumulateError(String name, String error) {
assertConfig();
errors.computeIfAbsent(name, k -> new ArrayList<>(1)).add(error);
}
<T> T get(String name, Class<T> type, Object defaultValue) {
Map<String, Object> map = current.get();
if (List.class.isAssignableFrom(type) && defaultValue == null) {
defaultValue = Collections.EMPTY_LIST;
}
if (Map.class.isAssignableFrom(type) && defaultValue == null) {
defaultValue = Collections.EMPTY_MAP;
}
return converters.convert(map != null && map.containsKey(name) ? map.get(name) : defaultValue, type);
}
ConfigurationErrored configurationComplete() {
if (!errors.isEmpty()) {
LinkedHashMap<String, List<String>> e = errors;
errors = new LinkedHashMap<>();
return new ConfigurationErrored(e);
}
for (String name : inProgress.keySet()) {
if (inProgress.get(name) instanceof List) {
List<?> list = Collections.unmodifiableList((List<?>)inProgress.get(name));
inProgress.put(name, list);
}
if (inProgress.get(name) instanceof Map) {
Map<?, ?> map = Collections.unmodifiableMap((Map<?, ?>)inProgress.get(name));
inProgress.put(name, map);
}
}
current.set(Collections.unmodifiableMap(inProgress));
inProgress = new HashMap<>();
return null;
}
@Override
public String toString() {
return getClass().getSimpleName() + "(current = " + current + ")";
}
}