/*
* 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.InvocationTargetException;
import java.lang.reflect.Method;
import org.krakenapps.api.Script;
import org.krakenapps.api.ScriptArgument;
import org.krakenapps.api.ScriptContext;
import org.krakenapps.api.ScriptFactory;
import org.krakenapps.api.ScriptUsage;
import org.krakenapps.main.Kraken;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ScriptRunner implements Runnable {
private Logger logger = LoggerFactory.getLogger(ScriptRunner.class.getName());
private ScriptContext context;
private String methodName;
private String[] args;
private boolean isPromptEnabled = true;
public ScriptRunner(ScriptContext context, String line) {
String[] tokens = ScriptArgumentParser.tokenize(line.trim());
String[] commandTokens = tokens[0].split("\\.");
String alias = null;
if (commandTokens.length != 2) {
alias = "core";
this.methodName = commandTokens[0];
} else {
alias = commandTokens[0];
this.methodName = commandTokens[1];
}
this.context = context;
this.args = getArguments(tokens);
ServiceReference[] refs = null;
try {
refs = Kraken.getContext().getServiceReferences(ScriptFactory.class.getName(), "(alias=" + alias + ")");
} catch (InvalidSyntaxException e) {
e.printStackTrace();
}
if (refs == null || refs.length == 0)
throw new NullPointerException("script not found.");
ScriptFactory scriptFactory = (ScriptFactory) Kraken.getContext().getService(refs[0]);
if (scriptFactory == null) {
throw new NullPointerException("script not found.");
}
Script script = scriptFactory.createScript();
context.setCurrentScript(script);
Kraken.getContext().ungetService(refs[0]);
}
public void setPrompt(boolean enabled) {
this.isPromptEnabled = enabled;
}
private String[] getArguments(String[] tokens) {
String[] arguments = new String[tokens.length - 1];
for (int i = 1; i < tokens.length; ++i) {
arguments[i - 1] = tokens[i];
}
return arguments;
}
@Override
public void run() {
context.turnEchoOn();
context.getInputStream().flush();
Script script = context.getCurrentScript();
script.setScriptContext(context);
invokeScript(script);
if (isPromptEnabled)
context.printPrompt();
context.setCurrentScript(null);
}
private void invokeScript(Script script) {
Method method;
ScriptUsage usage = null;
try {
method = script.getClass().getDeclaredMethod(methodName, new Class[] { String[].class });
usage = method.getAnnotation(ScriptUsage.class);
verifyScriptArguments(usage, args);
method.invoke(script, (Object) args);
} catch (IllegalArgumentException e) {
if (usage == null) {
context.println("IllegalArgumentException, but no usage found. Please ask script author to add usage information.");
return;
}
if (usage.description() != null) {
context.println("Description");
context.println("");
context.println("\t" + usage.description());
context.println("");
}
if (usage.arguments() == null || usage.arguments().length == 0)
return;
context.println("Arguments\n");
int i = 1;
for (ScriptArgument argument : usage.arguments()) {
String optional = argument.optional() ? " (optional)" : " (required)";
context.println("\t" + i++ + ". " + argument.name() + ": " + argument.description() + optional);
}
} catch (SecurityException e) {
context.println(e.toString());
logger.warn("script runner: ", e);
} catch (NoSuchMethodException e) {
context.println("syntax error.");
logger.warn("script runner: {}.{} not found", script.getClass().getName(), methodName);
} catch (IllegalAccessException e) {
context.println("syntax error.");
logger.warn("script runner: {}.{} forbidden", script.getClass().getName(), methodName);
} catch (InvocationTargetException e) {
context.println(e.getTargetException().toString());
logger.warn("script runner: ", e);
}
}
private void verifyScriptArguments(ScriptUsage usage, String[] args) {
if (usage == null || usage.arguments() == null || usage.arguments().length == 0)
return;
if (countRequiredArguments(usage.arguments()) > args.length)
throw new IllegalArgumentException("arguments length does not match.");
// TODO: type match
}
private int countRequiredArguments(ScriptArgument[] args) {
int count = 0;
for (ScriptArgument arg : args) {
if (arg.optional() == false)
count++;
}
return count;
}
}