Package com.scratchdisk.script.rhino

Source Code of com.scratchdisk.script.rhino.ExtendedJavaObject

/*
* Scriptographer
*
* This file is part of Scriptographer, a Scripting Plugin for Adobe Illustrator
* http://scriptographer.org/
*
* Copyright (c) 2002-2010, Juerg Lehni
* http://scratchdisk.com/
*
* All rights reserved. See LICENSE file for details.
*
* File created on 02.01.2005.
*/

package com.scratchdisk.script.rhino;

import java.util.HashMap;

import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

import com.scratchdisk.script.ChangeReceiver;
import com.scratchdisk.script.ChangeEmitter;

/**
* @author lehni
*/
public class ExtendedJavaObject extends NativeJavaObject {
  HashMap<String, Object> properties;
  ExtendedJavaClass classWrapper = null;
 
  /**
   * @param scope
   * @param javaObject
   * @param staticType
   */
  public ExtendedJavaObject(Scriptable scope, Object javaObject,
    Class staticType, boolean unsealed) {
    super(scope, javaObject, staticType);
    properties = unsealed ? new HashMap<String, Object>() : null;
    classWrapper = ExtendedJavaClass.getClassWrapper(scope, staticType);
  }

  public Scriptable getPrototype() {
    Scriptable prototype = super.getPrototype();
    return prototype == null
        ? classWrapper.getInstancePrototype()
        : prototype;
  }

  protected ExtendedJavaObject changeReceiver = null;
  protected String changeProperty = null;
  protected int currentChangeVersion = -1;
  public static int changeVersion = -1;

  protected void fetchChangeReceiver() {
    // If there is a change receiver, fetch the new value of this object
    // from it before calling anything on it. We are doing this by
    // replacing the underlying native object each time.
    if (currentChangeVersion != changeVersion) {
      Object result = changeReceiver.get(changeProperty, this);
      if (result != this && result instanceof ExtendedJavaObject) {
        ExtendedJavaObject update = (ExtendedJavaObject) result;
        javaObject = update.javaObject;
        // Help the garbage collector
        update.javaObject = null;
      }
      currentChangeVersion = changeVersion;
    }
  }

  protected void updateChangeReceiver() {
    // If there is a modification listener, update this field in it
    // right away now.
    changeReceiver.put(changeProperty, changeReceiver, this);
  }

  protected void handleChangeEmitter(Object object, String property) {
    // Now see if the result is a change emitter for this listener.
    // If so, create the links between the two.
    if (object instanceof ExtendedJavaObject) {
      ExtendedJavaObject other = (ExtendedJavaObject) object;
      if (other.javaObject instanceof ChangeEmitter) {
        other.changeReceiver = this;
        other.changeProperty = property;
      }
    }
  }

  public Object get(String name, Scriptable start) {
    // See whether this object defines the property.
    // Properties need to come first, as they might override something
    // defined in the underlying Java object
    if (properties != null && properties.containsKey(name))
      return properties.get(name);
    if (changeReceiver != null)
      fetchChangeReceiver();
    Scriptable prototype = getPrototype();
    Object result = prototype.get(name, this);
    if (result != Scriptable.NOT_FOUND)
      return result;
    result = members.get(this, name, javaObject, false);
    if (result != Scriptable.NOT_FOUND) {
      if (javaObject instanceof ChangeReceiver)
        handleChangeEmitter(result, name);
      return result;
    }
    if (name.equals("prototype"))
      return prototype;
    return Scriptable.NOT_FOUND;
  }

  public void put(String name, Scriptable start, Object value) {
    EvaluatorException error = null;
    if (members.has(name, false)) {
      try {
        // Try setting the value on member first
        members.put(this, name, javaObject, value, false);
        if (changeReceiver != null)
          updateChangeReceiver();
        return; // done
      } catch (EvaluatorException e) {
        // Rethrow errors that have another cause (a real Java exception from the
        // called getter / setter) or that are about conversion problems.
        if (e.getCause() != null || e.getMessage().indexOf("Cannot convert") != -1)
          throw e;
        error = e;
      }
    }
    // Still here? An exception has happened. Let's try other things
    if (name.equals("prototype")) {
      if (value instanceof Scriptable)
        setPrototype((Scriptable) value);
    } else if (properties != null) {
      // Ignore EvaluatorException exceptions that might have happened in
      // members.put above. These would happen if the user tries to
      // override a Java method or field. We allow this on the level of
      // the wrapper though, if the wrapper was created unsealed (meaning
      // properties exist).
      properties.put(name, value);
    } else if (error != null) {
      // If nothing of the above worked, throw the error again.
      throw error;
    }
  }

  public boolean has(String name, Scriptable start) {
    return members.has(name, false) ||
        properties != null && properties.containsKey(name);
  }

  public void delete(String name) {
    if (properties != null)
      properties.remove(name);
  }
 
  public Object[] getIds() {
    // Concatenate the super classes ids array with the keySet from
    // properties HashMap:
    Object[] javaIds = super.getIds();
    if (properties != null) {
      int numProps = properties.size();
      if (numProps == 0)
        return javaIds;
      Object[] ids = new Object[javaIds.length + numProps];
      properties.keySet().toArray(ids);
      System.arraycopy(javaIds, 0, ids, numProps, javaIds.length);
      return ids;
    }
    return javaIds;
  }

  public Object getDefaultValue(Class<?> hint) {
    // Try the ScriptableObject version first that tries to call toString / valueOf,
    // and fallback on the Java toString only if that does not work out.
    try {
      return ScriptableObject.getDefaultValue(this, hint);
    } catch (EcmaError e) {
      return super.getDefaultValue(hint);
    }
  }
}
TOP

Related Classes of com.scratchdisk.script.rhino.ExtendedJavaObject

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.