--- 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;