Script Beans - part 2

This is continuation of my earlier post on script beans. On rethinking, I've made few (minor) changes to ScriptObject and Callable. The changes are:
  • Using varargs instead of Object[] arguments in few places.
  • Added invoke method in ScriptObject -- this is used to directly invoke a method on a script object instead of getting a method/function valued property using get and then invoking Callable.call method. Why? Many dynamically typed languages have Smalltalk's doesNotUnderstand equivalent. i.e., if a method is not found, then a method missing handler is invoked. - like JRuby's method_missing and Groovy's invokeMethod. ScriptObject.invoke may be implemented by calling ScriptObject.get and Callable.call on result and possibly incorporating language specific method missing method as well.
  • ScriptObject.put returns boolean to tell whether the put was successful or not (may be read-only property was assigned or property addition is not possible and so on).


ScriptObject

import javax.script.ScriptException;

/\*\*
 \* Any Java object supporting this interface can be
 \* accessed from scripts with "simpler" access pattern.
 \* For example, a script engine may support natural
 \* property/field access syntax for the properties exposed
 \* via this interface. We use this interface so that we
 \* can dynamically add/delete/modify fields exposed to
 \* scripts. Also, script engines may expose this interface for
 \* it's own objects.
 \*/
public interface ScriptObject {
  // special value to denote no-result -- so that
  // null could be used as proper result value
  public static final Object UNDEFINED = new Object();
  // empty object array
  public static final Object[] EMPTY_ARRAY = new Object[0];

  /\*
   \* Returns all property names supported by this object.
   \* Property "name" is either a String or an Integer".
   \*/
  public Object[] getIds();

  /\*\*
   \* Get the value of the named property.
   \*/
  public Object get(String name);

  /\*\*
   \* Get the value of the "indexed" property. 
   \* Returns UNDEFINED if the property does not exist.
   \*/
  public Object get(int index);

  /\*\*
   \* Set the value of the named property. Returns
   \* whether the put was successful or not.
   \*/
  public boolean put(String name, Object value);

  /\*\*
   \* Set the value of the indexed property. Returns
   \* whether the put was successful or not.
   \*/
  public boolean put(int index, Object value);

  /\*\*
   \* Returns whether the named property exists or not.
   \*/
  public boolean has(String name);

  /\*\*
   \* Returns whether the indexed property exists or not.
   \*/
  public boolean has(int index);

  /\*\*
   \* Deletes the named property. Returns true on success.
   \*/
  public boolean delete(String name);

  /\*\*
   \* Deletes the indexed property. Returns true on success.
   \*/
  public boolean delete(int index);

  /\*\*
   \* Call the named method on this script object.
   \*/
  public Object invoke(String name, Object... arguments)
      throws NoSuchMethodException, ScriptException;
}



Callable.java

import javax.script.ScriptException;

/\*\*
 \* This interface is used to represent "function/method" valued
 \* properties in ScriptObjects.
 \*/
public interface Callable {
  /\*\*
   \* Call the underlying function passing the given
   \* arguments and return the result.
   \*/
  public Object call(Object... args) throws ScriptException;
}



AbstractScriptObject.java

import javax.script.ScriptException;

/\*\*
 \* Simple dummy implementation of ScriptObject.
 \*/
public abstract class AbstractScriptObject 
  implements ScriptObject {

  public Object[] getIds() {
    return EMPTY_ARRAY;
  }    

  public Object get(String name) {
    return UNDEFINED;
  }

  public Object get(int index) {
    return UNDEFINED;
  }

  public boolean put(String name, Object value) {
    return false;
  }

  public boolean put(int index, Object value) {
    return false;
  }

  public boolean has(String name) {
    return false;
  }

  public boolean has(int index) {
    return false;
  }

  public boolean delete(String name) {
    return false;
  }

  public boolean delete(int index) {
    return false;
  }

  public Object invoke(String name, Object... arguments) 
    throws NoSuchMethodException, ScriptException {
    Object value =  get(name);
    if (value instanceof Callable) {
      return ((Callable)value).call(arguments);
    } else {
      throw new NoSuchMethodException(name);
    }
  }
}

Comments:

The invoke(...) method can be helpful for interface usability reasons, but I don't see why a MethodMissing kind of feature could not be implemented by having a Callable subclass following the Special Case pattern.

Excellent blog, BTW. I specially liked the Scala summary posts, I'm hoping that they will help to make the language more popular.

Posted by Rafael Ferreira on March 24, 2007 at 07:36 PM IST #

Hi Rafael Ferreira: Yes, I agree that Callable could take care of that case as well. But, as you said, invoke() is easier to work with. And explicit Callable helps in creating and storing "method references" for future call from event handlers/listeners and so on. And thanks for your good words on my blog.

Posted by A. Sundararajan on March 25, 2007 at 05:52 AM IST #

You asked "Also, beanutils API seems to concentrate only on "properties" only. There is nothing mentioned about "methods". (Did I miss anything in BeanUtils API that deals methods?)" There is a simple reason, not all methods are part of the bean. There are getters, setters and maybe listener infrastructure, but that's it. Not all methods do fit here.. especially no overloaded methods. Now for your ScriptObject... this is thought to be used from a script, yes? As for groovy, to support this as it is thought, we need a wrapper around your ScriptObject... which is kind of funny.. because if you have a POJO that you want to use with the ScriptObject, then the language needs to wrap that ScriptObject with a wrapper and so you get access the way you wanted to have this... only, in Groovy, we could have used the POJO directly. Of course you would not get method missing then...

Posted by Jochen "blackdrag" Theodorou on March 26, 2007 at 10:00 AM IST #

Post a Comment:
Comments are closed for this entry.
About

sundararajan

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Bookmarks
Links

No bookmarks in folder

Blogroll

No bookmarks in folder

News

No bookmarks in folder