001 /*****************************************************************************
002 * Copyright (C) NanoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * Original code by Nick Sieger *
008 *****************************************************************************/
009
010 package org.nanocontainer.script.jruby;
011
012 import java.io.IOException;
013 import java.io.Reader;
014 import java.io.StringWriter;
015 import java.util.Collections;
016
017 import org.jruby.IRuby;
018 import org.jruby.exceptions.RaiseException;
019 import org.jruby.javasupport.JavaEmbedUtils;
020 import org.jruby.runtime.builtin.IRubyObject;
021 import org.nanocontainer.integrationkit.PicoCompositionException;
022 import org.nanocontainer.reflection.DefaultNanoPicoContainer;
023 import org.nanocontainer.script.NanoContainerMarkupException;
024 import org.nanocontainer.script.ScriptedContainerBuilder;
025 import org.picocontainer.PicoContainer;
026 import org.picocontainer.alternatives.EmptyPicoContainer;
027
028 /**
029 * The script uses the {@code nanocontainer.rb} script to create an instance of
030 * {@link PicoContainer}.
031 * There are implicit variables named "$parent" and "$assembly_scope".
032 *
033 * @author Nick Sieger
034 */
035 public class JRubyContainerBuilder extends ScriptedContainerBuilder {
036 public static final String MARKUP_EXCEPTION_PREFIX = "nanobuilder: ";
037
038 private String script;
039
040 public JRubyContainerBuilder(Reader script, ClassLoader classLoader) {
041 super(script, classLoader);
042 this.script = toString( script );
043 }
044
045 private String toString(Reader script) {
046 int charsRead;
047 char[] chars = new char[1024];
048 StringWriter writer = new StringWriter();
049 try {
050 while ((charsRead = script.read(chars)) != -1) {
051 writer.write(chars, 0, charsRead);
052 }
053 } catch (IOException e) {
054 throw new RuntimeException("unable to read script from reader", e);
055 }
056 return writer.toString();
057 }
058
059 protected PicoContainer createContainerFromScript(PicoContainer parentContainer, Object assemblyScope) {
060 if (parentContainer == null) {
061 parentContainer = new EmptyPicoContainer();
062 }
063 parentContainer = new DefaultNanoPicoContainer(getClassLoader(), parentContainer);
064
065 IRuby ruby = JavaEmbedUtils.initialize(Collections.EMPTY_LIST);
066 ruby.getLoadService().require("org/nanocontainer/script/jruby/nanobuilder");
067 ruby.defineReadonlyVariable("$parent", JavaEmbedUtils.javaToRuby(ruby, parentContainer));
068 ruby.defineReadonlyVariable("$assembly_scope", JavaEmbedUtils.javaToRuby(ruby, assemblyScope));
069 try {
070 IRubyObject result = ruby.evalScript(script);
071 return (PicoContainer) JavaEmbedUtils.rubyToJava(ruby, result, PicoContainer.class);
072 } catch (RaiseException re) {
073 if (re.getCause() instanceof NanoContainerMarkupException) {
074 throw (NanoContainerMarkupException) re.getCause();
075 }
076 String message = (String) JavaEmbedUtils.rubyToJava(ruby, re.getException().message, String.class);
077 if (message.startsWith(MARKUP_EXCEPTION_PREFIX)) {
078 throw new NanoContainerMarkupException(message.substring(MARKUP_EXCEPTION_PREFIX.length()));
079 } else {
080 throw new PicoCompositionException(message, re);
081 }
082 }
083 }
084 }