summaryrefslogtreecommitdiffstats
path: root/bridges/source/jni_uno/jni_info.h
blob: 7a18e553e4004ff96e63918d03200ca083cd4c60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#pragma once

#include <sal/config.h>

#include <unordered_map>

#include "jni_base.h"

#include <mutex>
#include <rtl/ref.hxx>
#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>

#include <uno/environment.h>
#include <typelib/typedescription.hxx>

#include <com/sun/star/uno/Type.hxx>

namespace jvmaccess { class UnoVirtualMachine; }

namespace jni_uno
{

inline bool type_equals(
    typelib_TypeDescriptionReference * type1,
    typelib_TypeDescriptionReference * type2 )
{
    if (type1 == type2)
        return true;
    OUString const & name1 =
          OUString::unacquired( &type1->pTypeName );
    OUString const & name2 =
          OUString::unacquired( &type2->pTypeName );
    return ((type1->eTypeClass == type2->eTypeClass) && name1 == name2);
}

inline bool is_XInterface( typelib_TypeDescriptionReference * type )
{
    return ((typelib_TypeClass_INTERFACE == type->eTypeClass) &&
            OUString::unacquired( &type->pTypeName ) == "com.sun.star.uno.XInterface");
}

struct JNI_type_info
{
    JNI_type_info(const JNI_type_info&) = delete;
    const JNI_type_info& operator=(const JNI_type_info&) = delete;

    ::com::sun::star::uno::TypeDescription      m_td;
    jclass                                      m_class;

    virtual void destroy( JNIEnv * jni_env ) = 0;
protected:
    void destruct( JNIEnv * jni_env )
        { jni_env->DeleteGlobalRef( m_class ); }
    virtual ~JNI_type_info() {}
    explicit JNI_type_info(
        JNI_context const & jni, typelib_TypeDescription * td );
};

struct JNI_interface_type_info : public JNI_type_info
{
    jobject                                     m_proxy_ctor; // proxy ctor
    jobject                                     m_type;
    // sorted via typelib function index
    std::unique_ptr<jmethodID[]>                m_methods;

    virtual void destroy( JNIEnv * jni_env ) override;
    explicit JNI_interface_type_info(
        JNI_context const & jni, typelib_TypeDescription * td );

private:
    virtual ~JNI_interface_type_info() override {}
};

struct JNI_compound_type_info : public JNI_type_info
{
    JNI_type_info const *                       m_base;
    // ctor( msg ) for exceptions
    jmethodID                                   m_exc_ctor;
    // sorted via typelib member index
    std::unique_ptr<jfieldID[]>                 m_fields;

    virtual void destroy( JNIEnv * jni_env ) override;
    explicit JNI_compound_type_info(
        JNI_context const & jni, typelib_TypeDescription * td );

private:
    virtual ~JNI_compound_type_info() override {}
};

struct JNI_type_info_holder
{
    JNI_type_info * m_info;

    JNI_type_info_holder(const JNI_type_info_holder&) = delete;
    const JNI_type_info_holder& operator=(const JNI_type_info_holder&) = delete;

    JNI_type_info_holder() : m_info( nullptr ) {}
};

typedef std::unordered_map<
    OUString, JNI_type_info_holder > t_str2type;

class JNI_info
{
    mutable std::mutex          m_mutex;
    mutable t_str2type          m_type_map;

public:
    // These two are needed very early by find_class from within the ctor:
    jclass                      m_class_Class;
    jmethodID                   m_method_Class_forName;

    jobject                     m_object_java_env;
    jobject                     m_object_Any_VOID;
    jobject                     m_object_Type_UNSIGNED_SHORT;
    jobject                     m_object_Type_UNSIGNED_LONG;
    jobject                     m_object_Type_UNSIGNED_HYPER;

    jclass                      m_class_Object;
    jclass                      m_class_Character;
    jclass                      m_class_Boolean;
    jclass                      m_class_Byte;
    jclass                      m_class_Short;
    jclass                      m_class_Integer;
    jclass                      m_class_Long;
    jclass                      m_class_Float;
    jclass                      m_class_Double;
    jclass                      m_class_String;

    jclass                      m_class_UnoRuntime;
    jclass                      m_class_RuntimeException;
    jclass                      m_class_Any;
    jclass                      m_class_Type;
    jclass                      m_class_TypeClass;
    jclass                      m_class_JNI_proxy;
    jclass                      m_class_AsynchronousFinalizer;

    jmethodID                   m_method_Object_toString;
    jmethodID                   m_method_Class_getName;
    jmethodID                   m_method_Throwable_getMessage;
    jmethodID                   m_ctor_Character_with_char;
    jmethodID                   m_ctor_Boolean_with_boolean;
    jmethodID                   m_ctor_Byte_with_byte;
    jmethodID                   m_ctor_Short_with_short;
    jmethodID                   m_ctor_Integer_with_int;
    jmethodID                   m_ctor_Long_with_long;
    jmethodID                   m_ctor_Float_with_float;
    jmethodID                   m_ctor_Double_with_double;
    jmethodID                   m_method_Boolean_booleanValue;
    jmethodID                   m_method_Byte_byteValue;
    jmethodID                   m_method_Character_charValue;
    jmethodID                   m_method_Double_doubleValue;
    jmethodID                   m_method_Float_floatValue;
    jmethodID                   m_method_Integer_intValue;
    jmethodID                   m_method_Long_longValue;
    jmethodID                   m_method_Short_shortValue;

    jmethodID                   m_method_IEnvironment_getRegisteredInterface;
    jmethodID                   m_method_IEnvironment_registerInterface;
    jmethodID                   m_method_UnoRuntime_generateOid;
    jmethodID                   m_method_UnoRuntime_queryInterface;
    jmethodID                   m_ctor_Any_with_Type_Object;
    jfieldID                    m_field_Any_type;
    jfieldID                    m_field_Any_object;
    jmethodID                   m_ctor_Type_with_Class;
    jmethodID                   m_ctor_Type_with_Name_TypeClass;
    jfieldID                    m_field_Type_typeName;
    jmethodID                   m_method_TypeClass_fromInt;
    jfieldID                    m_field_Enum_m_value;

    jmethodID                   m_method_JNI_proxy_get_proxy_ctor;
    jmethodID                   m_method_JNI_proxy_create;
    jfieldID                    m_field_JNI_proxy_m_receiver_handle;
    jfieldID                    m_field_JNI_proxy_m_td_handle;
    jfieldID                    m_field_JNI_proxy_m_type;
    jfieldID                    m_field_JNI_proxy_m_oid;

    jmethodID                   m_ctor_AsynchronousFinalizer;
    jmethodID                   m_method_AsynchronousFinalizer_drain;

    ::com::sun::star::uno::TypeDescription m_XInterface_queryInterface_td;
    ::com::sun::star::uno::Type const & m_Exception_type;
    ::com::sun::star::uno::Type const & m_RuntimeException_type;
    ::com::sun::star::uno::Type const & m_void_type;
    JNI_interface_type_info const * m_XInterface_type_info;

    // noncopyable
    JNI_info(const JNI_info&) = delete;
    const JNI_info& operator=(const JNI_info&) = delete;

    JNI_type_info const * get_type_info(
        JNI_context const & jni,
        typelib_TypeDescription * type ) const;
    JNI_type_info const * get_type_info(
        JNI_context const & jni,
        typelib_TypeDescriptionReference * type ) const;
    JNI_type_info const * get_type_info(
        JNI_context const & jni,
        OUString const & uno_name ) const;
    inline static void append_sig(
        OStringBuffer * buf, typelib_TypeDescriptionReference * type,
        bool use_Object_for_type_XInterface = true, bool use_slashes = true );

    // get this
    static JNI_info const * get_jni_info(
        rtl::Reference< jvmaccess::UnoVirtualMachine > const & uno_vm );
    inline void destroy( JNIEnv * jni_env );

private:
    JNI_type_info const * create_type_info(
        JNI_context const & jni, typelib_TypeDescription * td ) const;

    void destruct( JNIEnv * jni_env );

    JNI_info( JNIEnv * jni_env, jobject class_loader,
              jclass classClass, jmethodID methodForName );
    ~JNI_info() {}
};

inline void JNI_info::destroy( JNIEnv * jni_env )
{
    destruct( jni_env );
    delete this;
}

inline void JNI_info::append_sig(
    OStringBuffer * buf, typelib_TypeDescriptionReference * type,
    bool use_Object_for_type_XInterface, bool use_slashes )
{
    switch (type->eTypeClass)
    {
    case typelib_TypeClass_VOID:
        buf->append( 'V' );
        break;
    case typelib_TypeClass_CHAR:
        buf->append( 'C' );
        break;
    case typelib_TypeClass_BOOLEAN:
        buf->append( 'Z' );
        break;
    case typelib_TypeClass_BYTE:
        buf->append( 'B' );
        break;
    case typelib_TypeClass_SHORT:
    case typelib_TypeClass_UNSIGNED_SHORT:
        buf->append( 'S' );
        break;
    case typelib_TypeClass_LONG:
    case typelib_TypeClass_UNSIGNED_LONG:
        buf->append( 'I' );
        break;
    case typelib_TypeClass_HYPER:
    case typelib_TypeClass_UNSIGNED_HYPER:
        buf->append( 'J' );
        break;
    case typelib_TypeClass_FLOAT:
        buf->append( 'F' );
        break;
    case typelib_TypeClass_DOUBLE:
        buf->append( 'D' );
        break;
    case typelib_TypeClass_STRING:
        if ( use_slashes ) {
            buf->append( "Ljava/lang/String;" );
        } else {
            buf->append( "Ljava.lang.String;" );
        }
        break;
    case typelib_TypeClass_TYPE:
        if ( use_slashes ) {
            buf->append( "Lcom/sun/star/uno/Type;" );
        } else {
            buf->append( "Lcom.sun.star.uno.Type;" );
        }
        break;
    case typelib_TypeClass_ANY:
        if ( use_slashes ) {
            buf->append( "Ljava/lang/Object;" );
        } else {
            buf->append( "Ljava.lang.Object;" );
        }
        break;
    case typelib_TypeClass_ENUM:
    case typelib_TypeClass_STRUCT:
    case typelib_TypeClass_EXCEPTION:
    {
        OUString const & uno_name =
              OUString::unacquired( &type->pTypeName );
        buf->append( 'L' );
        // Erase type arguments of instantiated polymorphic struct types:
        sal_Int32 i = uno_name.indexOf( '<' );
        if ( i < 0 ) {
            buf->append(
                OUStringToOString(
                    use_slashes ? uno_name.replace( '.', '/' ) : uno_name,
                    RTL_TEXTENCODING_JAVA_UTF8 ) );
        } else {
            OUString s( uno_name.copy( 0, i ) );
            buf->append(
                OUStringToOString(
                    use_slashes ? s.replace( '.', '/' ) : s,
                    RTL_TEXTENCODING_JAVA_UTF8 ) );
        }
        buf->append( ';' );
        break;
    }
    case typelib_TypeClass_SEQUENCE:
    {
        buf->append( '[' );
        TypeDescr td( type );
        append_sig(
            buf, reinterpret_cast<typelib_IndirectTypeDescription *>(td.get())->pType,
            use_Object_for_type_XInterface, use_slashes );
        break;
    }
    case typelib_TypeClass_INTERFACE:
        if (use_Object_for_type_XInterface && is_XInterface( type ))
        {
            if ( use_slashes ) {
                buf->append( "Ljava/lang/Object;" );
            } else {
                buf->append( "Ljava.lang.Object;" );
            }
        }
        else
        {
            OUString const & uno_name =
                  OUString::unacquired( &type->pTypeName );
            buf->append( 'L' );
            buf->append(
                OUStringToOString(
                    use_slashes ? uno_name.replace( '.', '/' ) : uno_name,
                    RTL_TEXTENCODING_JAVA_UTF8 ) );
            buf->append( ';' );
        }
        break;
    default:
        throw BridgeRuntimeError(
            "unsupported type: " +
            OUString::unacquired( &type->pTypeName ) );
    }
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */