blob: 8efc1ae4386fbab87fbab177f05610ca5a3ce1db [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 org.apache.mrql;
import java.lang.reflect.Method;
import org.apache.mrql.gen.*;
import java.util.*;
/** imports external Java methods into MRQL */
final public class ClassImporter {
final static boolean trace_imported_methods = false;
final static String[] object_methods
= { "hashCode", "getClass", "wait", "equals", "toString", "notify", "notifyAll" };
static Vector<MethodInfo> methods = new Vector<MethodInfo>();
public static void load_classes () {
if (methods == null)
methods = new Vector<MethodInfo>();
if (methods.size() == 0) {
importClass("org.apache.mrql.SystemFunctions");
//****** import your classes with user-defined functions here
}
}
private static boolean object_method ( String s ) {
for (int i = 0; i < object_methods.length; i++)
if (object_methods[i].equals(s))
return true;
return false;
}
private static Tree getType ( Class<?> c ) {
String cn = c.getCanonicalName();
Class<?>[] inf = c.getInterfaces();
if (cn.equals("org.apache.mrql.MRData"))
return new VariableLeaf("any");
if (cn.startsWith("org.apache.mrql.MR_"))
return new VariableLeaf(cn.substring(19));
if (cn.equals("org.apache.mrql.Bag"))
return new Node("bag",new Trees(new VariableLeaf("any")));
if (cn.equals("org.apache.mrql.Inv"))
return new VariableLeaf("any");
if (cn.equals("org.apache.mrql.Union"))
return new VariableLeaf("union");
if (cn.equals("org.apache.mrql.Lambda"))
return new VariableLeaf("any");
if (inf.length > 0 && inf[0].equals("org.apache.mrql.MRData"))
return new VariableLeaf("any");
throw new Error("Unsupported type in imported method: "+cn);
}
private static Trees signature ( Method m ) {
Class<?> co = m.getReturnType();
Class<?>[] cs = m.getParameterTypes();
Trees as = new Trees(getType(co));
for (int i = 0; i < cs.length; i++)
as = as.append(getType(cs[i]));
return as;
}
public static String method_name ( int method_number ) {
return methods.get(method_number).name;
}
public static Trees signature ( int method_number ) {
return methods.get(method_number).signature;
}
/** import all Java methods from a given Java class */
public static void importClass ( String class_name ) {
try {
Method[] ms = Class.forName(class_name).getMethods();
Vector<MethodInfo> mv = new Vector<MethodInfo>();
for (int i = 0; i < ms.length; i++)
if (!object_method(ms[i].getName()) && ms[i].getModifiers() == 9)
try {
Trees sig = signature(ms[i]);
MethodInfo m = new MethodInfo(ms[i].getName(),sig,ms[i]);
mv.add(m);
methods.add(m);
} catch ( Exception e ) {
System.out.println("Warning: method "+ms[i].getName()+" cannot be imported");
System.out.println(e);
throw new Error("");
};
Collections.sort(methods);
if (Translator.functions == null)
Translator.functions = Trees.nil;
for ( MethodInfo m: methods )
Translator.functions = Translator.functions.append(new Node(m.name,m.signature));
if (trace_imported_methods) {
System.out.print("Importing methods: ");
for (int i = 0; i < mv.size(); i++ )
System.out.print(mv.get(i).name+mv.get(i).signature.tail()
+":"+mv.get(i).signature.head()+" ");
System.out.println();
}
} catch (ClassNotFoundException x) {
throw new Error("Undefined class: "+class_name);
}
}
/** import a Java method with a given name from a given Java class */
public static void importMethod ( String class_name, String method_name ) {
try {
Method[] ms = Class.forName(class_name).getMethods();
MethodInfo m = null;
for (int i = 0; i < ms.length; i++)
if (ms[i].getName().equals(method_name)
&& !object_method(ms[i].getName()) && ms[i].getModifiers() == 9) {
Trees sig = signature(ms[i]);
m = new MethodInfo(ms[i].getName(),sig,ms[i]);
Translator.functions = Translator.functions.append(new Node(ms[i].getName(),sig));
break;
};
if (m == null)
throw new Error("No such method: "+method_name);
methods.add(m);
Collections.sort(methods);
if (trace_imported_methods)
System.out.println("Importing method: "+m.name+m.signature.tail()
+":"+m.signature.head()+" ");
} catch (ClassNotFoundException x) {
throw new Error("Undefined class: "+class_name);
}
}
public static void print_methods () {
for (int i = 0; i < methods.size(); i++ ) {
MethodInfo m = methods.get(i);
System.out.print(" "+m.name+":"+m.signature.tail()+"->"+m.signature.head());
};
}
/** return the method specification of a system method with a given name over some expressions;
* When the method is overloaded, find the most specific (in terms of arg subtyping)
* @param method_name the given method name
* @param args the method expressions
* @return the method specification
*/
public static Tree find_method ( String method_name, Trees args ) {
for (int i = 0; i < methods.size(); i++ ) {
MethodInfo m = methods.get(i);
if (m.name.equals(method_name) && TypeInference.subtype(args,m.signature.tail()))
return m.signature.head();
};
return null;
}
/** return the method number of a system method with a given name over some expressions;
* When the method is overloaded, find the most specific (in terms of arg subtyping)
* @param method_name the given method name
* @param args the method expressions
* @return the method number
*/
public static int find_method_number ( String method_name, Trees args ) {
for (int i = 0; i < methods.size(); i++ ) {
MethodInfo m = methods.get(i);
if (m.name.equals(method_name) && TypeInference.subtype(args,m.signature.tail()))
return i;
};
return -1;
}
/** call a system method with a given number over MRData
* @param method_number the method number
* @param args in input arguments
* @return the result of invoking this method over the args
*/
public static MRData call ( int method_number, MRData... args ) {
if (method_number < 0 || method_number >= methods.size())
throw new Error("Run-time error (unknown method name)");
MethodInfo m = methods.get(method_number);
try {
return (MRData)m.method.invoke(null,(Object[])args);
} catch (Exception e) {
Tuple t = new Tuple(args.length);
for ( int i = 0; i < args.length; i++ )
t.set(i,args[i]);
System.err.println("Run-time error in method call: "+m.name+t+" of type "
+m.signature.tail()+"->"+m.signature.head());
throw new Error(e.toString());
}
}
}