/**
* Copyright 2007-2015, Kaazing Corporation. All rights reserved.
*
* 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 org.kaazing.k3po.lang.el;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.el.ELException;
import org.kaazing.k3po.lang.el.spi.FunctionMapperSpi;
/**
* Spi for Function in the K3PO Language.
*
*/
public final class FunctionMapper extends javax.el.FunctionMapper {
private final Map<String, FunctionMapperSpi> functionMapperSpis;
private FunctionMapper(Map<String, FunctionMapperSpi> functionMapperSpis) {
this.functionMapperSpis = functionMapperSpis;
}
/**
* Creates a new Function Mapper.
* @return returns an instance of the FunctionMapper
*/
public static FunctionMapper newFunctionMapper() {
ServiceLoader<FunctionMapperSpi> loader = loadFunctionMapperSpi();
// load FunctionMapperSpi instances
ConcurrentMap<String, FunctionMapperSpi> functionMappers = new ConcurrentHashMap<>();
for (FunctionMapperSpi functionMapperSpi : loader) {
String prefixName = functionMapperSpi.getPrefixName();
FunctionMapperSpi oldFunctionMapperSpi = functionMappers.putIfAbsent(prefixName, functionMapperSpi);
if (oldFunctionMapperSpi != null) {
throw new ELException(String.format("Duplicate prefix function mapper: %s", prefixName));
}
}
return new FunctionMapper(functionMappers);
}
/**
* Resolves a Function via prefix and local name.
* @param prefix of the function
* @param localName of the function
* @return an instance of a Method
*/
public Method resolveFunction(String prefix, String localName) {
FunctionMapperSpi functionMapperSpi = findFunctionMapperSpi(prefix);
return functionMapperSpi.resolveFunction(localName);
}
private static ServiceLoader<FunctionMapperSpi> loadFunctionMapperSpi() {
Class<FunctionMapperSpi> service = FunctionMapperSpi.class;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return (classLoader != null) ? ServiceLoader.load(service, classLoader) : ServiceLoader.load(service);
}
private FunctionMapperSpi findFunctionMapperSpi(String prefix) throws ELException {
if (prefix == null) {
throw new NullPointerException("prefix");
}
FunctionMapperSpi functionMapper = functionMapperSpis.get(prefix);
if (functionMapper == null) {
throw new ELException(String.format("Unable to load prefix '%s': No appropriate function mapper found",
prefix));
}
return functionMapper;
}
}