/**
* Copyright 2013 Netflix, Inc.
*
* 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 rx.util.functions;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import org.jackhuang.hellominecraft.logging.logger.Logger;
/**
* Allows execution of functions from multiple different languages.
*
* Language support is provided via implementations of {@link FunctionLanguageAdaptor}.
*
* This class will dynamically look for known language adaptors on the classpath at startup or new ones can be registered using {@link #registerLanguageAdaptor(Class[], FunctionLanguageAdaptor)}.
*/
public class Functions {
private static final Logger logger = new Logger("Functions");
private final static ConcurrentHashMap, FunctionLanguageAdaptor> languageAdaptors = new ConcurrentHashMap, FunctionLanguageAdaptor>();
static {
/* optimistically look for supported languages if they are in the classpath */
loadLanguageAdaptor("Groovy");
loadLanguageAdaptor("JRuby");
loadLanguageAdaptor("Clojure");
loadLanguageAdaptor("Scala");
// as new languages arise we can add them here but this does not prevent someone from using 'registerLanguageAdaptor' directly
}
private static boolean loadLanguageAdaptor(String name) {
String className = "rx.lang." + name.toLowerCase() + "." + name + "Adaptor";
try {
Class> c = Class.forName(className);
FunctionLanguageAdaptor a = (FunctionLanguageAdaptor) c.newInstance();
registerLanguageAdaptor(a.getFunctionClass(), a);
logger.info("Successfully loaded function language adaptor: " + name + " with path: " + className);
} catch (ClassNotFoundException e) {
logger.info("Could not find function language adaptor: " + name + " with path: " + className);
return false;
} catch (Exception e) {
logger.error("Failed trying to initialize function language adaptor: " + className, e);
return false;
}
return true;
}
public static void registerLanguageAdaptor(Class>[] functionClasses, FunctionLanguageAdaptor adaptor) {
for (Class> functionClass : functionClasses) {
if (functionClass.getPackage().getName().startsWith("java.")) {
throw new IllegalArgumentException("FunctionLanguageAdaptor implementations can not specify java.lang.* classes.");
}
languageAdaptors.put(functionClass, adaptor);
}
}
public static void removeLanguageAdaptor(Class> functionClass) {
languageAdaptors.remove(functionClass);
}
public static Collection getRegisteredLanguageAdaptors() {
return languageAdaptors.values();
}
/**
* Utility method for determining the type of closure/function and executing it.
*
* @param function
*/
@SuppressWarnings({ "rawtypes" })
public static FuncN from(final Object function) {
if (function == null) {
throw new RuntimeException("function is null. Can't send arguments to null function.");
}
/* check for typed Rx Function implementation first */
if (function instanceof Function) {
return fromFunction((Function) function);
} else {
/* not an Rx Function so try language adaptors */
// check for language adaptor
for (final Class c : languageAdaptors.keySet()) {
if (c.isInstance(function)) {
final FunctionLanguageAdaptor la = languageAdaptors.get(c);
// found the language adaptor so wrap in FuncN and return
return new FuncN() {
@Override
public Object call(Object... args) {
return la.call(function, args);
}
};
}
}
// no language adaptor found
}
// no support found
throw new RuntimeException("Unsupported closure type: " + function.getClass().getSimpleName());
}
//
// @SuppressWarnings("unchecked")
// private static R executionRxFunction(Function function, Object... args) {
// // check Func* classes
// if (function instanceof Func0) {
// Func0 f = (Func0) function;
// if (args.length != 0) {
// throw new RuntimeException("The closure was Func0 and expected no arguments, but we received: " + args.length);
// }
// return (R) f.call();
// } else if (function instanceof Func1) {
// Func1