001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2013 Sebastian
003     * Thomschke.
004     *
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     *
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.expression;
014    
015    import java.util.ArrayList;
016    import java.util.Map;
017    import java.util.Map.Entry;
018    
019    import net.sf.oval.exception.ExpressionEvaluationException;
020    import net.sf.oval.internal.Log;
021    
022    import org.jruby.CompatVersion;
023    import org.jruby.Ruby;
024    import org.jruby.RubyInstanceConfig;
025    import org.jruby.javasupport.JavaEmbedUtils;
026    import org.jruby.runtime.builtin.IRubyObject;
027    
028    /**
029     * @author Sebastian Thomschke
030     *
031     */
032    public class ExpressionLanguageJRubyImpl implements ExpressionLanguage
033    {
034            private static final Log LOG = Log.getLog(ExpressionLanguageJRubyImpl.class);
035    
036            /**
037             * {@inheritDoc}
038             */
039            public Object evaluate(final String expression, final Map<String, ? > values) throws ExpressionEvaluationException
040            {
041                    LOG.debug("Evaluating JRuby expression: {1}", expression);
042                    try
043                    {
044                            final RubyInstanceConfig config = new RubyInstanceConfig();
045                            config.setCompatVersion(CompatVersion.RUBY1_9);
046                            final Ruby runtime = JavaEmbedUtils.initialize(new ArrayList<String>(), config);
047    
048                            final StringBuilder localVars = new StringBuilder();
049                            for (final Entry<String, ? > entry : values.entrySet())
050                            {
051                                    runtime.getGlobalVariables().set("$" + entry.getKey(), JavaEmbedUtils.javaToRuby(runtime, entry.getValue()));
052                                    localVars.append(entry.getKey()) //
053                                                    .append("=$") //
054                                                    .append(entry.getKey()) //
055                                                    .append("\n");
056                            }
057                            final IRubyObject result = runtime.evalScriptlet(localVars + expression);
058                            return JavaEmbedUtils.rubyToJava(runtime, result, Object.class);
059                    }
060                    catch (final RuntimeException ex)
061                    {
062                            throw new ExpressionEvaluationException("Evaluating JRuby expression failed: " + expression, ex);
063                    }
064            }
065    
066            /**
067             * {@inheritDoc}
068             */
069            public boolean evaluateAsBoolean(final String expression, final Map<String, ? > values) throws ExpressionEvaluationException
070            {
071                    final Object result = evaluate(expression, values);
072                    if (!(result instanceof Boolean)) throw new ExpressionEvaluationException("The script must return a boolean value.");
073                    return (Boolean) result;
074            }
075    }