/*
* Copyright 2014 TWO SIGMA OPEN SOURCE, LLC
*
* 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 com.twosigma.beaker.autocomplete;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ClassUtils {
protected ClassLoader loader;
private Map<String, String> typeMap;
private Map<String, String> classToTypeMap;
public final int DO_STATIC = 0;
public final int DO_NON_STATIC = 1;
public final int DO_ALL = 2;
public ClassUtils(ClassLoader l) {
loader = l;
typeMap = new HashMap<String, String>();
classToTypeMap = new HashMap<String, String>();
}
public ClassUtils() {
loader = null;
typeMap = new HashMap<String, String>();
classToTypeMap = new HashMap<String, String>();
}
public void clear() {
typeMap.clear();
classToTypeMap.clear();
}
public void defineVariable(String name, String type) {
typeMap.put(name, type);
}
public String getVariableType(String name) {
return typeMap.get(name);
}
public void defineClassShortName(String name, String fqname) {
classToTypeMap.put(name, fqname);
}
protected Class<?> getClass(String name) throws ClassNotFoundException {
try {
if(loader!=null) return loader.loadClass(name);
return Class.forName(name);
} catch(Exception e) { return null; }
}
public AutocompleteCandidate expandExpression(String txt, AutocompleteRegistry registry, int type) {
if(!txt.contains("."))
return null;
boolean endsWithDot = txt.endsWith(".");
Pattern p = Pattern.compile("((?:[a-zA-Z$_][a-zA-Z0-9$_]*(?:\\(.*\\))?\\.\\s*)+)$");
Matcher m;
if(!endsWithDot)
m = p.matcher(txt.substring(0,txt.lastIndexOf('.')+1));
else
m = p.matcher(txt);
if(m.find()) {
try {
//System.out.println("using "+m.group(0));
String [] v = m.group(0).split("\\.");
String curtype;
String n = v[0].trim();
// find starting type
if(typeMap.containsKey(n))
curtype = typeMap.get(n);
else
curtype = n;
// decode starting type
if (classToTypeMap.containsKey(curtype))
curtype = classToTypeMap.get(curtype);
for(int i=1; i<v.length; i++) {
// get next field type
String field = v[i];
//System.out.println("looking up "+field);
String ntype = null;
Class<?> cl = getClass(curtype);
if(cl==null) {
//System.out.println("not found "+curtype);
return null;
}
if(field.contains("(")) {
field = field.substring(0, field.indexOf('('));
Method[] mtn = cl.getMethods();
for(int j=0; j<mtn.length; j++) {
if(mtn[j].getName().equals(field) && Modifier.isPublic(mtn[j].getModifiers()) &&
((Modifier.isStatic(mtn[j].getModifiers()) && (type != DO_NON_STATIC)) ||
(!Modifier.isStatic(mtn[j].getModifiers()) && (type != DO_STATIC)))
) {
ntype = mtn[j].getReturnType().getCanonicalName();
break;
}
}
} else {
Field[] flds = cl.getFields();
for ( Field f : flds) {
if(f.getName().equals(field) && Modifier.isPublic(f.getModifiers()) &&
((Modifier.isStatic(f.getModifiers()) && (type != DO_NON_STATIC)) ||
(!Modifier.isStatic(f.getModifiers()) && (type != DO_STATIC)))
) {
ntype = f.getType().getCanonicalName();
break;
}
}
}
if(ntype==null) {
//System.out.println("cannot find type for "+field);
return null;
}
curtype = ntype;
}
// now get last field options
AutocompleteCandidate c = new AutocompleteCandidate(GenericCompletionTypes.FIELD, v, v.length);
AutocompleteCandidate l = c;
while(l.hasChildren()) l = l.getChildrens().get(0);
Class<?> cl = getClass(curtype);
if(cl==null) {
//System.out.println("not found "+curtype);
return null;
}
Field[] fl = cl.getFields();
Method[] mt = cl.getMethods();
if(fl!=null) {
for (Field f : fl) {
if(!f.getName().contains("$") && Modifier.isPublic(f.getModifiers()) &&
((Modifier.isStatic(f.getModifiers()) && (type != DO_NON_STATIC)) ||
(!Modifier.isStatic(f.getModifiers()) && (type != DO_STATIC))) ) {
AutocompleteCandidate c2 = new AutocompleteCandidate(GenericCompletionTypes.FIELD, f.getName());
l.addChildren(c2);
}
}
}
if(mt != null) {
for (Method mm : mt) {
if(!mm.getName().contains("$") && Modifier.isPublic(mm.getModifiers()) &&
((Modifier.isStatic(mm.getModifiers()) && (type != DO_NON_STATIC)) ||
(!Modifier.isStatic(mm.getModifiers()) && (type != DO_STATIC))) ) {
String mtn = mm.getName();
Class<?>[] pt = mm.getParameterTypes();
if(pt!=null) {
mtn += "(";
for(int id=0; id<pt.length; id++) {
if(id>0) mtn += ",";
int idx = pt[id].getName().lastIndexOf('.');
if(idx<0) idx=0; else idx++;
mtn += "a"+pt[id].getName().substring(idx);
}
mtn += ")";
} else
mtn += "()";
AutocompleteCandidate c2 = new AutocompleteCandidate(GenericCompletionTypes.FIELD, mtn);
l.addChildren(c2);
}
}
}
registry.addCandidate(c);
// output our query
c = new AutocompleteCandidate(GenericCompletionTypes.FIELD, v);
l = c;
while(l.hasChildren()) l = l.getChildrens().get(0);
if(endsWithDot)
l.addChildren(new AutocompleteCandidate(GenericCompletionTypes.FIELD, ""));
else
l.addChildren(new AutocompleteCandidate(GenericCompletionTypes.FIELD, txt.substring(txt.lastIndexOf('.')+1)));
return c;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
}