--- a/trunk/php-java-bridge/java.c +++ b/trunk/php-java-bridge/java.c @@ -17,6 +17,10 @@ #include "java_bridge.h" #include "protocol.h" +#ifdef ZEND_ENGINE_2 +#include "zend_interfaces.h" +#endif + ZEND_DECLARE_MODULE_GLOBALS(java) PHP_RINIT_FUNCTION(java) @@ -97,10 +101,54 @@ (*JG(jenv))->DeleteLocalRef(JG(jenv), p); } +PHP_FUNCTION(java_instanceof) +{ + zval **pobj, **pclass, **handle; + jobject obj; + jclass class; + jboolean result; + int type, n; + + if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &pobj, &pclass) == FAILURE) + WRONG_PARAM_COUNT; + + convert_to_object_ex(pobj); + convert_to_object_ex(pclass); + + if(!JG(jenv)) { + php_error(E_ERROR, "java not initialized"); + return; + } + + n = zend_hash_index_find(Z_OBJPROP_PP(pobj), 0, (void**) &handle); + if(n==FAILURE) { + php_error(E_ERROR, "parameter #1 is not a java object"); + return; + } + obj = zend_list_find(Z_LVAL_PP(handle), &type); + assert(obj); + + n = zend_hash_index_find(Z_OBJPROP_PP(pclass), 0, (void**) &handle); + if(n==FAILURE) { + php_error(E_ERROR, "parameter #2 is not a java object"); + return; + } + class = zend_list_find(Z_LVAL_PP(handle), &type); + assert(class); + + result = (*JG(jenv))->IsInstanceOf(JG(jenv), obj, class); + if(result == JNI_TRUE) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} + function_entry java_functions[] = { PHP_FE(java_last_exception_get, NULL) PHP_FE(java_last_exception_clear, NULL) PHP_FE(java_set_library_path, NULL) + PHP_FE(java_instanceof, NULL) {NULL, NULL, NULL} }; @@ -222,7 +270,7 @@ } php_java_call_function_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, - "java", 1, 0, + "java", 1, 1, getThis(), argc, argv); efree(argv); @@ -240,7 +288,7 @@ } php_java_call_function_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, - "java", 1, 1, + "java", 1, 0, getThis(), argc, argv); efree(argv); @@ -313,15 +361,233 @@ php_java_get_property_handler(Z_STRVAL(*argv[0]), getThis(), return_value); efree(argv); } +PHP_METHOD(java, offsetExists) +{ + zval **argv, **handle; + int type, argc; + jobject obj, map; + + argc = ZEND_NUM_ARGS(); + argv = (zval **) safe_emalloc(sizeof(zval *), argc, 0); + if (zend_get_parameters_array(ht, argc, argv) == FAILURE) { + php_error(E_ERROR, "Couldn't fetch arguments into array."); + RETURN_NULL(); + } + zend_hash_index_find(Z_OBJPROP_P(getThis()), 0, (void**) &handle); + obj = zend_list_find(Z_LVAL_PP(handle), &type); + map = (*JG(jenv))->CallObjectMethod(1, JG(jenv), JG(php_reflect), JG(getPhpMap), obj); + + php_java_invoke("offsetExists", map, argc, argv, return_value); + +} +PHP_METHOD(java, offsetGet) +{ + zval **argv, **handle; + int type, argc; + jobject obj, map; + + argc = ZEND_NUM_ARGS(); + argv = (zval **) safe_emalloc(sizeof(zval *), argc, 0); + if (zend_get_parameters_array(ht, argc, argv) == FAILURE) { + php_error(E_ERROR, "Couldn't fetch arguments into array."); + RETURN_NULL(); + } + zend_hash_index_find(Z_OBJPROP_P(getThis()), 0, (void**) &handle); + obj = zend_list_find(Z_LVAL_PP(handle), &type); + map = (*JG(jenv))->CallObjectMethod(1, JG(jenv), JG(php_reflect), JG(getPhpMap), obj); + + php_java_invoke("offsetGet", map, argc, argv, return_value); + +} + +PHP_METHOD(java, offsetSet) +{ + zval **argv, **handle; + int type, argc; + jobject obj, map; + + argc = ZEND_NUM_ARGS(); + argv = (zval **) safe_emalloc(sizeof(zval *), argc, 0); + if (zend_get_parameters_array(ht, argc, argv) == FAILURE) { + php_error(E_ERROR, "Couldn't fetch arguments into array."); + RETURN_NULL(); + } + zend_hash_index_find(Z_OBJPROP_P(getThis()), 0, (void**) &handle); + obj = zend_list_find(Z_LVAL_PP(handle), &type); + map = (*JG(jenv))->CallObjectMethod(1, JG(jenv), JG(php_reflect), JG(getPhpMap), obj); + + php_java_invoke("offsetSet", map, argc, argv, return_value); + +} + +PHP_METHOD(java, offsetUnset) +{ + zval **argv, **handle; + int type, argc; + jobject obj, map; + + argc = ZEND_NUM_ARGS(); + argv = (zval **) safe_emalloc(sizeof(zval *), argc, 0); + if (zend_get_parameters_array(ht, argc, argv) == FAILURE) { + php_error(E_ERROR, "Couldn't fetch arguments into array."); + RETURN_NULL(); + } + zend_hash_index_find(Z_OBJPROP_P(getThis()), 0, (void**) &handle); + obj = zend_list_find(Z_LVAL_PP(handle), &type); + map = (*JG(jenv))->CallObjectMethod(1, JG(jenv), JG(php_reflect), JG(getPhpMap), obj); + + php_java_invoke("offsetUnset", map, argc, argv, return_value); + +} + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_offsetGet, 0) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_offsetSet, 0) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO(); static function_entry java_class_functions[] = { - PHP_ME(java, java_class, NULL, 0) - PHP_ME(java, java, NULL, 0) - PHP_ME(java, __call, NULL, 0) - PHP_ME(java, __tostring, NULL, 0) - PHP_ME(java, __get, NULL, 0) - PHP_ME(java, __set, NULL, 0) + PHP_ME(java, java_class, NULL, 0) + PHP_ME(java, java, NULL, 0) + PHP_ME(java, __call, NULL, 0) + PHP_ME(java, __tostring, NULL, 0) + PHP_ME(java, __get, NULL, 0) + PHP_ME(java, __set, NULL, 0) + PHP_ME(java, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(java, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(java, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(java, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) }; + + + +typedef struct { + zend_object_iterator intern; + jobject java_iterator; + zval *current_object; + int type; +} java_iterator; + +static void iterator_dtor(zend_object_iterator *iter TSRMLS_DC) +{ + proxyenv *jenv = JG(jenv); + java_iterator *iterator = (java_iterator *)iter; + + zval_ptr_dtor((zval**)&iterator->intern.data); + if (iterator->current_object) zval_ptr_dtor((zval**)&iterator->current_object); + + if(iterator->java_iterator) { + (*jenv)->DeleteGlobalRef(jenv, iterator->java_iterator); + iterator->java_iterator = 0; + } + + efree(iterator); +} + +static int iterator_valid(zend_object_iterator *iter TSRMLS_DC) +{ + java_iterator *iterator = (java_iterator *)iter; + return (iterator->java_iterator && iterator->current_object) ? SUCCESS : FAILURE; +} + +static void iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + java_iterator *iterator = (java_iterator *)iter; + *data = &iterator->current_object; +} + +static int iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +{ + proxyenv *jenv = JG(jenv); + java_iterator *iterator = (java_iterator *)iter; + zval *presult; + + MAKE_STD_ZVAL(presult); + + php_java_invoke("currentKey", iterator->java_iterator, 0, 0, presult); + + if(ZVAL_IS_NULL(presult)) { + zval_ptr_dtor((zval**)&presult); + return HASH_KEY_NON_EXISTANT; + } + + if(iterator->type == HASH_KEY_IS_STRING) { + *str_key_len = Z_STRLEN_P(presult); + *str_key = estrndup(Z_STRVAL_P(presult), *str_key_len); + } else { + ulong i =(unsigned long)atol((char*)Z_STRVAL_P(presult)); + *int_key = i; + } + zval_ptr_dtor((zval**)&presult); + return iterator->type; +} + +static void init_current_data(java_iterator *iterator TSRMLS_DC) +{ + MAKE_STD_ZVAL(iterator->current_object); + object_init_ex(iterator->current_object, php_java_class_entry); + iterator->current_object->is_ref=1; + iterator->current_object->refcount=1; + php_java_invoke("currentData", iterator->java_iterator, 0, 0, iterator->current_object); +} + +static void iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + java_iterator *iterator = (java_iterator *)iter; + if (iterator->current_object) { + zval_ptr_dtor((zval**)&iterator->current_object); + iterator->current_object = NULL; + } + if((*JG(jenv))->CallObjectMethod(0, JG(jenv), iterator->java_iterator, JG(moveForward))) + init_current_data(iterator TSRMLS_CC); +} + +static zend_object_iterator_funcs java_iterator_funcs = { + iterator_dtor, + iterator_valid, + iterator_current_data, + iterator_current_key, + iterator_move_forward, + NULL +}; + +static zend_object_iterator *get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC) +{ + proxyenv *jenv = JG(jenv); + java_iterator *iterator = emalloc(sizeof *iterator); + + zval **handle; + int type; + jobject java_iterator, obj; + + object->refcount++; + iterator->intern.data = (void*)object; + iterator->intern.funcs = &java_iterator_funcs; + + zend_hash_index_find(Z_OBJPROP_P(object), 0, (void**) &handle); + obj = zend_list_find(Z_LVAL_PP(handle), &type); + assert(obj); + java_iterator = (*jenv)->CallObjectMethod(1, jenv, JG(php_reflect), JG(getPhpMap), obj); + if (!java_iterator) return NULL; + + java_iterator = (*jenv)->NewGlobalRef(jenv, java_iterator); + assert(java_iterator); + iterator->java_iterator = java_iterator; + iterator->type = + (*jenv)->CallObjectMethod(0, jenv, java_iterator, JG(getType)) + ? HASH_KEY_IS_STRING + : HASH_KEY_IS_LONG; + + if((*jenv)->CallObjectMethod(0, jenv, java_iterator, JG(hasMore))) { + init_current_data(iterator TSRMLS_CC); + } + return (zend_object_iterator*)iterator; +} static void make_lambda(zend_internal_function *f, void (*handler)(INTERNAL_FUNCTION_PARAMETERS)) @@ -347,8 +613,8 @@ char *name = Z_STRVAL(function_name->element); int arg_count = ZEND_NUM_ARGS(); pval **arguments = (pval **) emalloc(sizeof(pval *)*arg_count); - short createInstance = !strcmp("java_class", name); - short constructor = !strcmp("java", name) || createInstance; + short createInstance = strcmp("java_class", name); + short constructor = !strcmp("java", name) || !createInstance; getParametersArray(ht, arg_count, arguments); @@ -407,6 +673,7 @@ PHP_MINIT_FUNCTION(java) { + zend_class_entry *parent; #ifndef ZEND_ENGINE_2 zend_class_entry ce; INIT_OVERLOADED_CLASS_ENTRY(ce, "java", NULL, @@ -414,69 +681,79 @@ get_property_handler, set_property_handler); - php_java_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + php_java_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + + INIT_CLASS_ENTRY(ce, "java_class", NULL); + parent = (zend_class_entry *) php_java_class_entry; + zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); #else - zend_class_entry ce; - zend_class_entry *parent; - zend_internal_function call, get, set; - - make_lambda(&call, ZEND_FN(java___call)); - make_lambda(&get, ZEND_FN(java___get)); - make_lambda(&set, ZEND_FN(java___set)); - - INIT_OVERLOADED_CLASS_ENTRY(ce, "java", - java_class_functions, - (zend_function*)&call, - (zend_function*)&get, - (zend_function*)&set); + zend_class_entry ce; + zend_internal_function call, get, set; + + make_lambda(&call, ZEND_FN(java___call)); + make_lambda(&get, ZEND_FN(java___get)); + make_lambda(&set, ZEND_FN(java___set)); + + INIT_OVERLOADED_CLASS_ENTRY(ce, "java", + java_class_functions, + (zend_function*)&call, + (zend_function*)&get, + (zend_function*)&set); + + ce.get_iterator = get_iterator; + + php_java_class_entry = + zend_register_internal_class(&ce TSRMLS_CC); + zend_class_implements(php_java_class_entry TSRMLS_CC, 1, zend_ce_arrayaccess); + php_java_class_entry->ce_flags=0;//??? FIXME + + INIT_OVERLOADED_CLASS_ENTRY(ce, "java_exception", + java_class_functions, + (zend_function*)&call, + (zend_function*)&get, + (zend_function*)&set); + + parent = (zend_class_entry *) zend_exception_get_default(); + php_java_exception_class_entry = + zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); + + INIT_CLASS_ENTRY(ce, "java_class", java_class_functions); + parent = (zend_class_entry *) php_java_class_entry; + +zend_class_entry *e= +zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); + e->ce_flags=0;//??? FIXME +#endif + + /* Register the resource, with destructor (arg 1) and text + description (arg 3), the other arguments are just standard + placeholders */ + le_jobject = zend_register_list_destructors_ex(php_java_destructor, NULL, "java", module_number); + + ZEND_INIT_MODULE_GLOBALS(java, php_java_alloc_globals_ctor, NULL); + + if(REGISTER_INI_ENTRIES()==SUCCESS) { + /* set the default values for all undefined */ + extern void java_init_cfg(struct cfg *cfg); - php_java_class_entry = - zend_register_internal_class(&ce TSRMLS_CC); - - INIT_OVERLOADED_CLASS_ENTRY(ce, "java_exception", - java_class_functions, - (zend_function*)&call, - (zend_function*)&get, - (zend_function*)&set); - - parent = (zend_class_entry *) zend_exception_get_default(); - php_java_exception_class_entry = - zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); - - INIT_CLASS_ENTRY(ce, "java_class", java_class_functions); - parent = (zend_class_entry *) php_java_class_entry; - zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); + java_init_cfg(&JG(cfg)); +#ifndef CFG_JAVA_SOCKET_INET + JG(cfg).saddr.sun_family = AF_LOCAL; + memset(JG(cfg).saddr.sun_path, 0, sizeof JG(cfg).saddr.sun_path); + strcpy(JG(cfg).saddr.sun_path, JG(cfg).sockname); +#else + JG(cfg).saddr.sin_family = AF_INET; + JG(cfg).saddr.sin_port=htons(atoi(JG(cfg).sockname)); + JG(cfg).saddr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); #endif - - /* Register the resource, with destructor (arg 1) and text - description (arg 3), the other arguments are just standard - placeholders */ - le_jobject = zend_register_list_destructors_ex(php_java_destructor, NULL, "java", module_number); - - ZEND_INIT_MODULE_GLOBALS(java, php_java_alloc_globals_ctor, NULL); - - if(REGISTER_INI_ENTRIES()==SUCCESS) { - /* set the default values for all undefined */ - extern void java_init_cfg(struct cfg *cfg); - - java_init_cfg(&JG(cfg)); -#ifndef CFG_JAVA_SOCKET_INET - JG(cfg).saddr.sun_family = AF_LOCAL; - memset(JG(cfg).saddr.sun_path, 0, sizeof JG(cfg).saddr.sun_path); - strcpy(JG(cfg).saddr.sun_path, JG(cfg).sockname); -#else - JG(cfg).saddr.sin_family = AF_INET; - JG(cfg).saddr.sin_port=htons(atoi(JG(cfg).sockname)); - JG(cfg).saddr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); -#endif - } - init_server(); - - assert(!java_ini_last_updated); - java_ini_last_updated=java_ini_updated; - java_ini_updated=0; - - return SUCCESS; + } + init_server(); + + assert(!java_ini_last_updated); + java_ini_last_updated=java_ini_updated; + java_ini_updated=0; + + return SUCCESS; } static char*get_server_args(struct cfg*cfg) { int i;