linphone-ios/wrappers/java/genwrapper.py

903 lines
38 KiB
Python

#!/usr/bin/python
# Copyright (C) 2017 Belledonne Communications SARL
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
import argparse
import os
import sys
import pystache
import errno
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools'))
print(sys.path)
import genapixml as CApi
import abstractapi as AbsApi
import metadoc
##########################################################################
ENUMS_LIST = {
'AccountCreatorActivationCodeStatus': 'AccountCreator',
'AccountCreatorDomainStatus': 'AccountCreator',
'AccountCreatorEmailStatus': 'AccountCreator',
'AccountCreatorLanguageStatus': 'AccountCreator',
'AccountCreatorPasswordStatus': 'AccountCreator',
'AccountCreatorPhoneNumberStatus': 'AccountCreator',
'AccountCreatorStatus': 'AccountCreator',
'AccountCreatorTransportStatus': 'AccountCreator',
'AccountCreatorUsernameStatus': 'AccountCreator',
'AddressFamily': 'CallStats',
'AudioRoute': 'Call',
'AuthMethod': 'Core',
'CallDir': 'Call',
'CallState': 'Call',
'CallStatus': 'CallLog',
'ChatRoomState': 'ChatRoom',
'ChatMessageDirection': 'ChatMessage',
'ChatMessageState': 'ChatMessage',
'ConfiguringState': 'Core',
'ConsolidatedPresence': 'PresenceModel',
'CoreLogCollectionUploadState': 'Core',
'EcCalibratorStatus': 'Core',
'EventLogType': 'EventLog',
'GlobalState': 'Core',
'FriendListStatus': 'FriendList',
'FriendListSyncStatus': 'FriendList',
'IceState': 'CallStats',
'LimeState': 'Core',
'LogCollectionState': 'Core',
'MediaDirection': 'Core',
'MediaEncryption': 'Core',
'PlayerState': 'Player',
'PresenceActivityType': 'PresenceActivity',
'PublishState': 'Event',
'RegistrationState': 'Core',
'StreamType': 'CallStats',
'SubscriptionDir': 'Event',
'SubscribePolicy': 'Friend',
'TransportType': 'Address',
'TunnelMode': 'Tunnel',
'UpnpState': 'Core',
'VersionUpdateCheckResult': 'Core',
'XmlRpcRequestArgType': 'XmlRpcRequest',
'XmlRpcRequestStatus': 'XmlRpcRequest',
}
##########################################################################
class JavaTranslator(object):
def __init__(self, packageName, exceptions):
self.exceptions = exceptions
package_dirs = packageName.split('.')
self.jni_package = ''
self.jni_path = ''
for directory in package_dirs:
self.jni_package += directory + '_'
self.jni_path += directory + '/'
self.docTranslator = metadoc.JavaDocTranslator()
def throws_exception(self, _type):
if not self.exceptions:
return False
if type(_type) is AbsApi.BaseType:
if _type.name == 'status':
return True
return False
def translate_argument_name(self, _argName):
return _argName.to_snake_case()
def translate_java_jni_enum_name(self, _enum):
name = _enum.name.to_camel_case()
if name in ENUMS_LIST:
className = ENUMS_LIST[name]
if name.startswith(className):
name = name[len(className):]
name = className + '$' + name
return name
def translate_java_jni_base_type_name(self, _type):
if _type == 'string':
return 'Ljava/lang/String;'
elif _type == 'integer':
return 'I'
elif _type == 'boolean':
return 'Z'
elif _type == 'floatant':
return 'F'
elif _type == 'size':
return 'I'
elif _type == 'time':
return 'I'
elif _type == 'status':
return 'I'
elif _type == 'string_array':
return '[Ljava/lang/String;'
elif _type == 'character':
return 'C'
elif _type == 'void':
return 'V'
return _type
def translate_as_c_base_type(self, t):
_type = t.name
if _type == 'string':
return 'char *'
elif _type == 'integer':
if t.size is None:
if t.isUnsigned:
return 'unsigned int'
return 'int'
inttype = 'int{0}_t'.format(t.size)
if t.isUnsigned:
inttype = 'u' + inttype
if t.isref:
inttype = inttype + ' *'
if t.isconst:
inttype = 'const ' + inttype
return inttype
elif _type == 'boolean':
return 'bool_t'
elif _type == 'floatant':
return 'float'
elif _type == 'size':
return 'size_t'
elif _type == 'time':
return 'time_t'
elif _type == 'status':
return 'int'
elif _type == 'string_array':
return 'char **'
elif _type == 'character':
return 'char'
elif _type == 'void':
if t.isref:
return 'void *'
return 'void'
return _type
def translate_type(self, _type, native=False, jni=False, isReturn=False):
if type(_type) is AbsApi.ListType:
if jni:
if type(_type.containedTypeDesc) is AbsApi.ClassType:
return 'jobjectArray'
elif type(_type.containedTypeDesc) is AbsApi.BaseType:
if _type.containedTypeDesc.name == 'string':
return 'jobjectArray'
return self.translate_type(_type.containedTypeDesc, jni=True) + 'Array'
elif type(_type.containedTypeDesc) is AbsApi.EnumType:
ptrtype = self.translate_type(_type.containedTypeDesc, native)
ptrtype = ''
if type(_type.containedTypeDesc) is AbsApi.ClassType:
ptrtype = self.translate_type(_type.containedTypeDesc, native)
elif type(_type.containedTypeDesc) is AbsApi.BaseType:
ptrtype = self.translate_type(_type.containedTypeDesc, native)
elif type(_type.containedTypeDesc) is AbsApi.EnumType:
ptrtype = self.translate_type(_type.containedTypeDesc, native)
else:
if _type.containedTypeDesc:
raise AbsApi.Error('translation of bctbx_list_t of ' + _type.containedTypeDesc.name)
else:
raise AbsApi.Error('translation of bctbx_list_t of unknow type !')
return ptrtype + '[]'
elif type(_type) is AbsApi.ClassType:
if jni:
return 'jobject'
return _type.desc.name.to_camel_case()
elif type(_type) is AbsApi.EnumType:
if native:
return 'int'
elif jni:
return 'jint'
if _type.desc.name.to_camel_case() == "XmlRpcStatus":
return "XmlRpcRequest.Status"
elif _type.desc.name.to_camel_case() == "XmlRpcArgType":
return "XmlRpcRequest.ArgType"
name = _type.desc.name.to_camel_case()
if name in ENUMS_LIST:
className = ENUMS_LIST[name]
if name.startswith(className):
name = name[len(className):]
name = className + '.' + name
return name
elif type(_type) is AbsApi.BaseType:
if _type.name == 'string':
if jni:
return 'jstring'
return 'String'
elif _type.name == 'integer':
if _type.size is not None and _type.isref:
if jni:
return 'jbyteArray'
return 'byte[]'
if jni:
return 'jint'
return 'int'
elif _type.name == 'boolean':
if jni:
return 'jboolean'
return 'boolean'
elif _type.name == 'floatant':
if jni:
return 'jfloat'
return 'float'
elif _type.name == 'size':
if jni:
return 'jint'
return 'int'
elif _type.name == 'time':
if jni:
return 'jlong'
return 'long'
elif _type.name == 'status':
if jni:
return 'jint'
if native:
return 'int'
return 'void'
elif _type.name == 'string_array':
if jni:
return 'jobjectArray'
return 'String[]'
elif _type.name == 'character':
if jni:
return 'jchar'
return 'char'
elif _type.name == 'void':
if isReturn:
return 'void'
if jni:
return 'jobject'
return 'Object'
return _type.name
def translate_argument(self, _arg, native=False, jni=False):
return '{0} {1}'.format(self.translate_type(_arg.type, native, jni), self.translate_argument_name(_arg.name))
def translate_property(self, _property):
properties = []
if _property.getter is not None:
properties.append(self.translate_method(_property.getter))
if _property.setter is not None:
properties.append(self.translate_method(_property.setter))
return properties
def translate_jni_property(self, className, _property):
properties = []
if _property.getter is not None:
properties.append(self.translate_jni_method(className, _property.getter))
if _property.setter is not None:
properties.append(self.translate_jni_method(className, _property.setter))
return properties
def generate_listener(self, name, _class):
methodDict = {}
methodDict['return'] = 'void'
methodDict['return_native'] = 'void'
methodDict['return_keyword'] = ''
methodDict['convertInputClassArrayToLongArray'] = False
methodDict['name'] = name
methodDict['exception'] = False
methodDict['enumCast'] = False
methodDict['classCast'] = False
methodDict['params'] = _class.name.to_camel_case() + 'Listener listener'
methodDict['native_params'] = 'long nativePtr, ' + _class.name.to_camel_case() + 'Listener listener'
methodDict['static_native_params'] = ''
methodDict['native_params_impl'] = ', listener'
methodDict['deprecated'] = False
methodDict['doc'] = None
return methodDict
def generate_add_listener(self, _class):
return self.generate_listener('addListener', _class)
def generate_remove_listener(self, _class):
return self.generate_listener('removeListener', _class)
def generate_set_listener(self, _class):
return self.generate_listener('setListener', _class)
def translate_method(self, _method):
methodDict = {}
methodDict['return'] = self.translate_type(_method.returnType, isReturn=True)
methodDict['return_native'] = self.translate_type(_method.returnType, native=True, isReturn=True)
methodDict['return_keyword'] = '' if methodDict['return'] == 'void' else 'return '
methodDict['hasReturn'] = not methodDict['return'] == 'void'
methodDict['convertInputClassArrayToLongArray'] = False
methodDict['name'] = _method.name.to_camel_case(lower=True)
methodDict['exception'] = self.throws_exception(_method.returnType)
methodDict['enumCast'] = type(_method.returnType) is AbsApi.EnumType
methodDict['classCast'] = type(_method.returnType) is AbsApi.ClassType
methodDict['params'] = ''
methodDict['native_params'] = 'long nativePtr'
methodDict['static_native_params'] = ''
methodDict['native_params_impl'] = ''
for arg in _method.args:
if arg is not _method.args[0]:
methodDict['params'] += ', '
methodDict['static_native_params'] += ', '
methodDict['native_params'] += ', '
methodDict['native_params_impl'] += ', '
methodDict['params'] += self.translate_argument(arg)
methodDict['native_params'] += self.translate_argument(arg, True)
methodDict['static_native_params'] += self.translate_argument(arg, True)
if type(arg.type) is AbsApi.EnumType:
methodDict['native_params_impl'] += self.translate_argument_name(arg.name) + '.toInt()'
else:
methodDict['native_params_impl'] += self.translate_argument_name(arg.name)
methodDict['deprecated'] = _method.deprecated
methodDict['doc'] = _method.briefDescription.translate(self.docTranslator) if _method.briefDescription is not None else None
return methodDict
def translate_jni_method(self, className, _method, static=False):
methodDict = {}
methodDict['classCName'] = 'Linphone' + className.to_camel_case()
methodDict['className'] = className.to_camel_case()
methodDict['classImplName'] = className.to_camel_case() + 'Impl'
methodDict['jniPath'] = self.jni_path
methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True)
methodDict['hasListReturn'] = methodDict['return'] == 'jobjectArray'
methodDict['hasByteArrayReturn'] = methodDict['return'] == 'jbyteArray'
methodDict['hasReturn'] = not methodDict['return'] == 'void' and not methodDict['hasListReturn'] and not methodDict['hasByteArrayReturn']
methodDict['hasStringReturn'] = methodDict['return'] == 'jstring'
methodDict['hasNormalReturn'] = not methodDict['hasListReturn'] and not methodDict['hasStringReturn'] and not methodDict['hasByteArrayReturn']
methodDict['name'] = 'Java_' + self.jni_package + className.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True)
methodDict['notStatic'] = not static
methodDict['c_name'] = 'linphone_' + className.to_snake_case() + "_" + _method.name.to_snake_case()
methodDict['returnObject'] = methodDict['hasReturn'] and type(_method.returnType) is AbsApi.ClassType
methodDict['returnClassName'] = self.translate_type(_method.returnType)
methodDict['isRealObjectArray'] = False
methodDict['isStringObjectArray'] = False
methodDict['c_type_return'] = self.translate_as_c_base_type(_method.returnType)
if methodDict['hasListReturn']:
if type(_method.returnType) is AbsApi.BaseType and _method.returnType.name == 'string_array':
methodDict['isStringObjectArray'] = True
elif type(_method.returnType.containedTypeDesc) is AbsApi.BaseType:
methodDict['isStringObjectArray'] = True
elif type(_method.returnType.containedTypeDesc) is AbsApi.ClassType:
methodDict['isRealObjectArray'] = True
methodDict['objectCPrefix'] = 'linphone_' + _method.returnType.containedTypeDesc.desc.name.to_snake_case()
methodDict['objectClassCName'] = 'Linphone' + _method.returnType.containedTypeDesc.desc.name.to_camel_case()
methodDict['objectClassName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case()
methodDict['objectClassImplName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() + 'Impl'
methodDict['params'] = 'JNIEnv *env, jobject thiz, jlong ptr'
methodDict['params_impl'] = ''
methodDict['strings'] = []
methodDict['objects'] = []
methodDict['lists'] = []
methodDict['array'] = []
methodDict['bytes'] = []
methodDict['returnedObjectGetter'] = ''
for arg in _method.args:
methodDict['params'] += ', '
if static:
if arg is not _method.args[0]:
methodDict['params_impl'] += ', '
else:
methodDict['params_impl'] += ', '
methodDict['params'] += self.translate_argument(arg, jni=True)
argname = self.translate_argument_name(arg.name)
if type(arg.type) is AbsApi.ClassType:
classCName = 'Linphone' + arg.type.desc.name.to_camel_case()
if classCName[-8:] == 'Listener':
classCName = 'Linphone' + arg.type.desc.name.to_camel_case()[:-8] + 'Cbs'
methodDict['objects'].append({'object': argname, 'objectClassCName': classCName})
methodDict['params_impl'] += 'c_' + argname
elif type(arg.type) is AbsApi.ListType:
isStringList = type(arg.type.containedTypeDesc) is AbsApi.BaseType and arg.type.containedTypeDesc.name == 'string'
isObjList = type(arg.type.containedTypeDesc) is AbsApi.ClassType
methodDict['lists'].append({'list': argname, 'isStringList': isStringList, 'isObjList': isObjList, 'objectClassCName': arg.type.containedTypeDesc.name})
methodDict['params_impl'] += 'bctbx_list_' + argname
elif type(arg.type) is AbsApi.EnumType:
argCType = arg.type.name
methodDict['params_impl'] += '(' + argCType + ') ' + argname
elif type(arg.type) is AbsApi.BaseType:
if arg.type.name == 'integer' and arg.type.size is not None and arg.type.isref:
methodDict['bytes'].append({'bytesargname': argname, 'bytesargtype' : self.translate_as_c_base_type(arg.type)})
methodDict['params_impl'] += 'c_' + argname
elif arg.type.name == 'string':
methodDict['strings'].append({'string': argname})
methodDict['params_impl'] += 'c_' + argname
else:
methodDict['params_impl'] += '(' + self.translate_as_c_base_type(arg.type) + ')' + argname
else:
methodDict['params_impl'] += argname
return methodDict
def translate_class(self, _class):
classDict = {
'methods': [],
'jniMethods': [],
}
classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory"
classDict['isLinphoneCore'] = _class.name.to_camel_case() == "Core"
classDict['doc'] = _class.briefDescription.translate(self.docTranslator) if _class.briefDescription is not None else None
for _property in _class.properties:
try:
classDict['methods'] += self.translate_property(_property)
classDict['jniMethods'] += self.translate_jni_property(_class.name, _property)
except AbsApi.Error as e:
print('error while translating {0} property: {1}'.format(_property.name.to_snake_case(), e.args[0]))
for method in _class.instanceMethods:
try:
methodDict = self.translate_method(method)
jniMethodDict = self.translate_jni_method(_class.name, method)
classDict['methods'].append(methodDict)
classDict['jniMethods'].append(jniMethodDict)
except AbsApi.Error as e:
print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
for method in _class.classMethods:
try:
methodDict = self.translate_method(method)
jniMethodDict = self.translate_jni_method(_class.name, method, True)
classDict['methods'].append(methodDict)
classDict['jniMethods'].append(jniMethodDict)
except AbsApi.Error as e:
print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
islistenable = _class.listenerInterface is not None
if islistenable:
isMultiListener = (_class.multilistener)
if isMultiListener:
classDict['methods'].append(self.generate_add_listener(_class))
classDict['methods'].append(self.generate_remove_listener(_class))
else:
classDict['methods'].append(self.generate_set_listener(_class))
return classDict
def translate_jni_interface(self, _class, className, _method):
methodDict = {}
listenerName = 'Linphone' + className.to_camel_case()
methodDict['classCName'] = listenerName[:-8] #Remove Listener at the end
methodDict['className'] = className.to_camel_case()
methodDict['classImplName'] = className.to_camel_case() + 'Impl'
methodDict['jniPath'] = self.jni_path
methodDict['cPrefix'] = 'linphone_' + className.to_snake_case()[:-9] # Remove _listener at the end
methodDict['callbackName'] = methodDict['cPrefix'] + '_' + _method.name.to_snake_case()
methodDict['jname'] = _method.name.to_camel_case(lower=True)
methodDict['return'] = self.translate_as_c_base_type(_method.returnType)
methodDict['jniUpcallMethod'] = 'CallVoidMethod'
methodDict['isJniUpcallBasicType'] = False
methodDict['isJniUpcallObject'] = False
if type(_method.returnType) is AbsApi.ClassType:
methodDict['return'] += '*'
methodDict['jniUpcallMethod'] = 'CallObjectMethod'
methodDict['isJniUpcallObject'] = True
methodDict['jniUpcallType'] = 'jobject'
elif type(_method.returnType) is AbsApi.BaseType:
if not _method.returnType.name == 'void':
methodDict['jniUpcallMethod'] = 'CallIntMethod'
methodDict['jniUpcallType'] = self.translate_type(_method.returnType, jni=True)
methodDict['isJniUpcallBasicType'] = True
methodDict['returnIfFail'] = '' if methodDict['return'] == 'void' else ' NULL'
methodDict['hasReturn'] = not methodDict['return'] == 'void'
methodDict['isSingleListener'] = not _class.multilistener
methodDict['isMultiListener'] = _class.multilistener
methodDict['firstParam'] = ''
methodDict['jobjects'] = []
methodDict['jenums'] = []
methodDict['jstrings'] = []
methodDict['params'] = ''
methodDict['jparams'] = '('
methodDict['params_impl'] = ''
for arg in _method.args:
argname = self.translate_argument_name(arg.name)
if arg is not _method.args[0]:
methodDict['params'] += ', '
methodDict['params_impl'] += ', '
else:
methodDict['firstParam'] = argname
if (arg.type.isconst):
methodDict['params'] += 'const '
if type(arg.type) is AbsApi.ClassType:
methodDict['params'] += 'Linphone' + arg.type.desc.name.to_camel_case() + ' *' + argname
methodDict['jparams'] += 'L' + self.jni_path + arg.type.desc.name.to_camel_case() + ';'
methodDict['params_impl'] += 'j_' + argname
methodDict['jobjects'].append({'objectName': argname, 'className': arg.type.desc.name.to_camel_case(), })
elif type(arg.type) is AbsApi.BaseType:
methodDict['params'] += self.translate_as_c_base_type(arg.type) + ' ' + argname
methodDict['jparams'] += self.translate_java_jni_base_type_name(arg.type.name)
if arg.type.name == 'string':
methodDict['params_impl'] += 'j_' + argname
methodDict['jstrings'].append({'stringName': argname,})
else:
methodDict['params_impl'] += argname
elif type(arg.type) is AbsApi.EnumType:
methodDict['params'] += 'Linphone' + arg.type.desc.name.to_camel_case() + ' ' + argname
methodDict['jparams'] += 'L' + self.jni_path + self.translate_java_jni_enum_name(arg.type.desc) + ';'
methodDict['params_impl'] += 'j_' + argname
methodDict['jenums'].append({'enumName': argname, 'cEnumPrefix': 'linphone_' + arg.type.desc.name.to_snake_case()})
methodDict['jparams'] += ')'
if (methodDict['return'] == 'void'):
methodDict['jparams'] += 'V'
else:
if type(_method.returnType) is AbsApi.ClassType:
methodDict['jparams'] += 'L' + self.jni_path + _method.returnType.desc.name.to_camel_case() + ';'
elif type(_method.returnType) is AbsApi.BaseType:
methodDict['jparams'] += self.translate_java_jni_base_type_name(_method.returnType.name)
else:
pass #TODO
return methodDict
def translate_interface(self, _class):
interfaceDict = {
'methods': [],
'jniMethods': [],
}
interfaceDict['doc'] = _class.briefDescription.translate(self.docTranslator)
for method in _class.methods:
interfaceDict['methods'].append(self.translate_method(method))
interfaceDict['jniMethods'].append(self.translate_jni_interface(_class.listenedClass, _class.name, method))
return interfaceDict
def translate_enum(self, enum):
enumDict = {
'jniMethods': [],
}
enumDict['name'] = enum.name.to_camel_case()
enumDict['doc'] = enum.briefDescription.translate(self.docTranslator)
enumDict['values'] = []
i = 0
lastValue = None
enumDict['jniPath'] = self.jni_path
for enumValue in enum.enumerators:
enumValDict = {}
enumValDict['name'] = enumValue.name.to_camel_case()
enumValDict['doc'] = enumValue.briefDescription.translate(self.docTranslator)
if type(enumValue.value) is int:
lastValue = enumValue.value
enumValDict['value'] = str(enumValue.value)
elif type(enumValue.value) is AbsApi.Flag:
enumValDict['value'] = '1<<' + str(enumValue.value.position)
else:
if lastValue is not None:
enumValDict['value'] = lastValue + 1
lastValue += 1
else:
enumValDict['value'] = i
i += 1
enumValDict['commarorsemicolon'] = ';' if i == len(enum.enumerators) else ','
enumDict['values'].append(enumValDict)
return enumDict
##########################################################################
class JavaEnum(object):
def __init__(self, package, _enum, translator):
self._class = translator.translate_enum(_enum)
self.packageName = package
self.className = _enum.name.to_camel_case()
if self.className == 'XmlRpcArgType':
self.className = 'XmlRpcRequestArgType'
elif self.className == 'XmlRpcStatus':
self.className = 'XmlRpcRequestStatus'
self.cPrefix = 'linphone_' + _enum.name.to_snake_case()
self.filename = self.className + ".java"
self.values = self._class['values']
self.doc = self._class['doc']
self.jniName = translator.translate_java_jni_enum_name(_enum)
if self.className == 'XmlRpcRequestArgType':
self.jniName = 'XmlRpcRequest$ArgType'
elif self.className == 'XmlRpcRequestStatus':
self.jniName = 'XmlRpcRequest$Status'
class JniInterface(object):
def __init__(self, javaClass, apiClass):
self.isSingleListener = (not apiClass.multilistener)
self.isMultiListener = (apiClass.multilistener)
self.className = javaClass.className
self.classCName = javaClass.cName
self.cPrefix = javaClass.cPrefix
self.callbacks = []
listener = apiClass.listenerInterface
for method in listener.methods:
cb = 'linphone_' + listener.name.to_snake_case()[:-9] # Remove _listener at the end
cbName = cb + '_' + method.name.to_snake_case()
self.callbacks.append({
'callbackName': cbName,
'callback': method.name.to_snake_case()[3:], # Remove the on_
})
class JavaInterface(object):
def __init__(self, package, _interface, translator):
self._class = translator.translate_interface(_interface)
self.packageName = package
self.className = _interface.name.to_camel_case()
self.filename = self.className + ".java"
self.cPrefix = 'linphone_' + _interface.name.to_snake_case()
self.imports = []
self.methods = self._class['methods']
self.doc = self._class['doc']
self.jniMethods = self._class['jniMethods']
class JavaInterfaceStub(object):
def __init__(self, _interface):
self.packageName = _interface.packageName
self.className = _interface.className
self.classNameStub = self.className + "Stub"
self.filename = self.className + "Stub.java"
self.methods = _interface.methods
class JavaClass(object):
def __init__(self, package, _class, translator):
self._class = translator.translate_class(_class)
self.isLinphoneFactory = self._class['isLinphoneFactory']
self.isLinphoneCore = self._class['isLinphoneCore']
self.isNotLinphoneFactory = not self.isLinphoneFactory
self.cName = 'Linphone' + _class.name.to_camel_case()
self.cPrefix = 'linphone_' + _class.name.to_snake_case()
self.packageName = package
self.className = _class.name.to_camel_case()
self.classImplName = self.className + "Impl"
self.factoryName = _class.name.to_snake_case()
self.filename = self.className + ".java"
self.imports = []
self.methods = self._class['methods']
self.jniMethods = self._class['jniMethods']
self.doc = self._class['doc']
self.enums = []
self.jniInterface = None
if _class.listenerInterface is not None:
self.jniInterface = JniInterface(self, _class)
def add_enum(self, enum):
if enum.className.startswith(self.className):
enum.className = enum.className[len(self.className):]
self.enums.append(enum)
class Jni(object):
def __init__(self, package):
self.enums = []
self.interfaces = []
self.callbacks = []
self.objects = []
self.methods = []
self.jni_package = ''
self.jni_path = ''
package_dirs = package.split('.')
for directory in package_dirs:
self.jni_package += directory + '_'
self.jni_path += directory + '/'
def add_enum(self, javaEnum):
obj = {
'jniPrefix': self.jni_package,
'jniPath': self.jni_path,
'jniName': javaEnum.jniName,
'cPrefix': javaEnum.cPrefix,
'className': javaEnum.className,
}
self.enums.append(obj)
def add_object(self, javaClass):
if javaClass.className == 'Factory':
return
obj = {
'jniPrefix': self.jni_package,
'jniPath': self.jni_path,
'cPrefix': javaClass.cPrefix,
'className': javaClass.className,
'classCName': javaClass.cName,
'classImplName': javaClass.classImplName,
}
self.objects.append(obj)
jniInterface = javaClass.jniInterface
if jniInterface is not None:
interface = {
'isSingleListener': jniInterface.isSingleListener,
'isMultiListener': jniInterface.isMultiListener,
'classCName': jniInterface.classCName,
'className': jniInterface.className,
'cPrefix': jniInterface.cPrefix,
'jniPackage': self.jni_package,
'factoryName': javaClass.factoryName,
'callbacksList': []
}
for callback in jniInterface.callbacks:
interface['callbacksList'].append(callback)
self.interfaces.append(interface)
def add_callbacks(self, name, callbacks):
for callback in callbacks:
self.callbacks.append(callback)
def add_methods(self, name, methods):
for method in methods:
self.methods.append(method)
##########################################################################
class GenWrapper(object):
def __init__(self, srcdir, javadir, package, xmldir, exceptions):
self.srcdir = srcdir
self.javadir = javadir
self.package = package
self.exceptions = exceptions
project = CApi.Project()
project.initFromDir(xmldir)
project.check()
self.parser = AbsApi.CParser(project)
self.parser.functionBl = \
['linphone_factory_create_core_with_config',\
'linphone_factory_create_core',\
'linphone_factory_create_core_2',\
'linphone_factory_create_core_with_config_2',\
'linphone_vcard_get_belcard',\
'linphone_core_get_current_vtable',\
'linphone_factory_get',\
'linphone_factory_clean',\
'linphone_call_zoom_video',\
'linphone_core_get_zrtp_cache_db',\
'linphone_config_get_range']
self.parser.parse_all()
self.translator = JavaTranslator(package, exceptions)
self.renderer = pystache.Renderer()
self.jni = Jni(package)
self.enums = {}
self.interfaces = {}
self.classes = {}
self.enums_to_remove = []
def render_all(self):
for _interface in self.parser.interfacesIndex.values():
self.render_java_interface(_interface)
for _class in self.parser.classesIndex.values():
self.render_java_class(_class)
for _enum in self.parser.enumsIndex.items():
if _enum[1] is not None:
self.render_java_enum(_enum[1])
for name, value in self.enums.items():
self.jni.add_enum(value)
if name in ENUMS_LIST:
className = ENUMS_LIST[name]
print('Enum ' + name + ' belongs to class ' + className)
self.classes[className].add_enum(value)
self.enums_to_remove.append(name)
for enum in self.enums_to_remove:
self.enums.pop(enum, None)
for name, value in self.enums.items():
self.render(value, self.javadir + '/' + value.filename)
for name, value in self.interfaces.items():
self.render(value, self.javadir + '/' + value.filename)
for name, value in self.classes.items():
self.render(value, self.javadir + '/' + value.filename)
self.jni.add_object(value)
self.render(self.jni, self.srcdir + '/linphone_jni.cc')
def render(self, item, path):
tmppath = path + '.tmp'
content = ''
with open(tmppath, mode='w') as f:
f.write(self.renderer.render(item))
with open(tmppath, mode='rU') as f:
content = f.read()
with open(path, mode='w') as f:
f.write(content)
os.unlink(tmppath)
def render_java_enum(self, _class):
if _class is not None:
try:
javaenum = JavaEnum(self.package, _class, self.translator)
self.enums[javaenum.className] = javaenum
except AbsApi.Error as e:
print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0]))
def render_java_interface(self, _class):
if _class is not None:
try:
javainterface = JavaInterface(self.package, _class, self.translator)
self.interfaces[javainterface.className] = javainterface
javaInterfaceStub = JavaInterfaceStub(javainterface)
self.interfaces[javaInterfaceStub.classNameStub] = javaInterfaceStub
except AbsApi.Error as e:
print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0]))
self.jni.add_callbacks(javainterface.className, javainterface.jniMethods)
def render_java_class(self, _class):
if _class is not None:
try:
javaclass = JavaClass(self.package, _class, self.translator)
self.classes[javaclass.className] = javaclass
except AbsApi.Error as e:
print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0]))
self.jni.add_methods(javaclass.className, javaclass.jniMethods)
##########################################################################
def main():
argparser = argparse.ArgumentParser(description='Generate source files for the Java wrapper')
argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed')
argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.')
argparser.add_argument('-p --package', type=str, help='the package name for the wrapper', dest='package', default='org.linphone.core')
argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='name', default='linphone_jni.cc')
argparser.add_argument('-e --exceptions', type=bool, help='enable the wrapping of LinphoneStatus into CoreException', dest='exceptions', default=False)
args = argparser.parse_args()
srcdir = args.outputdir + '/src'
javadir = args.outputdir + '/java'
package_dirs = args.package.split('.')
for directory in package_dirs:
javadir += '/' + directory
try:
os.makedirs(srcdir)
except OSError as e:
if e.errno != errno.EEXIST:
print("Cannot create '{0}' dircetory: {1}".format(srcdir, e.strerror))
sys.exit(1)
try:
os.makedirs(javadir)
except OSError as e:
if e.errno != errno.EEXIST:
print("Cannot create '{0}' dircetory: {1}".format(javadir, e.strerror))
sys.exit(1)
genwrapper = GenWrapper(srcdir, javadir, args.package, args.xmldir, args.exceptions)
genwrapper.render_all()
if __name__ == '__main__':
main()