Back to index

lightning-sunbird  0.9+nobinonly
xpctest_overloaded.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   John Bandhauer <jband@netscape.com>
00026  *   Pierre Phaneuf <pp@ludusdesign.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 /* implement nsIXPCTestOverloaded as an example. */
00043 
00044 #include "xpctest_private.h"
00045 #include "nsIXPCScriptable.h"
00046 
00047 /*
00048 * This is an example of one way to reflect an interface into JavaScript such
00049 * that one method name is overloaded to reflect multiple methods. This practice
00050 * is strongly discouraged. But, some legacy JavaScript interfaces require this
00051 * in order to support existing JavaScript code.
00052 */
00053 
00054 /***************************************************************************/
00055 /* This is a JS example of calling the object implemented below. */
00056 
00057 /*
00058 * // to run this in the shell...
00059 * // put this in "foo.js" and the run "xpcshell foo.js"
00060 *
00061 *  var clazz = Components.classes.nsOverloaded;
00062 *  var iface = Components.interfaces.nsIXPCTestOverloaded;
00063 *
00064 *  foo = clazz.createInstance(iface);
00065 *
00066 *  try {
00067 *      print("foo.Foo1(1)...  ");  foo.Foo1(1)
00068 *      print("foo.Foo2(1,2)...");  foo.Foo2(1,2)
00069 *      print("foo.Foo(3)...   ");  foo.Foo(3)
00070 *      print("foo.Foo(3,4)... ");  foo.Foo(3,4)
00071 *      print("foo.Foo()...    ");  foo.Foo();
00072 *  } catch(e) {
00073 *      print("caught exception: "+e);
00074 *  }
00075 *
00076 */
00077 
00078 /***************************************************************************/
00079 
00080 /*
00081 * This is the implementation of nsIXPCScriptable. This interface is used
00082 * by xpconnect in order to allow wrapped native objects to gain greater
00083 * control over how they are reflected into JavaScript. Most wrapped native
00084 * objects do not need to implement this interface. It is useful for dynamic
00085 * properties (those properties not explicitly mentioned in the .idl file).
00086 * Here we are using the nsIXPCScriptable as a way to bootstrap some JS code
00087 * to be run each time a wrapper is built around an instance of our object.
00088 *
00089 * xpconnect allows implementors of nsIXPCScriptable to bend the rules a bit...
00090 * implementations of nsIXPCScriptable are not required to follow QueryInterface
00091 * identity rules; i.e. doing a QI(NS_GET_IID(nsISupports)) on this interface is
00092 * not required to return the same pointer as doing so on the object that
00093 * presented this interface. Thus, it is allowable to implement only one
00094 * nsIXPCScriptable instance per class if desired.
00095 */
00096 
00097 class xpcoverloaded : public nsIXPCTestOverloaded, public nsIXPCScriptable
00098 {
00099 public:
00100     NS_DECL_ISUPPORTS
00101     NS_DECL_NSIXPCTESTOVERLOADED
00102     NS_DECL_NSIXPCSCRIPTABLE
00103 
00104     xpcoverloaded();
00105     virtual ~xpcoverloaded();
00106 };
00107 
00108 xpcoverloaded::xpcoverloaded()
00109 {
00110     NS_ADDREF_THIS();
00111 }
00112 
00113 xpcoverloaded::~xpcoverloaded()
00114 {
00115     // empty
00116 }
00117 
00118 NS_IMPL_ISUPPORTS2(xpcoverloaded, nsIXPCTestOverloaded, nsIXPCScriptable)
00119 
00120 /* void Foo1 (in PRInt32 p1); */
00121 NS_IMETHODIMP
00122 xpcoverloaded::Foo1(PRInt32 p1)
00123 {
00124     printf("xpcoverloaded::Foo1 called with p1 = %d\n", p1);
00125     return NS_OK;
00126 }
00127 
00128 /* void Foo2 (in PRInt32 p1, in PRInt32 p2); */
00129 NS_IMETHODIMP
00130 xpcoverloaded::Foo2(PRInt32 p1, PRInt32 p2)
00131 {
00132     printf("xpcoverloaded::Foo2 called with p1 = %d and p2 = %d\n", p1, p2);
00133     return NS_OK;
00134 }
00135 
00136 // The nsIXPCScriptable map declaration that will generate stubs for us...
00137 #define XPC_MAP_CLASSNAME           xpcoverloaded
00138 #define XPC_MAP_QUOTED_CLASSNAME   "xpcoverloaded"
00139 #define                             XPC_MAP_WANT_CREATE
00140 #define XPC_MAP_FLAGS               0
00141 #include "xpc_map_end.h" /* This will #undef the above */
00142 
00143 // We implement this method ourselves
00144 
00145 
00146 /* void create (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj); */
00147 NS_IMETHODIMP 
00148 xpcoverloaded::Create(nsIXPConnectWrappedNative *wrapper, 
00149                       JSContext * cx, JSObject * obj)
00150 {
00151 /*
00152 * Here are two implementations...
00153 *
00154 * The first uses a shared prototype object to implement the forwarding
00155 * function.
00156 *
00157 * The second adds the forwarding function to each and every object
00158 */
00159 #if 1
00160 /*
00161 * NOTE: in the future xpconnect is likely to build and maintain a
00162 * 'per CLSID' prototype object. When we have flattened interfaces code will
00163 * be able to ask the wrapper for the prototype object. The prototype object
00164 * will be shared by all wrapped objects with the given CLSID.
00165 *
00166 * *** If anyone uses the code below to make their own prototype objects they
00167 *     should be prepared to convert the code when the new scheme arrives. ***
00168 */
00169 
00170     static const char name[] = "__xpcoverloadedProto__";
00171     static const char source[] =
00172         "__xpcoverloadedProto__ = {"
00173         "   Foo : function() {"
00174         "     switch(arguments.length) {"
00175         "     case 1: return this.Foo1(arguments[0]);"
00176         "     case 2: return this.Foo2(arguments[0], arguments[1]);"
00177         "     default: throw '1 or 2 arguments required';"
00178         "     }"
00179         "   }"
00180         "};";
00181 
00182     jsval proto;
00183 
00184     if(!JS_GetProperty(cx, JS_GetGlobalObject(cx), name, &proto) ||
00185        JSVAL_IS_PRIMITIVE(proto))
00186     {
00187        if(!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), source, strlen(source),
00188                           "builtin", 1, &proto) ||
00189           !JS_GetProperty(cx, JS_GetGlobalObject(cx), name, &proto)||
00190           JSVAL_IS_PRIMITIVE(proto))
00191             return NS_ERROR_UNEXPECTED;
00192     }
00193     if(!JS_SetPrototype(cx, obj, JSVAL_TO_OBJECT(proto)))
00194         return NS_ERROR_UNEXPECTED;
00195     return NS_OK;
00196 
00197 #else
00198     // NOTE: this script is evaluated where the wrapped object is the current
00199     // 'this'.
00200 
00201     // here is a 'Foo' implementation that will forward to the appropriate
00202     // non-overloaded method.
00203     static const char source[] =
00204         "this.Foo = function() {"
00205         "  switch(arguments.length) {"
00206         "  case 1: return this.Foo1(arguments[0]);"
00207         "  case 2: return this.Foo2(arguments[0], arguments[1]);"
00208         "  default: throw '1 or 2 arguments required';"
00209         "  }"
00210         "};";
00211 
00212     jsval ignored;
00213     JS_EvaluateScript(cx, obj, source, strlen(source), "builtin", 1, &ignored);
00214     return NS_OK;
00215 #endif
00216 }
00217 
00218 /***************************************************************************/
00219 
00220 
00221 /***************************************************************************/
00222 // our standard generic factory helper.
00223 
00224 // static
00225 NS_IMETHODIMP
00226 xpctest::ConstructOverloaded(nsISupports *aOuter, REFNSIID aIID, void **aResult)
00227 {
00228     nsresult rv;
00229     NS_ASSERTION(aOuter == nsnull, "no aggregation");
00230     xpcoverloaded* obj = new xpcoverloaded();
00231 
00232     if(obj)
00233     {
00234         rv = obj->QueryInterface(aIID, aResult);
00235         NS_ASSERTION(NS_SUCCEEDED(rv), "unable to find correct interface");
00236         NS_RELEASE(obj);
00237     }
00238     else
00239     {
00240         *aResult = nsnull;
00241         rv = NS_ERROR_OUT_OF_MEMORY;
00242     }
00243 
00244     return rv;
00245 }
00246 /***************************************************************************/
00247 
00248 
00249 
00250