Java tutorial
/******************************************************************************* * 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.gdt.eclipse.designer.ie.jsni; import java.lang.ref.WeakReference; import java.lang.reflect.AccessibleObject; import java.lang.reflect.InvocationTargetException; import org.eclipse.swt.internal.ole.win32.COM; import org.eclipse.swt.internal.ole.win32.IDispatch; import org.eclipse.swt.ole.win32.Variant; import com.google.gwt.dev.shell.designtime.DispatchIdOracle; import com.google.gwt.dev.shell.designtime.JsValueGlue; import com.google.gwt.dev.shell.designtime.MethodAdaptor; import com.google.gwt.dev.shell.designtime.WrappersCache; /** * Wraps an arbitrary Java Method as an Automation-compatible server. The class was motivated by the * need to expose Java objects into JavaScript. * * <p> * <b>Features</b> * </p> * <ul> * <li>Implements the <code>IDispatch</code> interface for you</li> * <li>If the COM client keeps a reference to this object, this object is prevented from being * garbage collected</li> * </ul> * * <p> * <b>Limitations</b> * </p> * <ul> * <li>Only late-bound dispatch is supported</li> * <li>Named arguments are not supported (see {@link #GetIDsOfNames})).</li> * </ul> */ public class MethodDispatch extends IDispatchImpl { private final WeakReference<ClassLoader> classLoaderRef; private final WeakReference<DispatchIdOracle> dispIdOracleRef; private final MethodAdaptor method; public MethodDispatch(ClassLoader cl, DispatchIdOracle ora, MethodAdaptor method) { this.classLoaderRef = new WeakReference<ClassLoader>(cl); this.dispIdOracleRef = new WeakReference<DispatchIdOracle>(ora); this.method = method; } @Override public String toString() { return "\nfunction " + method.toString() + "(){\n [native code]\n}\n"; } /** * ID 0 is magic. It can either mean toString or invoke, depending on the flags. So we start with * ID 1 for toString. {@link IDispatchProxy} and {@link BrowserWidgetIE6.External} should be fixed * to do the same. */ @Override protected void getIDsOfNames(String[] names, int[] ids) throws HResultException { if (names[0].equalsIgnoreCase("toString")) { ids[0] = 1; } else if (names[0].equalsIgnoreCase("call")) { ids[0] = 2; } else if (names[0].equalsIgnoreCase("apply")) { ids[0] = 3; } else { throw new HResultException(IDispatchImpl.DISP_E_UNKNOWNNAME); } } /* * Handles all the things the browser can do to a function object. */ @Override protected Variant invoke(int id, int flags, Variant[] params) throws HResultException, InstantiationException, InvocationTargetException { ClassLoader classLoader = classLoaderRef.get(); if (classLoader == null) { throw new RuntimeException("Invalid class loader."); } DispatchIdOracle dispIdOracle = dispIdOracleRef.get(); if (dispIdOracle == null) { throw new RuntimeException("Invalid dispatch oracle."); } switch (id) { case 0: // An implicit access. if ((flags & COM.DISPATCH_METHOD) != 0) { // implicit call -- "m()" return callMethod(classLoader, dispIdOracle, null, params, method); } else if ((flags & COM.DISPATCH_PROPERTYGET) != 0) { // implicit toString -- "'foo' + m" return new Variant(toString()); } break; case 1: // toString if ((flags & COM.DISPATCH_METHOD) != 0) { // "m.toString()" return new Variant(toString()); } else if ((flags & COM.DISPATCH_PROPERTYGET) != 0) { // "m.toString" MethodAdaptor toStringMethod; try { toStringMethod = new MethodAdaptor(Object.class.getDeclaredMethod("toString")); } catch (Throwable e) { throw new RuntimeException("Failed to get Object.toString() method", e); } AccessibleObject obj = toStringMethod.getUnderlyingObject(); IDispatchImpl dispMethod = (IDispatchImpl) WrappersCache.getWrapperForObject(classLoader, obj); if (dispMethod == null || dispMethod.refCount < 1) { dispMethod = new MethodDispatch(classLoader, dispIdOracle, toStringMethod); WrappersCache.putWrapperForObject(classLoader, obj, dispMethod); } IDispatch disp = new IDispatch(dispMethod.getAddress()); disp.AddRef(); return new Variant(disp); } break; case 2: // call if ((flags & COM.DISPATCH_METHOD) != 0) { // "m.call(thisObj, arg)" /* * First param must be a this object of the correct type (for instance * methods). If method is static, it can be null. */ Object jthis = JsValueGlue.get(new JsValueIE6(params[0]), classLoader, method.getDeclaringClass(), "this"); Variant[] otherParams = new Variant[params.length - 1]; System.arraycopy(params, 1, otherParams, 0, otherParams.length); return callMethod(classLoader, dispIdOracle, jthis, otherParams, method); } else if ((flags & COM.DISPATCH_PROPERTYGET) != 0) { // "m.call" // TODO: not supported } break; case 3: // apply // TODO: not supported break; case IDispatchProxy.DISPID_MAGIC_GETGLOBALREF: // We are NOT in fact a "wrapped Java Object", but we don't want to // throw an exception for being asked. return new Variant(0); default: // The specified member id is out of range. throw new HResultException(COM.DISP_E_MEMBERNOTFOUND); } throw new HResultException(COM.E_NOTSUPPORTED); } }