1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26
27#include "config.h"
28#include "JavaNPObjectV8.h"
29
30#if ENABLE(JAVA_BRIDGE)
31
32#include "JNIUtilityPrivate.h"
33#include "JavaClassV8.h"
34#include "JavaFieldV8.h"
35#include "JavaInstanceV8.h"
36#include "JavaMethod.h"
37#include "JavaValueV8.h"
38#include "npruntime_impl.h"
39
40namespace JSC {
41
42namespace Bindings {
43
44static NPObject* AllocJavaNPObject(NPP, NPClass*)
45{
46    JavaNPObject* obj = static_cast<JavaNPObject*>(malloc(sizeof(JavaNPObject)));
47    if (!obj)
48        return 0;
49    memset(obj, 0, sizeof(JavaNPObject));
50    return reinterpret_cast<NPObject*>(obj);
51}
52
53static void FreeJavaNPObject(NPObject* npobj)
54{
55    JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(npobj);
56    obj->m_instance = 0; // free does not call the destructor
57    free(obj);
58}
59
60static NPClass JavaNPObjectClass = {
61    NP_CLASS_STRUCT_VERSION,
62    AllocJavaNPObject, // allocate,
63    FreeJavaNPObject, // free,
64    0, // invalidate
65    JavaNPObjectHasMethod,
66    JavaNPObjectInvoke,
67    0, // invokeDefault,
68    JavaNPObjectHasProperty,
69    JavaNPObjectGetProperty,
70    0, // setProperty
71    0, // removeProperty
72    0, // enumerate
73    0 // construct
74};
75
76NPObject* JavaInstanceToNPObject(JavaInstance* instance)
77{
78    JavaNPObject* object = reinterpret_cast<JavaNPObject*>(_NPN_CreateObject(0, &JavaNPObjectClass));
79    object->m_instance = instance;
80    return reinterpret_cast<NPObject*>(object);
81}
82
83// Returns null if obj is not a wrapper of JavaInstance
84JavaInstance* ExtractJavaInstance(NPObject* obj)
85{
86    if (obj->_class == &JavaNPObjectClass)
87        return reinterpret_cast<JavaNPObject*>(obj)->m_instance.get();
88    return 0;
89}
90
91bool JavaNPObjectHasMethod(NPObject* obj, NPIdentifier identifier)
92{
93    JavaInstance* instance = ExtractJavaInstance(obj);
94    if (!instance)
95        return false;
96    NPUTF8* name = _NPN_UTF8FromIdentifier(identifier);
97    if (!name)
98        return false;
99
100    instance->begin();
101    bool result = (instance->getClass()->methodsNamed(name).size() > 0);
102    instance->end();
103
104    // TODO: use NPN_MemFree
105    free(name);
106
107    return result;
108}
109
110bool JavaNPObjectInvoke(NPObject* obj, NPIdentifier identifier, const NPVariant* args, uint32_t argCount, NPVariant* result)
111{
112    JavaInstance* instance = ExtractJavaInstance(obj);
113    if (!instance)
114        return false;
115    NPUTF8* name = _NPN_UTF8FromIdentifier(identifier);
116    if (!name)
117        return false;
118
119    instance->begin();
120
121    MethodList methodList = instance->getClass()->methodsNamed(name);
122    // TODO: use NPN_MemFree
123    free(name);
124
125    // Try to find a good match for the overloaded method. The
126    // fundamental problem is that JavaScript doesn't have the
127    // notion of method overloading and Java does. We could
128    // get a bit more sophisticated and attempt to do some
129    // type checking as well as checking the number of parameters.
130    size_t numMethods = methodList.size();
131    JavaMethod* aMethod;
132    JavaMethod* jMethod = 0;
133    for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) {
134        aMethod = methodList[methodIndex];
135        if (aMethod->numParameters() == static_cast<int>(argCount)) {
136            jMethod = aMethod;
137            break;
138        }
139    }
140    if (!jMethod) {
141        instance->end();
142        return false;
143    }
144
145    JavaValue* jArgs = new JavaValue[argCount];
146    for (unsigned int i = 0; i < argCount; i++)
147        jArgs[i] = convertNPVariantToJavaValue(args[i], jMethod->parameterAt(i));
148
149// ANDROID
150    bool exceptionOccurred;
151    JavaValue jResult = instance->invokeMethod(jMethod, jArgs, exceptionOccurred);
152    instance->end();
153    delete[] jArgs;
154
155    if (exceptionOccurred)
156        return false;
157// END ANDROID
158
159    VOID_TO_NPVARIANT(*result);
160    convertJavaValueToNPVariant(jResult, result);
161    return true;
162}
163
164bool JavaNPObjectHasProperty(NPObject* obj, NPIdentifier identifier)
165{
166    JavaInstance* instance = ExtractJavaInstance(obj);
167    if (!instance)
168        return false;
169    NPUTF8* name = _NPN_UTF8FromIdentifier(identifier);
170    if (!name)
171        return false;
172    instance->begin();
173    bool result = instance->getClass()->fieldNamed(name);
174    instance->end();
175    free(name);
176    return result;
177}
178
179bool JavaNPObjectGetProperty(NPObject* obj, NPIdentifier identifier, NPVariant* result)
180{
181    VOID_TO_NPVARIANT(*result);
182    JavaInstance* instance = ExtractJavaInstance(obj);
183    if (!instance)
184        return false;
185    NPUTF8* name = _NPN_UTF8FromIdentifier(identifier);
186    if (!name)
187        return false;
188
189    instance->begin();
190    JavaField* field = instance->getClass()->fieldNamed(name);
191    free(name); // TODO: use NPN_MemFree
192    if (!field) {
193        instance->end();
194        return false;
195    }
196
197#if PLATFORM(ANDROID)
198    // JSC does not seem to support returning object properties so we emulate that
199    // behaviour here.
200    JavaValue value;
201#else
202    JavaValue value = instance->getField(field);
203#endif // PLATFORM(ANDROID)
204    instance->end();
205
206    convertJavaValueToNPVariant(value, result);
207
208    return true;
209}
210
211} // namespace Bindings
212
213} // namespace JSC
214
215#endif // ENABLE(JAVA_BRIDGE)
216