/*
* Copyright (C) 2012 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.crsh.lang;
import org.crsh.lang.impl.script.ScriptCompiler;
import org.crsh.lang.spi.Compiler;
import org.crsh.lang.spi.Language;
import org.crsh.plugin.PluginContext;
import org.crsh.plugin.ResourceKind;
import org.crsh.shell.impl.command.spi.Command;
import org.crsh.shell.impl.command.spi.CommandException;
import org.crsh.shell.impl.command.spi.CommandResolver;
import org.crsh.lang.spi.CommandResolution;
import org.crsh.util.TimestampedObject;
import org.crsh.vfs.Resource;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A shell command resolver for languages.
*
* @author Julien Viet
*/
public class LanguageCommandResolver implements CommandResolver {
/** . */
private final Map<String, TimestampedObject<CommandResolution>> commandCache = new ConcurrentHashMap<String, TimestampedObject<CommandResolution>>();
/** . */
final HashMap<String, Compiler> activeCompilers = new HashMap<String, Compiler>();
/** . */
final PluginContext context;
public LanguageCommandResolver(PluginContext context) {
//
activeCompilers.put("script", ScriptCompiler.getInstance());
//
for (Language lang : context.getPlugins(Language.class)) {
if (lang.isActive()) {
Compiler compiler = lang.getCompiler();
if (compiler != null) {
for (String ext : compiler.getExtensions()) {
activeCompilers.put(ext, compiler);
}
}
}
}
this.context = context;
}
public Compiler getCompiler(String name) {
return activeCompilers.get(name);
}
@Override
public Iterable<Map.Entry<String, String>> getDescriptions() {
LinkedHashMap<String, String> commands = new LinkedHashMap<String, String>();
for (String resourceName : context.listResources(ResourceKind.COMMAND)) {
int index = resourceName.indexOf('.');
String name = resourceName.substring(0, index);
String ext = resourceName.substring(index + 1);
if (activeCompilers.containsKey(ext)) {
try {
CommandResolution resolution = resolveCommand2(name);
commands.put(name, resolution.getDescription());
}
catch (CommandException e) {
//
}
}
}
return commands.entrySet();
}
@Override
public Command<?> resolveCommand(String name) throws CommandException, NullPointerException {
CommandResolution resolution = resolveCommand2(name);
return resolution != null ? resolution.getCommand() : null;
}
private CommandResolution resolveCommand2(String name) throws CommandException, NullPointerException {
for (Compiler manager : activeCompilers.values()) {
for (String ext : manager.getExtensions()) {
Iterable<Resource> resources = context.loadResources(name + "." + ext, ResourceKind.COMMAND);
for (Resource resource : resources) {
CommandResolution resolution = resolveCommand(manager, name, resource);
if (resolution != null) {
return resolution;
}
}
}
}
return null;
}
private CommandResolution resolveCommand(org.crsh.lang.spi.Compiler manager, String name, Resource script) throws CommandException {
TimestampedObject<CommandResolution> ref = commandCache.get(name);
if (ref != null) {
if (script.getTimestamp() != ref.getTimestamp()) {
ref = null;
}
}
CommandResolution command;
if (ref == null) {
command = manager.compileCommand(name, script.getContent());
if (command != null) {
commandCache.put(name, new TimestampedObject<CommandResolution>(script.getTimestamp(), command));
}
} else {
command = ref.getObject();
}
return command;
}
}