PageRenderTime 457ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/de/indisopht/guice/groovy/GroovyGuice.java

http://groovy-guice.googlecode.com/
Java | 395 lines | 156 code | 36 blank | 203 comment | 6 complexity | 6bd740ac9a5274438ff5fbb0dcd37d71 MD5 | raw file
Possible License(s): Apache-2.0
  1. /**
  2. * Copyright (C) 2009 Stefan Maassen
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package de.indisopht.guice.groovy;
  17. import groovy.lang.GroovyClassLoader;
  18. import groovy.lang.GroovyCodeSource;
  19. import groovy.lang.Script;
  20. import java.io.Reader;
  21. import java.lang.annotation.Annotation;
  22. import java.security.AccessController;
  23. import java.security.PrivilegedAction;
  24. import java.util.ArrayList;
  25. import java.util.Collection;
  26. import java.util.Collections;
  27. import java.util.HashMap;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.Map.Entry;
  31. import org.apache.log4j.Logger;
  32. import org.codehaus.groovy.control.CompilationFailedException;
  33. import org.codehaus.groovy.control.ConfigurationException;
  34. import org.osgi.framework.Bundle;
  35. import com.google.inject.AbstractModule;
  36. import com.google.inject.Guice;
  37. import com.google.inject.Injector;
  38. import com.google.inject.Key;
  39. import com.google.inject.Module;
  40. import de.indisopht.guice.groovy.internal.BridgedClassLoader;
  41. import de.indisopht.guice.groovy.internal.GroovyClassloaderFactory;
  42. import de.indisopht.guice.groovy.internal.annotations.GroovyGuiceInternal;
  43. /**
  44. * Fluent API for configuring the environment
  45. * of {@link Module}s with bindings to Groovy source
  46. * files
  47. *
  48. * <br>Basic Usage:<br>
  49. * <code><pre>
  50. * Module groovyGuiceModule = GroovyGuice
  51. * .create()
  52. * .addClasspath(classpath)
  53. * .build();</pre>
  54. * Guice.createInjector(myModule, groovyGuiceModule);<br>
  55. * </code>
  56. *
  57. * <br>Example bindings:<br>
  58. *
  59. * <pre><b>Binding a groovy class to a java interface</b><code>
  60. * bind(TestInterface.class).toProvider(new GroovyProvider&lt;TestInterface&gt;("TestClass"){});
  61. * </code>
  62. * <b>Binding grovvy code inside a string to a java class</b><code>
  63. * bind(MyClass.class).to(new GroovyProvider&lt;MyClass&gt;(&quot;import a.b.c; class B extends MyClass { }&quot;){});
  64. * </code>
  65. * <b>Binding a grovvy script inside a string</b><code>
  66. * bind(Script.class).toProvider(new GroovyProvider&lt;Script&gt;(&quot;println('groovy hello'); 'groovy'&quot;){});
  67. * </code>
  68. * <b>Binding a grovvy script from a file</b><code>
  69. * bind(Script.class).toProvider(new GroovyProvider&lt;Script&gt;(&quot;TestScript&quot;){});
  70. * </code>
  71. *
  72. * @author Stefan Maassen
  73. * @since 0.3.0
  74. *
  75. */
  76. public class GroovyGuice {
  77. private static final Logger logger=Logger.getLogger(GroovyGuice.class);
  78. /**
  79. * start configuration based on the
  80. * given modules
  81. *
  82. * @param modules the modues to configure
  83. * @return {@link GroovyModuleBuilderInstance}
  84. *
  85. * @deprecated method is obsolete and will be removed in future release
  86. */
  87. @Deprecated
  88. public static GroovyModuleBuilderInstance create(Module... modules) {
  89. return new GroovyModuleBuilderInstance();
  90. }
  91. /**
  92. * the given {@link Module}s (as Groovy source files) will be installed additionally
  93. * while creating the {@link Injector}. All given {@link Module}s must have a standard
  94. * constructor without any parameters.
  95. * </br></br>Please note, that the given Modules won't be recompiled due to unknown
  96. * side-effects on internal Guice behaviour.
  97. *
  98. * @param sourceModules the {@link Module}s (as Groovy source files) to install
  99. * @return {@link GroovyModuleBuilderInstance}
  100. */
  101. public static GroovyModuleBuilderInstance createWithGroovyModules(String... sourceModules) {
  102. GroovyModuleBuilderInstance result = new GroovyModuleBuilderInstance();
  103. Collections.addAll(result.groovySourceModules, sourceModules);
  104. return result;
  105. }
  106. /**
  107. * start configuration with no module
  108. *
  109. * @return {@link GroovyModuleBuilderInstance}
  110. *
  111. * @deprecated use {@link GroovyGuice#createModule()} instead
  112. */
  113. public static GroovyModuleBuilderInstance createWithEmptyModule() {
  114. return new GroovyModuleBuilderInstance();
  115. }
  116. /**
  117. * start configuration with no module
  118. *
  119. * @return {@link GroovyModuleBuilderInstance}
  120. */
  121. public static GroovyModuleBuilderInstance createModule() {
  122. return new GroovyModuleBuilderInstance();
  123. }
  124. /**
  125. * Building Block of Fluent API
  126. *
  127. * @author Stefan Maassen
  128. * @since 0.3.0
  129. */
  130. public static class GroovyModuleBuilderInstance {
  131. /**
  132. * factory class for {@link GroovyClassLoader}
  133. */
  134. private GroovyClassloaderFactory classloaderFactory = new GroovyClassloaderFactory();
  135. /**
  136. * {@link Script}s to bind
  137. */
  138. Map<Key<Script>, String> scripts = new HashMap<Key<Script>, String>();
  139. /**
  140. * used for OSGi configuration
  141. */
  142. private Bundle bundle;
  143. /**
  144. * a list of all {@link Module} files to be installed additionally and given as Groovy
  145. * source files
  146. */
  147. private List<String> groovySourceModules = new ArrayList<String>();
  148. /**
  149. * add path to current Classpath for
  150. * Groovy
  151. *
  152. * @param path classpath
  153. * @return {@link GroovyModuleBuilderInstance}
  154. */
  155. public GroovyModuleBuilderInstance addClasspath(String path) {
  156. classloaderFactory.getClassPath().addClasspath(path);
  157. return this;
  158. }
  159. /**
  160. * please note:
  161. * if peaberry is used for integrating OSGi, configuring the bundle is optional
  162. *
  163. * @param b the bundle
  164. * @return {@link GroovyModuleBuilderInstance}
  165. */
  166. public GroovyModuleBuilderInstance forBundle(Bundle b) {
  167. this.bundle=b;
  168. return this;
  169. }
  170. /**
  171. * whether loaded classes should be resolved or
  172. * not
  173. * default: {@link GroovyClassloaderFactory#isResolve()}
  174. *
  175. * @param b boolean value
  176. * @return {@link GroovyModuleBuilderInstance}
  177. */
  178. public GroovyModuleBuilderInstance resolveClasses(Boolean b) {
  179. classloaderFactory.setResolve(b);
  180. return this;
  181. }
  182. /**
  183. * alternative method for {@link #resolveClasses(Boolean)}
  184. *
  185. * @param b string representing a boolean value
  186. * @return {@link GroovyModuleBuilderInstance}
  187. */
  188. public GroovyModuleBuilderInstance resolveClasses(String b) {
  189. classloaderFactory.setResolve(Boolean.parseBoolean(b));
  190. return this;
  191. }
  192. /**
  193. * security configuration for the configured {@link Script}s
  194. *
  195. * @see SecurityManager
  196. * @see GroovyCodeSource#GroovyCodeSource(Reader, String, String)
  197. * @see <a href="http://docs.codehaus.org/display/GROOVY/Security">Groovy Security</a>
  198. *
  199. * @param base the code base to use
  200. * @return {@link GroovyModuleBuilderInstance}
  201. */
  202. public GroovyModuleBuilderInstance useCodeBase(String base) {
  203. classloaderFactory.setCodeBase(base);
  204. return this;
  205. }
  206. /**
  207. * enables recompilation of Groovy source files
  208. *
  209. * @return {@link GroovyModuleBuilderInstance}
  210. */
  211. public GroovyModuleBuilderInstance enableRecompilation() {
  212. classloaderFactory.setRecompile(true);
  213. return this;
  214. }
  215. /**
  216. * disables recompilation of Groovy source files
  217. *
  218. * @return {@link GroovyModuleBuilderInstance}
  219. */
  220. public GroovyModuleBuilderInstance disableRecompilation() {
  221. classloaderFactory.setRecompile(false);
  222. return this;
  223. }
  224. /**
  225. * starts a subpart of this Fluent API
  226. * for configuring scripts
  227. *
  228. * @param script the script
  229. * @return {@link ScriptBindConfig}
  230. */
  231. public ScriptBindConfig script(String script) {
  232. return new ScriptBindConfig(this, script);
  233. }
  234. /**
  235. * convinience method for configuring scripts
  236. *
  237. * @param script the script
  238. * @return {@link ScriptBindConfig}
  239. */
  240. public GroovyModuleBuilderInstance bindScript(String script) {
  241. return new ScriptBindConfig(this, script).bind();
  242. }
  243. /**
  244. * convinience method for configuring scripts with
  245. * an annotation
  246. *
  247. * @param script the script
  248. * @return {@link ScriptBindConfig}
  249. */
  250. public GroovyModuleBuilderInstance bindScript(String script, Annotation annotation) {
  251. return new ScriptBindConfig(this, script).bindWithAnnotation(annotation);
  252. }
  253. /**
  254. * finally builds some modules ready
  255. * for injection.
  256. * Please note, that given {@link Module}s
  257. * at {@link GroovyGuice#create(Module...)} must be given
  258. * to {@link Guice#createInjector(Module...)} as parameter
  259. *
  260. * @return {@link Collection} of {@link Module}s
  261. */
  262. public Module build() {
  263. return new AbstractModule() {
  264. @Override
  265. protected void configure() {
  266. classloaderFactory.setBridgedClassloader(AccessController.doPrivileged(new PrivilegedAction<BridgedClassLoader>() {
  267. public BridgedClassLoader run() {
  268. return new BridgedClassLoader(Thread.currentThread().getContextClassLoader(), bundle);
  269. }
  270. }));
  271. bind(GroovyClassLoader.class).annotatedWith(GroovyGuiceInternal.class).toInstance(classloaderFactory.createGroovyClassLoader());
  272. bind(GroovyClassloaderFactory.class).toInstance(classloaderFactory);
  273. for (final Entry<Key<Script>, String> currentEntry : scripts.entrySet()) {
  274. AccessController.doPrivileged(new PrivilegedAction<Void>() {
  275. @Override
  276. public Void run() {
  277. bind(currentEntry.getKey()).toProvider(new GroovyProvider<Script>(currentEntry.getValue()){});
  278. return null;
  279. }
  280. });
  281. }
  282. GroovyClassLoader gcl=classloaderFactory.createGroovyClassLoader();
  283. for (String currentSourceModule : groovySourceModules) {
  284. try {
  285. logger.info("installing Groovy module ["+currentSourceModule+"] ");
  286. install((Module)gcl.loadClass(currentSourceModule).newInstance());
  287. logger.debug("installed successfully Groovy module ["+currentSourceModule+"] ");
  288. } catch (InstantiationException e) {
  289. throw new ConfigurationException(e);
  290. } catch (IllegalAccessException e) {
  291. throw new ConfigurationException(e);
  292. } catch (CompilationFailedException e) {
  293. throw new ConfigurationException(e);
  294. } catch (ClassNotFoundException e) {
  295. throw new ConfigurationException(e);
  296. }
  297. }
  298. }
  299. };
  300. }
  301. }
  302. /**
  303. * Building Block of Fluent API
  304. * for binding {@link Script}s on the fly.
  305. *
  306. * @author Stefan Maassn
  307. *@since 0.3.0
  308. *
  309. */
  310. public static class ScriptBindConfig {
  311. private final GroovyModuleBuilderInstance parent;
  312. private final String script;
  313. private Annotation keyAnnotation=null;
  314. public ScriptBindConfig(GroovyModuleBuilderInstance parent, String script) {
  315. this.parent=parent;
  316. this.script=script;
  317. }
  318. /**
  319. * configure an {@link Annotation} for this script
  320. *
  321. * @param annotation
  322. * @return {@link ScriptBindConfig}
  323. *
  324. * @deprecated will be removed in future release; use {@link ScriptBindConfig#bindWithAnnotation(Annotation)} instead
  325. */
  326. public ScriptBindConfig withAnnotation(Annotation annotation) {
  327. this.keyAnnotation=annotation;
  328. return this;
  329. }
  330. /**
  331. * final step for configuring a {@link Script} on
  332. * the fly
  333. *
  334. * @return {@link GroovyModuleBuilderInstance}
  335. */
  336. public GroovyModuleBuilderInstance bind() {
  337. if (keyAnnotation!=null) {
  338. parent.scripts.put(Key.get(Script.class, keyAnnotation), script);
  339. } else {
  340. parent.scripts.put(Key.get(Script.class), script);
  341. }
  342. return parent;
  343. }
  344. /**
  345. * final step for configuring a {@link Script} on
  346. * the fly with the given annotation
  347. *
  348. * @return {@link GroovyModuleBuilderInstance}
  349. */
  350. public GroovyModuleBuilderInstance bindWithAnnotation(Annotation annotation) {
  351. if (annotation!=null) {
  352. parent.scripts.put(Key.get(Script.class, annotation), script);
  353. } else {
  354. parent.scripts.put(Key.get(Script.class), script);
  355. }
  356. return parent;
  357. }
  358. }
  359. }