/**
* Copyright 2005-2016 Red Hat, Inc.
*
* Red Hat 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.fabric8.karaf.core.properties;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import io.fabric8.karaf.core.Support;
import io.fabric8.karaf.core.properties.function.PropertiesFunction;
import org.apache.commons.lang3.text.StrLookup;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import static io.fabric8.kubernetes.client.utils.Utils.getSystemPropertyOrEnvVar;
@Component(
immediate = true,
policy = ConfigurationPolicy.IGNORE,
createPid = false
)
@Reference(
name = "function",
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
referenceInterface = PropertiesFunction.class
)
@Service(PlaceholderResolver.class)
public class PlaceholderResolverImpl implements PlaceholderResolver {
public static final String PLACEHOLDER_PREFIX = "fabric8.placeholder.prefix";
public static final String PLACEHOLDER_SUFFIX = "fabric8.placeholder.suffix";
public static final String DEFAULT_PLACEHOLDER_PREFIX = "$[";
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "]";
private final CopyOnWriteArrayList<PropertiesFunction> functions;
private final StrSubstitutor substitutor;
public PlaceholderResolverImpl() {
this.functions = new CopyOnWriteArrayList<>();
this.substitutor = Support.createStrSubstitutor(
getSystemPropertyOrEnvVar(PLACEHOLDER_PREFIX, DEFAULT_PLACEHOLDER_PREFIX),
getSystemPropertyOrEnvVar(PLACEHOLDER_SUFFIX, DEFAULT_PLACEHOLDER_SUFFIX),
new StrLookup<String>() {
@Override
public String lookup(String value) {
return resolve(value);
}
});
}
@Override
public String resolve(String value) {
String[] resolvers = Support.before(value, ":").split("\\+");
String remainder = Support.after(value, ":");
for (String resolver : resolvers) {
PropertiesFunction function = findFunction(resolver);
if (function == null) {
value = null;
break;
}
value = function.apply(remainder);
if (value != null) {
remainder = value;
} else {
break;
}
}
return value;
}
@Override
public String replace(String value) {
return substitutor.replace(value);
}
@Override
public boolean replaceIn(StringBuilder value) {
return substitutor.replaceIn(value);
}
@Override
public boolean replaceAll(Dictionary<String, Object> dictionary) {
int replacedCount = 0;
Enumeration<String> keys = dictionary.keys();
while(keys.hasMoreElements()) {
final String key = keys.nextElement();
final Object val = dictionary.get(key);
if (val instanceof String) {
StringBuilder sb = Support.acquireStringBuilder((String)val);
if (substitutor.replaceIn(sb)) {
replacedCount++;
dictionary.put(key, sb.toString());
}
}
}
return replacedCount > 0;
}
@Override
public boolean replaceAll(Map<String, Object> dictionary) {
int replacedCount = 0;
for(String key : dictionary.keySet()) {
final Object val = dictionary.get(key);
if (val instanceof String) {
StringBuilder sb = Support.acquireStringBuilder((String)val);
if (substitutor.replaceIn(sb)) {
replacedCount++;
dictionary.put(key, sb.toString());
}
}
}
return replacedCount > 0;
}
// ****************************
// Binding
// ****************************
protected void bindFunction(PropertiesFunction function) {
functions.addIfAbsent(function);
}
protected void unbindFunction(PropertiesFunction function) {
functions.remove(function);
}
// ****************************
// Helpers
// ****************************
private PropertiesFunction findFunction(String name) {
for (PropertiesFunction fun : functions) {
if (name.equals(fun.getName())) {
return fun;
}
}
return null;
}
}