All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jruby.embed.internal.BiVariableMap Maven / Gradle / Ivy

There is a newer version: 9.4.7.0
Show newest version
/**
 * **** BEGIN LICENSE BLOCK *****
 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Common Public
 * License Version 1.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.eclipse.org/legal/cpl-v10.html
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * Copyright (C) 2009-2011 Yoko Harada 
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the CPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the CPL, the GPL or the LGPL.
 * **** END LICENSE BLOCK *****
 */
package org.jruby.embed.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jruby.RubyObject;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.variable.BiVariable;
import org.jruby.embed.variable.VariableInterceptor;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.scope.ManyVarsDynamicScope;

/**
 * Ruby-Java bi-directional variable map implementation. Keys of this map
 * should be String, and values should be {@link BiVariable} type object.
 * This map does not permit null or empty key. Each operation of this class is not
 * synchronized; however, concurrent access to values are synchronized. When
 * {@link ScriptingContainer} is shared by multiple threads, specify thread safe
 * for a local context scope, which makes a map thread local.
 *
 * Usage example:
 * 
 *         ScriptingContainer container = new ScriptingContainer();
 *         Map map = container.getVarMap();
 *         map.put("@coefficient", new Float(3.14));
* or, using a shortcut method: * *
 *         ScriptingContainer container = new ScriptingContainer();
 *         container.put("@coefficient", new Float(3.14));
* * @author Yoko Harada */ public class BiVariableMap implements Map { private final LocalContextProvider provider; private final List varNames = new ArrayList(); private final List variables = new ArrayList(); private boolean lazy; /** * Constructs an empty map. Users do not instantiate this map. The map is created * internally. * * @param runtime is environment where variables are used to execute Ruby scripts. * @param behavior is one of variable behaviors defined in VariableBehavior. */ public BiVariableMap(LocalContextProvider provider, boolean lazy) { this.provider = provider; this.lazy = lazy; } /** * Returns a list of all names in this map. * * @return a List of all names. */ public List getNames() { return varNames; } /** * Returns a list of all values in this map. * * @return a List of all values. */ public List getVariables() { return variables; } /** * Returns a local variable behavior * * @return a local variable behavior */ public LocalVariableBehavior getLocalVariableBehavior() { return provider.getLocalVariableBehavior(); } /** * Returns a map whose value is a Java object not a BiVariable type object. * * @return a Map of key and value pair, in which values are simple Java objects. */ public Map getMap() { Map m = new HashMap(); for (BiVariable v : variables) { m.put(v.getName(), v.getJavaObject()); } return m; } /** * Returns the number of key-value mappings in this map. * * @return the number of key-value mappings in this map */ public int size() { return varNames.size(); } /** * Returns true if this map contains no key-value mappings. * * @return true if this map contains no key-value mappings */ public boolean isEmpty() { return varNames.isEmpty(); } private void checkKey(Object key) { if (key == null) { throw new NullPointerException("key is null"); } if (!(key instanceof String)) { throw new ClassCastException("key is NOT String"); } if (((String)key).length() == 0) { throw new IllegalArgumentException("key is empty"); } } /** * Returns true if this map contains a mapping for the specified * key. * * @param key is a key to be tested its presence * @return true if this map contains a mapping for the specified key */ public boolean containsKey(Object key) { checkKey(key); return varNames.contains((String)key); } /** * Returns true if this map maps one or more keys to the * specified value. * * @param value is a Java object to be tested it presence * @return Returns true if this map maps one or more keys to the * specified value. */ public boolean containsValue(Object value) { Iterator itr = variables.iterator(); while (itr.hasNext()) { BiVariable v = (BiVariable)itr.next(); if (value == v.getJavaObject()) { return true; } } return false; } /** * Returns the value in simple Java object to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * @param key is the key whose associated value is to be returned * @return the value in simple Java object to which the specified key is mapped, or * {@code null} if this map contains no mapping for the key */ public V get(Object key) { return get(provider.getRuntime().getTopSelf(), key); } /** * Returns the value in simple Java object to which the specified receiver * and key is mapped, or {@code null} if this map contains no mapping * for the key in a given receiver. * * @param receiver is a receiver object to get the value from * @param key is the key whose associated value is to be returned * @return the value in simple Java object to which the specified key is mapped, or * {@code null} if this map contains no mapping for the key */ public V get(Object receiver, Object key) { checkKey(key); RubyObject robj = getReceiverObject(receiver); // attemps to retrieve global variables if (lazy) VariableInterceptor.tryLazyRetrieval(provider.getLocalVariableBehavior(), this, robj, key); BiVariable var = getVariable(robj, (String)key); if (var == null) return null; else return (V) var.getJavaObject(); } private RubyObject getReceiverObject(Object receiver) { if (receiver == null || !(receiver instanceof IRubyObject)) return (RubyObject)provider.getRuntime().getTopSelf(); else if (receiver instanceof RubyObject) return (RubyObject)receiver; else return (RubyObject)((IRubyObject)receiver).getRuntime().getTopSelf(); } /** * Returns the value in BiVariable type to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * @param key is the key whose associated BiVariable object is to be returned * @return the BiVariable type object to which the specified key is mapped, or * {@code null} if this map contains no mapping for the key */ @Deprecated public BiVariable getVariable(String key) { return getVariable((RubyObject)provider.getRuntime().getTopSelf(), key); } /** * Returns the value in BiVariable type to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * @param receiver is a receiver object to get key-value pair from * @param key is the key whose associated BiVariable object is to be returned * @return the BiVariable type object to which the specified key is mapped, or * {@code null} if this map contains no mapping for the key */ public BiVariable getVariable(RubyObject receiver, String key) { for (int i=0; ikey, or * null if there was no mapping for key. */ public V put (K key, V value) { return put(provider.getRuntime().getTopSelf(), key, value); } /** * Associates the specified value with the specified key in this map. * The values is a simple Java object. If the map previously contained a mapping for * the key, the old value is replaced by the specified value. * * @param receiver a receiver object to associate a given key-value pair with * @param key the key with which the specified value is to be associated * @param value a simple Java object to be associated with the specified key * @return the previous value associated with key, or * null if there was no mapping for key. */ public V put (Object receiver, K key, V value) { checkKey(key); RubyObject robj = getReceiverObject(receiver); String name = ((String)key).intern(); BiVariable v = getVariable(robj, name); Object oldValue = null; if (v != null) { // updates oldValue = v.getJavaObject(); v.setJavaObject(robj.getRuntime(), value); } else { // creates new value v = VariableInterceptor.getVariableInstance(provider.getLocalVariableBehavior(), robj, name, value); if (v != null) { update(name, v); } } return (V)oldValue; } /** * Returns Ruby's local variable names this map has. The returned array is mainly * used to inject local variables to Ruby scripts while parsing. * * @return String array of Ruby's local variable names */ public String[] getLocalVarNames() { List localVarNames = new ArrayList(); for (BiVariable v : variables) { if (v.getType() == BiVariable.Type.LocalVariable) { localVarNames.add(v.getName()); } } if (localVarNames.size() > 0) { return localVarNames.toArray(new String[localVarNames.size()]); } return null; } /** * Returns Ruby's local variable values this map has. The returned array is * mainly used to inject local variables to Ruby scripts while evaluating. * * @return IRubyObject array of Ruby's local variable names. */ public IRubyObject[] getLocalVarValues() { List localVarValues = new ArrayList(); for (BiVariable v : variables) { if (v.getType() == BiVariable.Type.LocalVariable) { localVarValues.add(v.getRubyObject()); } } if (localVarValues.size() > 0) { return localVarValues.toArray(new IRubyObject[localVarValues.size()]); } return null; } void inject(ManyVarsDynamicScope scope, int depth, IRubyObject receiver) { VariableInterceptor.inject(this, provider.getRuntime(), scope, depth, receiver); } void retrieve(IRubyObject receiver) { RubyObject robj = getReceiverObject(receiver); VariableInterceptor.retrieve(provider.getLocalVariableBehavior(), this, robj); } void terminate() { VariableInterceptor.terminateGlobalVariables(provider.getLocalVariableBehavior(), variables, provider.getRuntime()); VariableInterceptor.terminateLocalVariables(provider.getLocalVariableBehavior(), varNames, variables); } /** * Removes the mapping for a key from this map if it is present in a top level. * *

Returns the value to which this map previously associated the key, * or null if the map contained no mapping for the key. * @param key the key whose mapping is to be removed from the map * @return the previous value associated with key, or * null if there was no mapping for key. */ public V remove(Object key) { return remove(provider.getRuntime().getTopSelf(), key); } /** * Removes the mapping for a key from this map if it is present in a given * receiver. * *

Returns the value to which this map previously associated the key, * or null if the map contained no mapping for the key. * @param key the key whose mapping is to be removed from the map * @return the previous value associated with key, or * null if there was no mapping for key. */ public V remove(Object receiver, Object key) { checkKey(key); RubyObject robj = getReceiverObject(receiver); String name = ((String)key).intern(); for (int i=0; i t) { if (t == null) { throw new NullPointerException("map is null"); } if (t.isEmpty()) { throw new IllegalArgumentException("map is empty"); } Set set = t.entrySet(); Iterator itr = set.iterator(); while (itr.hasNext()) { Map.Entry entry = (Map.Entry)itr.next(); if (entry.getKey() instanceof String) { K key = (K)entry.getKey(); V value = (V)entry.getValue(); put(key, value); } else { throw new ClassCastException("key is NOT String"); } } } /** * Removes all of the mappings from this map. * The map will be empty after this call returns. Ruby variables are also * removed from Ruby instance. However, Ruby instance keep having global variable * names with null value. */ public void clear() { varNames.clear(); for (BiVariable v : variables) { if (v != null) { v.remove(); } } variables.clear(); } /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map should be * reflected in the set, and vice-versa. However, the implementation * does not reflect changes currently. * * @return a set view of the keys contained in this map */ public Set keySet() { if (varNames.isEmpty()) { return null; } Set s = new HashSet(); for (String name : varNames) { s.add(name); } return s; } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map should be * reflected in the collection, and vice-versa. However, the implementation * does not reflect changes currently. * * @return a collection view of the values contained in this map */ public Collection values() { if (varNames.isEmpty()) { return null; } List l = new ArrayList(); for (BiVariable v : variables) { l.add(v.getJavaObject()); } return l; } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map should be * reflected in the set, and vice-versa. However, the implementation * does not reflect changes currently. * * @return an entry set of a map */ public Set entrySet() { if (varNames.isEmpty()) { return null; } return getMap().entrySet(); } /** * Adds a key-value pair of Ruby local variable to double array. * * @param name is a Ruby's local variable name * @param value is BiVariable type object corresponding to the name */ public void update(String name, BiVariable value) { varNames.add(name); variables.add(value); } /** * Returns true when eager retrieval is requird or false when eager retrieval is * unnecessary. * * @return true for eager retrieve, false for on-demand retrieval */ public boolean isLazy() { return lazy; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy