Package com.google.gwt.dev.shell.mac

Source Code of com.google.gwt.dev.shell.mac.JsValueSaf$JsCleanupSaf

/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gwt.dev.shell.mac;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gdt.eclipse.designer.mac.BrowserShellMac;
import com.google.gdt.eclipse.designer.mac.BrowserShellMac.DispatchObject;
import com.google.gwt.dev.shell.CompilingClassLoader;
import com.google.gwt.dev.shell.JsValue;

/**
* Represents a Safari JavaScript value.
*
* The basic rule is that any JSValue passed to Java code from native code will
* always be GC-protected in the native code and Java will always unprotect it
* when the value is finalized. It should always be stored in a JsValue object
* immediately to make sure it is cleaned up properly when it is no longer
* needed. This approach is required to avoid a race condition where the value
* is allocated in JNI code but could be garbage collected before Java takes
* ownership of the value. Java values passed into JavaScript store a GlobalRef
* of a WebKitDispatchAdapter or MethodDispatch objects, which are freed when
* the JS value is finalized.
*/
public class JsValueSaf extends JsValue {
  private static class JsCleanupSaf implements JsCleanup {
    private final long jsval;

    /**
     * Create a cleanup object which takes care of cleaning up the underlying JS
     * object.
     *
     * @param jsval JSValue pointer as a long
     */
    public JsCleanupSaf(long jsval) {
      this.jsval = jsval;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.google.gwt.dev.shell.JsValue.JsCleanup#doCleanup()
     */
    public void doCleanup() {
    BrowserShellMac.objcRelease(jsval);
    }
  }

  /*
   * Underlying JSValue* as a long.
   */
  private long jsval;

  /**
   * Create a Java wrapper around an undefined JSValue.
   */
  public JsValueSaf() {
    init(BrowserShellMac.jsUndefined());
  }

  /**
   * Create a Java wrapper around the underlying JSValue.
   *
   * @param jsval a pointer to the underlying JSValue object as a long
   */
  public JsValueSaf(long jsval) {
    init(jsval);
  }

  @Override
  public boolean getBoolean() {
    return BrowserShellMac.coerceToBoolean(jsval);
  }

  @Override
  public int getInt() {
    return BrowserShellMac.coerceToInt(jsval);
  }

  @Override
  public long getJavaScriptObjectPointer() {
    assert isJavaScriptObject();
    return jsval;
  }

  public long getJsValue() {
    return jsval;
  }

  @Override
  public double getNumber() {
    return BrowserShellMac.coerceToDouble(jsval);
  }

  @Override
  public String getString() {
    return BrowserShellMac.coerceToString(jsval);
  }

  @Override
  public String getTypeString() {
    return BrowserShellMac.getTypeString(jsval);
  }

  @Override
  public Object getWrappedJavaObject() {
    DispatchObject obj = BrowserShellMac.unwrapDispatch(jsval);
    return obj.getTarget();
  }

  @Override
  public boolean isBoolean() {
    return BrowserShellMac.isBoolean(jsval);
  }

  @Override
  public boolean isInt() {
    // Safari doesn't have integers, so this is always false
    return false;
  }

  @Override
  public boolean isJavaScriptObject() {
    return BrowserShellMac.isObject(jsval) && !BrowserShellMac.isWrappedDispatch(jsval);
  }

  @Override
  public boolean isNull() {
    return BrowserShellMac.isNull(jsval);
  }

  @Override
  public boolean isNumber() {
      return BrowserShellMac.isNumber(jsval);
  }

  @Override
  public boolean isString() {
    return BrowserShellMac.isString(jsval);
  }

  @Override
  public boolean isUndefined() {
    return BrowserShellMac.isUndefined(jsval);
  }

  @Override
  public boolean isWrappedJavaObject() {
    return BrowserShellMac.isWrappedDispatch(jsval);
  }

  @Override
  public void setBoolean(boolean val) {
    setJsValNoRetain(BrowserShellMac.convertBoolean(val));
  }

  @Override
  public void setByte(byte val) {
    setJsValNoRetain(BrowserShellMac.convertDouble(val));
  }

  @Override
  public void setChar(char val) {
    setJsValNoRetain(BrowserShellMac.convertDouble(val));
  }

  @Override
  public void setDouble(double val) {
    setJsValNoRetain(BrowserShellMac.convertDouble(val));
  }

  @Override
  public void setInt(int val) {
    setJsValNoRetain(BrowserShellMac.convertDouble(val));
  }

  @Override
  public void setNull() {
    setJsValNoRetain(BrowserShellMac.jsNull());
  }

  @Override
  public void setShort(short val) {
    setJsValNoRetain(BrowserShellMac.convertDouble(val));
  }

  @Override
  public void setString(String val) {
    setJsValNoRetain(BrowserShellMac.convertString(val));
  }

  @Override
  public void setUndefined() {
    setJsValNoRetain(BrowserShellMac.jsUndefined());
  }

  @Override
  public void setValue(JsValue other) {
    long jsvalOther = ((JsValueSaf) other).jsval;
    /*
     * Add another lock to this jsval, since both the other object and this one
     * will eventually release it.
     */
//    LowLevelSaf.gcProtect(LowLevelSaf.getCurrentJsContext(), jsvalOther);
//  XXX should we add the BrowserShell.gcLock()?   
    setJsVal(jsvalOther);
  }

  @Override
  public <T> void setWrappedJavaObject(CompilingClassLoader cl, T val) {
    DispatchObject dispObj;
    if (val == null) {
      setNull();
      return;
    } else if (val instanceof DispatchObject) {
      dispObj = (DispatchObject) val;
    } else {
      dispObj = (DispatchObject) cl.getWrapperForObject(val);
      if (dispObj == null) {
        dispObj = new WebKitDispatchAdapter(cl, val);
        cl.putWrapperForObject(val, dispObj);
      }
    }
    long jsVal = BrowserShellMac.wrapDispatch(dispObj);
  setJsValNoRetain(jsVal);
  }

  @Override
  protected JsCleanup createCleanupObject() {
    return new JsCleanupSaf(jsval);
  }

  /**
   * Initialization helper method.
   *
   * @param jsval underlying JSValue*
   */
  private void init(long jsval) {
    this.jsval = jsval;
  BrowserShellMac.objcRetain(this.jsval);
  }

  /**
   * Set a new value. Unlock the previous value, but do *not* lock the new value
   * (see class comment).
   *
   * @param jsval the new value to set
   */
  private void setJsVal(long jsval) {
  BrowserShellMac.objcRelease(this.jsval);
  init(jsval);
  }
  private void setJsValNoRetain(long jsval) {
  BrowserShellMac.objcRelease(this.jsval);
  this.jsval = jsval;
  }
  ////////////////////////////////////////////////////////////////////////////
  //
  // obj-c -> java refs
  //
  ////////////////////////////////////////////////////////////////////////////
  protected static Map<Long, Object> m_dispatchRefs = new HashMap<Long, Object>();
  /**
   * Invoked by native code at the moment when new wrapper objc object created for {@link DispatchObject}.
   *
   * @param ref
   *            the native pointer to objc object instance.
   * @param refObj
   *            the {@link DispatchObject} instance.
   */
  protected static void putDispatchObjectRef(long ref, Object refObj) {
  synchronized (m_dispatchRefs) {
    m_dispatchRefs.put(ref, refObj);
  }
  }
  /**
   * Invoked by native code every time when the objc wrapper needs the appropriate {@link DispatchObject}
   * instance.
   *
   * @param ref
   *            the native pointer to objc object instance.
   */
  protected static Object getDispatchObjectRef(long ref) {
  synchronized (m_dispatchRefs) {
    return m_dispatchRefs.get(ref);
  }
  }
  /**
   * Invoked by native code when the objc wrapper deallocated.
   *
   * @param ref
   *            the native pointer to objc object instance.
   */
  protected static void removeDispatchObjectRef(long ref) {
  synchronized (m_dispatchRefs) {
    m_dispatchRefs.remove(ref);
  }
  }
  /**
   * Clean up {@link DispatchObject} instances when disposing current {@link ModuleSpaceSaf}.
   */
  static void clearDispatchObjectRefs(CompilingClassLoader cl) {
  synchronized (m_dispatchRefs) {
    List<Long> removingRefs = new ArrayList<Long>();
    for (Long ref : m_dispatchRefs.keySet()) {
    Object dispObj = m_dispatchRefs.get(ref);
    if (dispObj instanceof WebKitDispatchAdapter) {
      WebKitDispatchAdapter dispatchAdapter = (WebKitDispatchAdapter) dispObj;
      if (dispatchAdapter.getClassLoader() == cl) {
        removingRefs.add(ref);
      }
    }
    }
    for (Long ref : removingRefs) {
    m_dispatchRefs.remove(ref);
    }
  }
  }
}
TOP

Related Classes of com.google.gwt.dev.shell.mac.JsValueSaf$JsCleanupSaf

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.