/*
* Copyright 2009 NCHOVY
*
* 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.krakenapps.console;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.krakenapps.api.Script;
import org.krakenapps.api.ScriptArgument;
import org.krakenapps.api.ScriptAutoCompletion;
import org.krakenapps.api.ScriptAutoCompletionHelper;
import org.krakenapps.api.ScriptFactory;
import org.krakenapps.api.ScriptSession;
import org.krakenapps.api.ScriptUsage;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConsoleAutoComplete {
private final Logger logger = LoggerFactory.getLogger(ConsoleAutoComplete.class);
private BundleContext bundleContext;
public ConsoleAutoComplete(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public List<ScriptAutoCompletion> search(ScriptSession session, String prefix) {
String[] tokens = ScriptArgumentParser.tokenize(prefix);
List<ScriptAutoCompletion> terms = new ArrayList<ScriptAutoCompletion>();
if (tokens.length <= 1 && !prefix.endsWith(" ")) {
if (isScriptFactoryDetermined(prefix)) {
addScriptMethods(prefix, terms);
} else {
addScriptAliases(prefix, terms);
addScriptMethods("core." + prefix, terms);
}
} else {
try {
int p = tokens[0].indexOf('.');
String alias = p > 0 ? tokens[0].substring(0, p) : "core";
String method = p > 0 ? tokens[0].substring(p + 1) : tokens[0];
Script script = newScript(alias);
Method m = script.getClass().getDeclaredMethod(method, new Class[] { String[].class });
if (m == null)
return terms;
ScriptUsage usage = m.getAnnotation(ScriptUsage.class);
if (usage == null)
return terms;
int argIndex = prefix.endsWith(" ") ? tokens.length - 1 : tokens.length - 2;
ScriptArgument arg = null;
if (argIndex < usage.arguments().length)
arg = usage.arguments()[argIndex];
if (arg == null || arg.autocompletion() == ScriptAutoCompletionHelper.class)
return terms;
String nextToken = prefix.endsWith(" ") ? "" : tokens[tokens.length - 1];
ScriptAutoCompletionHelper helper = (ScriptAutoCompletionHelper) arg.autocompletion().newInstance();
return helper.matches(session, nextToken);
} catch (NoSuchMethodException e) {
logger.debug("kraken core: cannot auto-complete", e);
} catch (Throwable e) {
logger.error("kraken core: cannot auto-complete", e);
}
}
Collections.sort(terms, new Comparator<ScriptAutoCompletion>() {
@Override
public int compare(ScriptAutoCompletion o1, ScriptAutoCompletion o2) {
return o1.getSuggestion().compareTo(o2.getSuggestion());
}
});
return terms;
}
private boolean isScriptFactoryDetermined(String prefix) {
return prefix.indexOf('.') >= 0;
}
private void addScriptMethods(String prefix, List<ScriptAutoCompletion> terms) {
try {
String token = prefix.split(" ")[0];
int dotPos = token.indexOf('.');
String alias = token.substring(0, dotPos);
String methodPrefix = token.substring(dotPos + 1);
Script script = newScript(alias);
for (Method m : script.getClass().getMethods()) {
Class<?>[] paramTypes = m.getParameterTypes();
if (paramTypes == null || paramTypes.length == 0) {
continue;
}
if (!paramTypes[0].isArray())
continue;
if (methodPrefix.length() == 0 || (methodPrefix.length() > 0 && m.getName().startsWith(methodPrefix))) {
terms.add(new ScriptAutoCompletion(m.getName()));
}
}
} catch (NullPointerException e) {
// ignore
}
}
private Script newScript(String alias) {
ServiceReference[] refs;
try {
refs = bundleContext.getServiceReferences(ScriptFactory.class.getName(), "(alias=" + alias + ")");
if (refs == null || refs.length == 0) {
return null;
}
ScriptFactory scriptFactory = (ScriptFactory) bundleContext.getService(refs[0]);
Script script = scriptFactory.createScript();
return script;
} catch (InvalidSyntaxException e) {
return null;
}
}
private void addScriptAliases(String prefix, List<ScriptAutoCompletion> terms) {
try {
ServiceReference[] refs = bundleContext.getServiceReferences(ScriptFactory.class.getName(), null);
if (refs == null)
return;
for (int i = 0; i < refs.length; i++) {
if (refs[i].getProperty("alias") != null) {
String alias = refs[i].getProperty("alias").toString();
if (alias.startsWith(prefix))
terms.add(new ScriptAutoCompletion(alias));
}
}
} catch (InvalidSyntaxException e) {
// ignore
}
}
}