001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 package org.crsh.lang; 020 021 import org.crsh.lang.impl.script.ScriptCompiler; 022 import org.crsh.lang.spi.Compiler; 023 import org.crsh.lang.spi.Language; 024 import org.crsh.plugin.PluginContext; 025 import org.crsh.plugin.ResourceKind; 026 import org.crsh.shell.impl.command.spi.Command; 027 import org.crsh.shell.impl.command.spi.CommandException; 028 import org.crsh.shell.impl.command.spi.CommandResolver; 029 import org.crsh.lang.spi.CommandResolution; 030 import org.crsh.util.TimestampedObject; 031 import org.crsh.vfs.Resource; 032 033 import java.util.HashMap; 034 import java.util.LinkedHashMap; 035 import java.util.Map; 036 import java.util.concurrent.ConcurrentHashMap; 037 038 /** 039 * A shell command resolver for languages. 040 * 041 * @author Julien Viet 042 */ 043 public class LanguageCommandResolver implements CommandResolver { 044 045 /** . */ 046 private final Map<String, TimestampedObject<CommandResolution>> commandCache = new ConcurrentHashMap<String, TimestampedObject<CommandResolution>>(); 047 048 /** . */ 049 final HashMap<String, Compiler> activeCompilers = new HashMap<String, Compiler>(); 050 051 /** . */ 052 final PluginContext context; 053 054 public LanguageCommandResolver(PluginContext context) { 055 056 // 057 activeCompilers.put("script", ScriptCompiler.getInstance()); 058 059 // 060 for (Language lang : context.getPlugins(Language.class)) { 061 if (lang.isActive()) { 062 Compiler compiler = lang.getCompiler(); 063 if (compiler != null) { 064 for (String ext : compiler.getExtensions()) { 065 activeCompilers.put(ext, compiler); 066 } 067 } 068 } 069 } 070 071 this.context = context; 072 } 073 074 public Compiler getCompiler(String name) { 075 return activeCompilers.get(name); 076 } 077 078 @Override 079 public Iterable<Map.Entry<String, String>> getDescriptions() { 080 LinkedHashMap<String, String> commands = new LinkedHashMap<String, String>(); 081 for (String resourceName : context.listResources(ResourceKind.COMMAND)) { 082 int index = resourceName.indexOf('.'); 083 String name = resourceName.substring(0, index); 084 String ext = resourceName.substring(index + 1); 085 if (activeCompilers.containsKey(ext)) { 086 try { 087 CommandResolution resolution = resolveCommand2(name); 088 commands.put(name, resolution.getDescription()); 089 } 090 catch (CommandException e) { 091 // 092 } 093 } 094 } 095 return commands.entrySet(); 096 } 097 098 @Override 099 public Command<?> resolveCommand(String name) throws CommandException, NullPointerException { 100 CommandResolution resolution = resolveCommand2(name); 101 return resolution != null ? resolution.getCommand() : null; 102 } 103 104 private CommandResolution resolveCommand2(String name) throws CommandException, NullPointerException { 105 for (Compiler manager : activeCompilers.values()) { 106 for (String ext : manager.getExtensions()) { 107 Iterable<Resource> resources = context.loadResources(name + "." + ext, ResourceKind.COMMAND); 108 for (Resource resource : resources) { 109 CommandResolution resolution = resolveCommand(manager, name, resource); 110 if (resolution != null) { 111 return resolution; 112 } 113 } 114 } 115 } 116 return null; 117 } 118 119 private CommandResolution resolveCommand(org.crsh.lang.spi.Compiler manager, String name, Resource script) throws CommandException { 120 TimestampedObject<CommandResolution> ref = commandCache.get(name); 121 if (ref != null) { 122 if (script.getTimestamp() != ref.getTimestamp()) { 123 ref = null; 124 } 125 } 126 CommandResolution command; 127 if (ref == null) { 128 command = manager.compileCommand(name, script.getContent()); 129 if (command != null) { 130 commandCache.put(name, new TimestampedObject<CommandResolution>(script.getTimestamp(), command)); 131 } 132 } else { 133 command = ref.getObject(); 134 } 135 return command; 136 } 137 138 }