001 package org.crsh.shell.impl; 002 003 import groovy.lang.GroovyClassLoader; 004 import groovy.lang.GroovyCodeSource; 005 import groovy.lang.Script; 006 import org.codehaus.groovy.control.CompilationFailedException; 007 import org.codehaus.groovy.control.CompilerConfiguration; 008 import org.crsh.command.CommandInvoker; 009 import org.crsh.command.GroovyScriptCommand; 010 import org.crsh.command.NoSuchCommandException; 011 import org.crsh.plugin.PluginContext; 012 import org.crsh.plugin.ResourceKind; 013 import org.crsh.shell.ErrorType; 014 import org.crsh.util.TimestampedObject; 015 import org.crsh.vfs.Resource; 016 017 import java.util.Map; 018 import java.util.concurrent.ConcurrentHashMap; 019 020 /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */ 021 class ClassManager<T> { 022 023 /** . */ 024 private final Map<String, TimestampedObject<Class<? extends T>>> classes = new ConcurrentHashMap<String, TimestampedObject<Class<? extends T>>>(); 025 026 /** . */ 027 private final PluginContext context; 028 029 /** . */ 030 private final Class<? extends Script> baseScriptClass; 031 032 /** . */ 033 private final CompilerConfiguration config; 034 035 /** . */ 036 private final Class<T> baseClass; 037 038 /** . */ 039 private final ResourceKind kind; 040 041 ClassManager(PluginContext context, ResourceKind kind, Class<T> baseClass, Class<? extends Script> baseScriptClass) { 042 CompilerConfiguration config = new CompilerConfiguration(); 043 config.setRecompileGroovySource(true); 044 config.setScriptBaseClass(GroovyScriptCommand.class.getName()); 045 046 // 047 this.context = context; 048 this.baseScriptClass = baseScriptClass; 049 this.config = config; 050 this.baseClass = baseClass; 051 this.kind = kind; 052 } 053 054 Class<? extends T> getClass(String name) throws NoSuchCommandException, NullPointerException { 055 if (name == null) { 056 throw new NullPointerException("No null argument allowed"); 057 } 058 059 TimestampedObject<Class<? extends T>> providerRef = classes.get(name); 060 061 // 062 Resource script = context.loadResource(name, kind); 063 064 // 065 if (script != null) { 066 if (providerRef != null) { 067 if (script.getTimestamp() != providerRef.getTimestamp()) { 068 providerRef = null; 069 } 070 } 071 072 // 073 if (providerRef == null) { 074 075 Class<?> clazz; 076 try { 077 GroovyCodeSource gcs = new GroovyCodeSource(script.getContent(), name, "/groovy/shell"); 078 GroovyClassLoader gcl = new GroovyClassLoader(context.getLoader(), config); 079 clazz = gcl.parseClass(gcs, false); 080 } 081 catch (CompilationFailedException e) { 082 throw new NoSuchCommandException(name, ErrorType.INTERNAL, "Could not compile command script " + name, e); 083 } 084 085 // 086 if (baseClass.isAssignableFrom(clazz)) { 087 Class<? extends T> providerClass = clazz.asSubclass(baseClass); 088 providerRef = new TimestampedObject<Class<? extends T>>(script.getTimestamp(), providerClass); 089 classes.put(name, providerRef); 090 } else { 091 throw new NoSuchCommandException(name, ErrorType.INTERNAL, "Parsed script " + clazz.getName() + 092 " does not implements " + CommandInvoker.class.getName()); 093 } 094 } 095 } 096 097 // 098 if (providerRef == null) { 099 return null; 100 } 101 102 // 103 return providerRef.getObject(); 104 } 105 106 T getInstance(String name) throws NoSuchCommandException, NullPointerException { 107 Class<? extends T> clazz = getClass(name); 108 if (clazz == null) { 109 return null; 110 } 111 112 // 113 try { 114 return clazz.newInstance(); 115 } 116 catch (Exception e) { 117 throw new NoSuchCommandException(name, ErrorType.INTERNAL, "Could not create command " + name + " instance", e); 118 } 119 } 120 }