    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    }