1/*
2 * Copyright (C) 2003, 2004, 2005, 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright 2010, The Android Open Source Project
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "JavaMethodJobject.h"
29
30#if ENABLE(JAVA_BRIDGE)
31
32#include "JavaString.h"
33
34#if USE(JSC)
35#include <runtime/JSObject.h>
36#include <runtime/ScopeChain.h>
37#endif
38#include <wtf/text/StringBuilder.h>
39
40using namespace JSC;
41using namespace JSC::Bindings;
42
43JavaMethodJobject::JavaMethodJobject(JNIEnv* env, jobject aMethod)
44{
45    // Get return type name
46    jstring returnTypeName = 0;
47    if (jobject returnType = callJNIMethod<jobject>(aMethod, "getReturnType", "()Ljava/lang/Class;")) {
48        returnTypeName = static_cast<jstring>(callJNIMethod<jobject>(returnType, "getName", "()Ljava/lang/String;"));
49        if (!returnTypeName)
50            returnTypeName = env->NewStringUTF("<Unknown>");
51        env->DeleteLocalRef(returnType);
52    }
53    m_returnTypeClassName = JavaString(env, returnTypeName);
54    m_returnType = javaTypeFromClassName(m_returnTypeClassName.utf8());
55    env->DeleteLocalRef(returnTypeName);
56
57    // Get method name
58    jstring methodName = static_cast<jstring>(callJNIMethod<jobject>(aMethod, "getName", "()Ljava/lang/String;"));
59    if (!methodName)
60        methodName = env->NewStringUTF("<Unknown>");
61    m_name = JavaString(env, methodName);
62    env->DeleteLocalRef(methodName);
63
64    // Get parameters
65    if (jarray jparameters = static_cast<jarray>(callJNIMethod<jobject>(aMethod, "getParameterTypes", "()[Ljava/lang/Class;"))) {
66        unsigned int numParams = env->GetArrayLength(jparameters);
67
68        for (unsigned int i = 0; i < numParams; i++) {
69            jobject aParameter = env->GetObjectArrayElement(static_cast<jobjectArray>(jparameters), i);
70            jstring parameterName = static_cast<jstring>(callJNIMethod<jobject>(aParameter, "getName", "()Ljava/lang/String;"));
71            if (!parameterName)
72                parameterName = env->NewStringUTF("<Unknown>");
73            m_parameters.append(JavaString(env, parameterName).impl());
74            env->DeleteLocalRef(aParameter);
75            env->DeleteLocalRef(parameterName);
76        }
77        env->DeleteLocalRef(jparameters);
78    }
79
80    // Created lazily.
81    m_signature = 0;
82
83    jclass modifierClass = env->FindClass("java/lang/reflect/Modifier");
84    int modifiers = callJNIMethod<jint>(aMethod, "getModifiers", "()I");
85    m_isStatic = static_cast<bool>(callJNIStaticMethod<jboolean>(modifierClass, "isStatic", "(I)Z", modifiers));
86    env->DeleteLocalRef(modifierClass);
87}
88
89JavaMethodJobject::~JavaMethodJobject()
90{
91    if (m_signature)
92        fastFree(m_signature);
93}
94
95// JNI method signatures use '/' between components of a class name, but
96// we get '.' between components from the reflection API.
97static void appendClassName(StringBuilder& builder, const char* className)
98{
99#if USE(JSC)
100    ASSERT(JSLock::lockCount() > 0);
101#endif
102
103    char* c = fastStrDup(className);
104
105    char* result = c;
106    while (*c) {
107        if (*c == '.')
108            *c = '/';
109        c++;
110    }
111
112    builder.append(result);
113
114    fastFree(result);
115}
116
117const char* JavaMethodJobject::signature() const
118{
119    if (!m_signature) {
120#if USE(JSC)
121        JSLock lock(SilenceAssertionsOnly);
122#endif
123
124        StringBuilder signatureBuilder;
125        signatureBuilder.append('(');
126        for (unsigned int i = 0; i < m_parameters.size(); i++) {
127            CString javaClassName = parameterAt(i).utf8();
128            JavaType type = javaTypeFromClassName(javaClassName.data());
129            if (type == JavaTypeArray)
130                appendClassName(signatureBuilder, javaClassName.data());
131            else {
132                signatureBuilder.append(signatureFromJavaType(type));
133                if (type == JavaTypeObject
134// ANDROID
135                    || type == JavaTypeString
136// ANDROID
137                    ) {
138                    appendClassName(signatureBuilder, javaClassName.data());
139                    signatureBuilder.append(';');
140                }
141            }
142        }
143        signatureBuilder.append(')');
144
145        const char* returnType = m_returnTypeClassName.utf8();
146        if (m_returnType == JavaTypeArray)
147            appendClassName(signatureBuilder, returnType);
148        else {
149            signatureBuilder.append(signatureFromJavaType(m_returnType));
150            if (m_returnType == JavaTypeObject
151// ANDROID
152                || m_returnType == JavaTypeString
153// ANDROID
154                ) {
155                appendClassName(signatureBuilder, returnType);
156                signatureBuilder.append(';');
157            }
158        }
159
160        String signatureString = signatureBuilder.toString();
161        m_signature = fastStrDup(signatureString.utf8().data());
162    }
163
164    return m_signature;
165}
166
167#endif // ENABLE(JAVA_BRIDGE)
168