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