You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Morten Ludvigsen <mo...@yahoo.co.uk> on 2002/10/16 12:38:09 UTC

SWIG Java bindings

Is anyone actively working on SWIG-Java bindings?

If not I think I will take a crack at it :-)

Regards,

Morten Ludvigsen
2-People Software
Denmark

__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: SV: SWIG Java bindings

Posted by Greg Stein <gs...@lyra.org>.
On Thu, Oct 17, 2002 at 05:22:44PM -0700, Daniel Rall wrote:
> Greg Stein <gs...@lyra.org> writes:
> 
> > I've been on Dan's case for this for a while -- to get him to send in a
> > patch, or even better: to provide commit access so that he can work on them
> > directly within the SVN repository.
> 
> I guess commit access to the SWIG stuff would be good.  Note that I
> have the same worries about breaking that trunk that Morten
> expressed.  :)

Could each of you send a username/password to me (offlist :-), and I'll get
you added. (sorry for the delay)

Have no fear about operating within the trunk. How can you break the Java
bindings? They don't exist yet :-)

Feasably, you could break the Python ones thru a bad change to a .i file,
but please don't worry about that. I seriously doubt that will happen, but
if so... this *is* version control. We can always back a change out.

Cheers,
-g

-- 
Greg Stein, http://www.lyra.org/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: SV: SWIG Java bindings

Posted by Daniel Rall <dl...@finemaltcoding.com>.
Greg Stein <gs...@lyra.org> writes:

> I've been on Dan's case for this for a while -- to get him to send in a
> patch, or even better: to provide commit access so that he can work on them
> directly within the SVN repository.

I guess commit access to the SWIG stuff would be good.  Note that I
have the same worries about breaking that trunk that Morten
expressed.  :)
-- 

Daniel Rall <dl...@finemaltcoding.com>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: SV: SWIG Java bindings

Posted by Morten Ludvigsen <mo...@yahoo.co.uk>.
 --- Greg Stein <gs...@lyra.org> wrote: 
> I've been on Dan's case for this for a while -- to get him to send in a
> patch, or even better: to provide commit access so that he can work on them
> directly within the SVN repository.
> 
> Morten: I'd be more than happy to extend the same: if you want to work on
> the SWIG Java bindings, then we can get you commit access so you can work on
> them cooperatively with others.

[SNIP]

I think that could be a good idea. However I am not nearly confidant enough to
commit to the trunk so maybe we could have a branch for this work?

BTW. I just realised that I have not introduced myself. I will send an introduction
to the list this evening (Danish time).

Regards,

Morten Ludvigsen
2-People Software
Denmark

__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: SV: SWIG Java bindings

Posted by Greg Stein <gs...@lyra.org>.
I've been on Dan's case for this for a while -- to get him to send in a
patch, or even better: to provide commit access so that he can work on them
directly within the SVN repository.

Morten: I'd be more than happy to extend the same: if you want to work on
the SWIG Java bindings, then we can get you commit access so you can work on
them cooperatively with others.

Cheers,
-g

On Wed, Oct 16, 2002 at 06:52:20PM +0200, Morten Ludvigsen wrote:
> Thanks,
> 
> I'll start looking at it now.
> 
> Regards,
> 
> Morten Ludvigsen
> 2-People Software
> Denmark
> 
> > -----Oprindelig meddelelse-----
> > Fra: dlr@finemaltcoding.com [mailto:dlr@finemaltcoding.com]
> > Sendt: 16. oktober 2002 18:17
> > Til: Morten Ludvigsen; dev@subversion.tigris.org
> > Emne: Re: SWIG Java bindings
> >
> > Morten Ludvigsen <mo...@yahoo.co.uk> writes:
> >
> > > Is anyone actively working on SWIG-Java bindings?
> > >
> > > If not I think I will take a crack at it :-)
> >
> > Hi Morten.  I've done a small amount of work on them.  What I have is
> > swigging successfully, but may not compile (haven't tried yet) and
> > surely won't run (a lot of it is still incomplete/stubbed/broken).  I
> > hope it's a useful starting place for you, and am very interested in
> > seeing some diffs with what ever progress you find time to make.
> > Hopefully I'll have time to help out a little more as well.
> > --
> >
> > Daniel Rall <dl...@finemaltcoding.com>

-- 
Greg Stein, http://www.lyra.org/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

SV: SWIG Java bindings

Posted by Morten Ludvigsen <mo...@2ps.dk>.
Thanks,

I'll start looking at it now.

Regards,

Morten Ludvigsen
2-People Software
Denmark

> -----Oprindelig meddelelse-----
> Fra: dlr@finemaltcoding.com [mailto:dlr@finemaltcoding.com]
> Sendt: 16. oktober 2002 18:17
> Til: Morten Ludvigsen; dev@subversion.tigris.org
> Emne: Re: SWIG Java bindings
>
>
> Morten Ludvigsen <mo...@yahoo.co.uk> writes:
>
> > Is anyone actively working on SWIG-Java bindings?
> >
> > If not I think I will take a crack at it :-)
>
> Hi Morten.  I've done a small amount of work on them.  What I have is
> swigging successfully, but may not compile (haven't tried yet) and
> surely won't run (a lot of it is still incomplete/stubbed/broken).  I
> hope it's a useful starting place for you, and am very interested in
> seeing some diffs with what ever progress you find time to make.
> Hopefully I'll have time to help out a little more as well.
> --
>
> Daniel Rall <dl...@finemaltcoding.com>
>
>
>
> Index: ./svn_types.i
> ===================================================================
> --- ./svn_types.i
> +++ ./svn_types.i	Wed Oct 16 09:01:38 2002
> @@ -83,6 +83,9 @@
>      $1 = PyString_AS_STRING($input);
>      $2 = PyString_GET_SIZE($input);
>  }
> +%typemap(java, in) (const char *PTR, apr_size_t LEN) {
> +    /* FIXME: This is just a stub -- implement JNI code! */
> +}
>
>  /*
> -----------------------------------------------------------------------
>     Define a generic arginit mapping for pools.
> Index: ./svn_string.i
> ===================================================================
> --- ./svn_string.i
> +++ ./svn_string.i	Wed Oct 16 09:01:03 2002
> @@ -42,6 +42,10 @@
>      }
>      $result = t_output_helper($result, s);
>  }
> +%typemap(java,argout,fragment="t_output_helper") RET_STRING {
> +    /* FIXME: This is just a stub -- implement JNI code! */
> +    return NULL;
> +}
>
>  /*
> -----------------------------------------------------------------------
>     TYPE: svn_stringbuf_t
> @@ -137,5 +141,8 @@
>      if ($1 == NULL)
>          return NULL;
>  }
> +%typemap(java,in) const apr_array_header_t *STRINGLIST {
> +    /* FIXME: This is just a stub -- implement JNI code! */
> +}
>
>  /*
> ----------------------------------------------------------------------- */
> Index: ./svn_fs.i
> ===================================================================
> --- ./svn_fs.i
> +++ ./svn_fs.i	Fri Oct 11 19:46:41 2002
> @@ -113,4 +113,8 @@
>  #ifdef SWIGPYTHON
>  #include "swigutil_py.h"
>  #endif
> +
> +#ifdef SWIGJAVA
> +#include "swigutil_java.h"
> +#endif
>  %}
> Index: ./swigutil_java.c
> ===================================================================
> --- ./swigutil_java.c
> +++ ./swigutil_java.c	Fri Oct 11 19:24:04 2002
> @@ -0,0 +1,602 @@
> +/*
> + * swigutil_java.c: utility functions for the SWIG Java bindings
> + *
> + * ====================================================================
> + * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
> + *
> + * This software is licensed as described in the file COPYING, which
> + * you should have received as part of this distribution.  The terms
> + * are also available at http://subversion.tigris.org/license-1.html.
> + * If newer versions of this license are posted there, you may use a
> + * newer version instead, at your option.
> + *
> + * This software consists of voluntary contributions made by many
> + * individuals.  For exact contribution history, see the revision
> + * history and logs, available at http://subversion.tigris.org/.
> + * ====================================================================
> + */
> +
> +
> +#include <jni.h>
> +
> +#include <apr_pools.h>
> +#include <apr_hash.h>
> +
> +#include "svn_string.h"
> +#include "svn_delta.h"
> +
> +#include "swigutil_java.h"
> +
> +
> +/* this baton is used for the editor, directory, and file batons. */
> +typedef struct {
> +  jobject editor;     /* the editor handling the callbacks */
> +  jobject baton;      /* the dir/file baton (or NULL for edit baton) */
> +  apr_pool_t *pool;     /* pool to use for errors */
> +} item_baton;
> +
> +typedef struct {
> +  jobject handler;    /* the window handler (a callable) */
> +  apr_pool_t *pool;     /* a pool for constructing errors */
> +} handler_baton;
> +
> +
> +static jobject make_pointer(const char *typename, void *ptr)
> +{
> +  /* ### cache the swig_type_info at some point? */
> +  return SWIG_NewPointerObj(ptr, SWIG_TypeQuery(typename), 0);
> +}
> +
> +/* for use by the "O&" format specifier */
> +static jobject make_ob_pool(void *ptr)
> +{
> +  return make_pointer("apr_pool_t *", ptr);
> +}
> +
> +/* for use by the "O&" format specifier */
> +static jobject make_ob_window(void *ptr)
> +{
> +  return make_pointer("svn_txdelta_window_t *", ptr);
> +}
> +
> +static jobject convert_hash(apr_hash_t *hash,
> +                            jobject  (*converter_func)(void *value,
> +                                                       void *ctx),
> +                            void *ctx)
> +{
> +  apr_hash_index_t *hi;
> +  jclass cls = JCALL1(FindClass, jenv, "java/util/HashMap");
> +  jobject dict = JCALL3(NewObject, jenv, cls,
> +                        JCALL3(GetMethodID, jenv, cls, "<init>", "(I)V"),
> +                        (jint) apr_hash_count(hash));
> +  jmethoID put = JCALL3(GetMethodID, jenv, cls, "put",
> +                        "(Ljava/lang/Object;Ljava/lang/Object;)"
> +                        "Ljava/lang/Object;"),
> +
> +  if (dict == NULL)
> +    return NULL;
> +
> +  for (hi = apr_hash_first(NULL, hash); hi; hi = apr_hash_next(hi))
> +    {
> +      const void *key;
> +      void *val;
> +      jobject value;
> +
> +      apr_hash_this(hi, &key, NULL, &val);
> +      value = (*converter_func)(val, ctx);
> +      JCALL3(CallObjectMethod, jenv, put,
> +              JCALL2(NewString, jenv, key, strlen(key)), value);
> +      JCALL1(DeleteLocalRef, jenv, value);
> +    }
> +
> +  return dict;
> +}
> +
> +static jobject convert_to_swigtype(void *value, void *ctx)
> +{
> +  /* ctx is a 'swig_type_info *' */
> +  return SWIG_NewPointerObj(value, ctx, 0);
> +}
> +
> +static jobject convert_svn_string_t(void *value, void *ctx)
> +{
> +  JNIEnv *jenv = (JNIEnv *) ctx;
> +  const svn_string_t *s = value;
> +
> +  /* ### borrowing from value in the pool. or should we copy? note
> +     ### that copying is "safest" */
> +
> +  return JCALL2(NewString, jenv, s->data, s->len);
> +}
> +
> +
> +jobject svn_swig_java_prophash_to_dict(JNIEnv *jenv, apr_hash_t *hash)
> +{
> +  return convert_hash(hash, convert_svn_string_t, jenv);
> +}
> +
> +jobject svn_swig_java_convert_hash(JNIEnv *jenv, apr_hash_t
> *hash, swig_type_info *type)
> +{
> +  return convert_hash(hash, convert_to_swigtype, type);
> +}
> +
> +jobject svn_swig_java_c_strings_to_list(JNIEnv *jenv, char **strings)
> +{
> +  jclass cls = JCALL1(FindClass, jenv, "java/util/ArrayList");
> +  jobject list = JCALL2(NewObject, jenv, cls,
> +                        JCALL3(GetMethodID, jenv, cls, "<init>", "()V"));
> +  jmethodID add = JCALL3(GetMethodID, jenv, cls, "add",
> "(Ljava/lang/Object;)Z");
> +  char *s;
> +  jobject obj;
> +  while ((s = *strings++) != NULL)
> +    {
> +      obj = JCALL2(NewString, jenv, s, strlen(s));
> +
> +      if (obj == NULL)
> +          goto error;
> +
> +      JCALL3(CallBooleanMethod, jenv, list, add, obj);
> +
> +      JCALL1(DeleteLocalRef, jenv, obj);
> +    }
> +
> +  return list;
> +
> + error:
> +  JCALL1(DeleteLocalRef, jenv, list);
> +  return NULL;
> +}
> +
> +jobject svn_swig_java_array_to_list(JNIEnv *jenv, const
> apr_array_header_t *strings)
> +{
> +  jclass cls = JCALL1(FindClass, jenv, "java/util/ArrayList");
> +  jobject list = JCALL3(NewObject, jenv, cls,
> +                        JCALL3(GetMethodID, jenv, cls, "<init>", "(I)V"),
> +                        strings->nelts);
> +  int i;
> +  jobject obj;
> +
> +  for (i = 0; i < strings->nelts; ++i)
> +    {
> +      const char *s;
> +
> +      s = APR_ARRAY_IDX(strings, i, const char *);
> +      obj = JCALL2(NewString, jenv, s, strlen(s));
> +      if (obj == NULL)
> +        goto error;
> +      PyList_SET_ITEM(list, i, obj);
> +      JCALL1(DeleteLocaleRef, jenv, obj);
> +    }
> +
> +  return list;
> +
> + error:
> +  JCALL1(DeleteLocaleRef, jenv, list);
> +  return NULL;
> +}
> +
> +const apr_array_header_t *svn_swig_java_strings_to_array(JNIEnv *jenv,
> +                                                         jobject source,
> +
> apr_pool_t *pool)
> +{
> +  int targlen;
> +  apr_array_header_t *temp;
> +
> +  jclass cls = JCALL1(FindClass, jenv, "lang/util/List");
> +  jmethodID size = JCALL3(GetMethodID, jenv, cls, "size", "()I");
> +  jmethodID get = JCALL3(GetMethodID, jenv, cls, "get",
> +                         "(I)Ljava/lang/Object;");
> +  if (!JCALL2(IsInstanceOf, jenv, source, cls))
> +    {
> +      /* FIXME: Resport by error (perhaps by throw an Exception)
> +         PyErr_SetString(PyExc_TypeError, "not a sequence"); */
> +      return NULL;
> +    }
> +  targlen = JCALL2(CallIntegerMethod, jenv, source, size);
> +  temp = apr_array_make(pool, targlen, sizeof(const char *));
> +  while (targlen--)
> +    {
> +      jobject o = JCALL3(CallObjectMethod, jenv, source, get, targlen);
> +      if (o == NULL)
> +          return NULL;
> +      if (!PyString_Check(o))
> +        {
> +          JCALL1(DeleteLocalRef, jenv, o);
> +          /* FIXME: Resport by error (perhaps by throw an Exception)
> +             PyErr_SetString(PyExc_TypeError, "not a sequence"); */
> +          return NULL;
> +        }
> +      APR_ARRAY_IDX(temp, targlen, const char *) = PyString_AS_STRING(o);
> +      JCALL1(DeleteLocalRef, jenv, o);
> +    }
> +  return temp;
> +}
> +
> +
> +static svn_error_t * convert_java_error(JNIEnv *jenv, apr_pool_t *pool)
> +{
> +  /* ### need to fetch the Python error and map it to an svn_error_t */
> +
> +  return svn_error_create(APR_EGENERAL, 0, NULL, pool,
> +                          "the Python callback raised an exception");
> +}
> +
> +static item_baton * make_baton(JNIEnv *jenv, apr_pool_t *pool,
> +                               jobject editor, jobject baton)
> +{
> +  item_baton *newb = apr_palloc(pool, sizeof(*newb));
> +
> +  /* one more reference to the editor. */
> +  Py_INCREF(editor);
> +
> +  /* note: we take the caller's reference to 'baton' */
> +
> +  newb->editor = editor;
> +  newb->baton = baton;
> +  newb->pool = pool;
> +
> +  return newb;
> +}
> +
> +static svn_error_t * close_baton(JNIEnv *jenv, void *baton,
> const char *method)
> +{
> +  item_baton *ib = baton;
> +  jobject result;
> +
> +  /* If there is no baton object, then it is an edit_baton, and we should
> +     not bother to pass an object. Note that we still shove a NULL onto
> +     the stack, but the format specified just won't reference it.  */
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char *)method,
> +                                    ib->baton ? (char *)"O" : NULL,
> +                                    ib->baton)) == NULL)
> +    {
> +      return convert_python_error(ib->pool);
> +    }
> +
> +  /* there is no return value, so just toss this object
> (probably Py_None) */
> +  Py_DECREF(result);
> +
> +  /* We're now done with the baton. Since there isn't really a free, all
> +     we need to do is note that its objects are no longer referenced by
> +     the baton.  */
> +  Py_DECREF(ib->editor);
> +  Py_XDECREF(ib->baton);
> +
> +#ifdef SVN_DEBUG
> +  ib->editor = ib->baton = NULL;
> +#endif
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_set_target_revision(void *edit_baton,
> +                                               svn_revnum_t
> target_revision)
> +{
> +  item_baton *ib = edit_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char
> *)"set_target_revision",
> +                                    (char *)"l",
> target_revision)) == NULL)
> +    {
> +      return convert_python_error(ib->pool);
> +    }
> +
> +  /* there is no return value, so just toss this object
> (probably Py_None) */
> +  Py_DECREF(result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_open_root(void *edit_baton,
> +                                     svn_revnum_t base_revision,
> +                                     apr_pool_t *dir_pool,
> +                                     void **root_baton)
> +{
> +  item_baton *ib = edit_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char *)"open_root",
> +                                    (char *)"lO&", base_revision,
> +                                    make_ob_pool, dir_pool)) == NULL)
> +    {
> +      return convert_python_error(dir_pool);
> +    }
> +
> +  /* make_baton takes our 'result' reference */
> +  *root_baton = make_baton(dir_pool, ib->editor, result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_delete_entry(const char *path,
> +                                        svn_revnum_t revision,
> +                                        void *parent_baton,
> +                                        apr_pool_t *pool)
> +{
> +  item_baton *ib = parent_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char *)"delete_entry",
> +                                    (char *)"slOO&", path,
> revision, ib->baton,
> +                                    make_ob_pool, pool)) == NULL)
> +    {
> +      return convert_python_error(pool);
> +    }
> +
> +  /* there is no return value, so just toss this object
> (probably Py_None) */
> +  Py_DECREF(result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_add_directory(const char *path,
> +                                         void *parent_baton,
> +                                         const char *copyfrom_path,
> +                                         svn_revnum_t copyfrom_revision,
> +                                         apr_pool_t *dir_pool,
> +                                         void **child_baton)
> +{
> +  item_baton *ib = parent_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char *)"add_directory",
> +                                    (char *)"sOslO&", path, ib->baton,
> +                                    copyfrom_path, copyfrom_revision,
> +                                    make_ob_pool, dir_pool)) == NULL)
> +    {
> +      return convert_python_error(dir_pool);
> +    }
> +
> +  /* make_baton takes our 'result' reference */
> +  *child_baton = make_baton(dir_pool, ib->editor, result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_open_directory(const char *path,
> +                                          void *parent_baton,
> +                                          svn_revnum_t base_revision,
> +                                          apr_pool_t *dir_pool,
> +                                          void **child_baton)
> +{
> +  item_baton *ib = parent_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char *)"open_directory",
> +                                    (char *)"sOlO&", path, ib->baton,
> +                                    base_revision,
> +                                    make_ob_pool, dir_pool)) == NULL)
> +    {
> +      return convert_python_error(dir_pool);
> +    }
> +
> +  /* make_baton takes our 'result' reference */
> +  *child_baton = make_baton(dir_pool, ib->editor, result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_change_dir_prop(void *dir_baton,
> +                                           const char *name,
> +                                           const svn_string_t *value,
> +                                           apr_pool_t *pool)
> +{
> +  item_baton *ib = dir_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char
> *)"change_dir_prop",
> +                                    (char *)"Oss#O&", ib->baton, name,
> +                                    value->data, value->len,
> +                                    make_ob_pool, pool)) == NULL)
> +    {
> +      return convert_python_error(pool);
> +    }
> +
> +  /* there is no return value, so just toss this object
> (probably Py_None) */
> +  Py_DECREF(result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_close_directory(void *dir_baton)
> +{
> +  return close_baton(dir_baton, "close_directory");
> +}
> +
> +static svn_error_t * thunk_add_file(const char *path,
> +                                    void *parent_baton,
> +                                    const char *copyfrom_path,
> +                                    svn_revnum_t copyfrom_revision,
> +                                    apr_pool_t *file_pool,
> +                                    void **file_baton)
> +{
> +  item_baton *ib = parent_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char *)"add_file",
> +                                    (char *)"sOslO&", path, ib->baton,
> +                                    copyfrom_path, copyfrom_revision,
> +                                    make_ob_pool, file_pool)) == NULL)
> +    {
> +      return convert_python_error(file_pool);
> +    }
> +
> +  /* make_baton takes our 'result' reference */
> +  *file_baton = make_baton(file_pool, ib->editor, result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_open_file(const char *path,
> +                                     void *parent_baton,
> +                                     svn_revnum_t base_revision,
> +                                     apr_pool_t *file_pool,
> +                                     void **file_baton)
> +{
> +  item_baton *ib = parent_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char *)"open_file",
> +                                    (char *)"sOlO&", path, ib->baton,
> +                                    base_revision,
> +                                    make_ob_pool, file_pool)) == NULL)
> +    {
> +      return convert_python_error(file_pool);
> +    }
> +
> +  /* make_baton takes our 'result' reference */
> +  *file_baton = make_baton(file_pool, ib->editor, result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_window_handler(svn_txdelta_window_t *window,
> +                                          void *baton)
> +{
> +  handler_baton *hb = baton;
> +  jobject result;
> +
> +  if (window == NULL)
> +    {
> +      /* the last call; it closes the handler */
> +
> +      /* invoke the handler with None for the window */
> +      /* ### python doesn't have 'const' on the format */
> +      result = PyObject_CallFunction(hb->handler, (char *)"O", Py_None);
> +
> +      /* we no longer need to refer to the handler object */
> +      Py_DECREF(hb->handler);
> +    }
> +  else
> +    {
> +      /* invoke the handler with the window */
> +      /* ### python doesn't have 'const' on the format */
> +      result = PyObject_CallFunction(hb->handler,
> +                                     (char *)"O&",
> make_ob_window, window);
> +    }
> +
> +  if (result == NULL)
> +    return convert_python_error(hb->pool);
> +
> +  /* there is no return value, so just toss this object
> (probably Py_None) */
> +  Py_DECREF(result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_apply_textdelta(
> +    void *file_baton,
> +    svn_txdelta_window_handler_t *handler,
> +    void **h_baton)
> +{
> +  item_baton *ib = file_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char
> *)"apply_textdelta",
> +                                    (char *)"O", ib->baton)) == NULL)
> +    {
> +      return convert_python_error(ib->pool);
> +    }
> +
> +  if (result == Py_None)
> +    {
> +      Py_DECREF(result);
> +      *handler = NULL;
> +      *h_baton = NULL;
> +    }
> +  else
> +    {
> +      handler_baton *hb = apr_palloc(ib->pool, sizeof(*hb));
> +
> +      /* return the thunk for invoking the handler. the baton takes our
> +         'result' reference. */
> +      hb->handler = result;
> +      hb->pool = ib->pool;
> +
> +      *handler = thunk_window_handler;
> +      *h_baton = hb;
> +    }
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_change_file_prop(void *file_baton,
> +                                            const char *name,
> +                                            const svn_string_t *value,
> +                                            apr_pool_t *pool)
> +{
> +  item_baton *ib = file_baton;
> +  jobject result;
> +
> +  /* ### python doesn't have 'const' on the method name and format */
> +  if ((result = PyObject_CallMethod(ib->editor, (char
> *)"change_file_prop",
> +                                    (char *)"Oss#O&", ib->baton, name,
> +                                    value->data, value->len,
> +                                    make_ob_pool, pool)) == NULL)
> +    {
> +      return convert_python_error(pool);
> +    }
> +
> +  /* there is no return value, so just toss this object
> (probably Py_None) */
> +  Py_DECREF(result);
> +
> +  return SVN_NO_ERROR;
> +}
> +
> +static svn_error_t * thunk_close_file(void *file_baton)
> +{
> +  return close_baton(file_baton, "close_file");
> +}
> +
> +static svn_error_t * thunk_close_edit(void *edit_baton)
> +{
> +  return close_baton(edit_baton, "close_edit");
> +}
> +
> +static svn_error_t * thunk_abort_edit(void *edit_baton)
> +{
> +  return close_baton(edit_baton, "abort_edit");
> +}
> +
> +static const svn_delta_editor_t thunk_editor = {
> +  thunk_set_target_revision,
> +  thunk_open_root,
> +  thunk_delete_entry,
> +  thunk_add_directory,
> +  thunk_open_directory,
> +  thunk_change_dir_prop,
> +  thunk_close_directory,
> +  thunk_add_file,
> +  thunk_open_file,
> +  thunk_apply_textdelta,
> +  thunk_change_file_prop,
> +  thunk_close_file,
> +  thunk_close_edit,
> +  thunk_abort_edit
> +};
> +
> +void svn_swig_java_make_editor(JNIEnv *jenv,
> +                               const svn_delta_editor_t **editor,
> +                               void **edit_baton,
> +                               jobject java_editor,
> +                               apr_pool_t *pool)
> +{
> +  *editor = &thunk_editor;
> +  *edit_baton = make_baton(pool, java_editor, NULL);
> +}
> +
> +/* ----------------------------------------------------------------
> + * local variables:
> + * eval: (load-file "../../../tools/dev/svn-dev.el")
> + * end:
> + */
> Index: ./svn_client.i
> ===================================================================
> --- ./svn_client.i
> +++ ./svn_client.i	Wed Oct 16 09:15:22 2002
> @@ -98,6 +98,12 @@
>      }
>      $result = t_output_helper($result, list);
>  }
> +%typemap(java,argout) apr_hash_t **statushash {
> +    /* FIXME: Use JNI equiv of Java type SWIGTYPE_p_svn_wc_status_t */
> +    $result = t_output_helper(
> +        $result,
> +        svn_swig_java_convert_hash(*$1, SWIGTYPE_p_svn_wc_status_t));
> +}
>
>  /*
> -----------------------------------------------------------------------
>     handle the "statushash" OUTPUT param for svn_client_status()
> @@ -128,6 +134,10 @@
>  #ifdef SWIGPYTHON
>  #include "swigutil_py.h"
>  #endif
> +
> +#ifdef SWIGJAVA
> +#include "swigutil_java.h"
> +#endif
>  %}
>
>  %include svn_client.h
> Index: ./swigutil_java.h
> ===================================================================
> --- ./swigutil_java.h
> +++ ./swigutil_java.h	Fri Oct 11 19:24:04 2002
> @@ -0,0 +1,103 @@
> +/*
> + * swigutil_java.h :  utility functions and stuff for the SWIG
> Java bindings
> + *
> + * ====================================================================
> + * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
> + *
> + * This software is licensed as described in the file COPYING, which
> + * you should have received as part of this distribution.  The terms
> + * are also available at http://subversion.tigris.org/license-1.html.
> + * If newer versions of this license are posted there, you may use a
> + * newer version instead, at your option.
> + *
> + * This software consists of voluntary contributions made by many
> + * individuals.  For exact contribution history, see the revision
> + * history and logs, available at http://subversion.tigris.org/.
> + * ====================================================================
> + */
> +
> +
> +#ifndef SVN_SWIG_SWIGUTIL_JAVA_H
> +#define SVN_SWIG_SWIGUTIL_JAVA_H
> +
> +#include <jni.h>
> +
> +#include <apr.h>
> +#include <apr_pools.h>
> +#include <apr_strings.h>
> +#include <apr_hash.h>
> +#include <apr_tables.h>
> +
> +#include "svn_types.h"
> +#include "svn_string.h"
> +#include "svn_delta.h"
> +
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +>
> +/* If this file is being included outside of a wrapper file, then need to
> +   create stubs for some of the SWIG types. */
> +
> +/* if SWIGEXPORT is defined, then we're in a wrapper. otherwise, we need
> +   the prototypes and type definitions. */
> +#ifndef SWIGEXPORT
> +#define SVN_NEED_SWIG_TYPES
> +#endif
> +
> +#ifdef SVN_NEED_SWIG_TYPES
> +
> +typedef struct _unnamed swig_type_info;
> +jobject *SWIG_NewPointerObj(JNIEnv *jenv, void *, swig_type_info
> *, int own);
> +swig_type_info *SWIG_TypeQuery(JNIEnv *jenv, const char *name);
> +
> +#endif /* SVN_NEED_SWIG_TYPES */
> +
> +>
> +/* helper function to convert an apr_hash_t* (char* -> svnstring_t*) to
> +   a Java Map */
> +jobject svn_swig_java_prophash_to_dict(JNIEnv *jenv, apr_hash_t *hash);
> +
> +/* convert a hash of 'const char *' -> TYPE into a Java Map */
> +jobject svn_swig_java_convert_hash(JNIEnv *jenv, apr_hash_t *hash,
> +                                   swig_type_info *type);
> +
> +/* helper function to convert a 'char **' into a Java List of String
> +   objects */
> +jobject svn_swig_java_c_strings_to_list(JNIEnv *jenv, char **strings);
> +
> +/* helper function to convert an array of 'const char *' to a
> Java List of
> +   String objects */
> +jobject svn_swig_java_array_to_list(JNIEnv *jenv,
> +                                    const apr_array_header_t *strings);
> +
> +/* helper function to convert a Java List of String objects into an
> +   'apr_array_header_t *' of 'const char *' objects.  Note that the
> +   objects must remain alive -- the values are not copied. This is
> +   appropriate for incoming arguments which are defined to last the
> +   duration of the function's execution.  */
> +const apr_array_header_t *svn_swig_java_strings_to_array(JNIEnv *jenv,
> +                                                         jobject source,
> +
> apr_pool_t *pool);
> +
> +/* make a editor that "thunks" from C callbacks up to Java */
> +void svn_swig_java_make_editor(JNIEnv *jenv,
> +                               const svn_delta_editor_t **editor,
> +                               void **edit_baton,
> +                               jobject java_editor,
> +                               apr_pool_t *pool);
> +
> +#ifdef __cplusplus
> +}
> +#endif /* __cplusplus */
> +
> +#endif  /* SVN_SWIG_SWIGUTIL_JAVA_H */
> +
> +>
> +/* ----------------------------------------------------------------
> + * local variables:
> + * eval: (load-file "../../../tools/dev/svn-dev.el")
> + * end:
> + */
> Index: ./util.i
> ===================================================================
> --- ./util.i
> +++ ./util.i	Fri Oct 11 19:46:41 2002
> @@ -189,4 +189,8 @@
>  #ifdef SWIGPYTHON
>  #include "swigutil_py.h"
>  #endif
> +
> +#ifdef SWIGJAVA
> +#include "swigutil_java.h"
> +#endif
>  %}
> Index: ./svn_repos.i
> ===================================================================
> --- ./svn_repos.i
> +++ ./svn_repos.i	Fri Oct 11 19:46:41 2002
> @@ -62,4 +62,8 @@
>  #ifdef SWIGPYTHON
>  #include "swigutil_py.h"
>  #endif
> +
> +#ifdef SWIGJAVA
> +#include "swigutil_java.h"
> +#endif
>  %}
> Index: ./svn_delta.i
> ===================================================================
> --- ./svn_delta.i
> +++ ./svn_delta.i	Fri Oct 11 19:46:41 2002
> @@ -82,4 +82,8 @@
>  #ifdef SWIGPYTHON
>  #include "swigutil_py.h"
>  #endif
> +
> +#ifdef SWIGJAVA
> +#include "swigutil_java.h"
> +#endif
>  %}
> Index: ./apr.i
> ===================================================================
> --- ./apr.i
> +++ ./apr.i	Wed Oct 16 08:15:40 2002
> @@ -62,6 +62,12 @@
>  %typemap(python,argout,fragment="t_output_helper") apr_time_t * {
>      $result = t_output_helper($result, PyLong_FromLongLong(*$1));
>  }
> +%typemap(java,argout) apr_time_t * {
> +    jclass cls = JCALL1(FindClass, jenv, "java/lang/Long");
> +    jmethodID ctor = JCALL3(GetMethodID, jenv, cls, "<init>", "(J)V");
> +    jobject l = JCALL3(NewObject, jenv, cls, ctor, (jlong) *$1);
> +    $result = t_output_helper($result, JCALL1(NewGlobalRef, jenv, l));
> +}
>
>  /*
> -----------------------------------------------------------------------
>     create some INOUT typemaps for apr_size_t
> @@ -73,6 +79,12 @@
>      temp = (apr_size_t) PyInt_AsLong($input);
>      $1 = &temp;
>  }
> +%typemap(java,in) apr_size_t *INOUT (apr_size_t temp) {
> +    jclass cls = JCALL1(FindClass, jenv, "java/lang/Long");
> +    jmethodID mid = JCALL3(GetStaticMethodID, jenv, cls,
> "longValue", "()J");
> +    temp = (apr_size_t) JCALL2(CallStaticLongMethod, jenv, mid, $input);
> +    $1 = &temp;
> +}
>
>  /*
> -----------------------------------------------------------------------
>     create an OUTPUT argument typemap for an apr_hash_t **
> @@ -93,6 +105,12 @@
>      Py_DECREF($result);
>      $result = svn_swig_py_prophash_to_dict(*$1);
>  }
> +%typemap(java,argout) apr_hash_t **PROPHASH {
> +    /* toss prior result, get new result from the hash */
> +    JCALL1(DeleteGlobalRef, jenv, $result);
> +    $result = JCALL1(NewGlobalRef, jenv,
> +                     svn_swig_java_prophash_to_dict(jenv, *$1));
> +}
>
>  /*
> -----------------------------------------------------------------------
>     apr_file_t ** is always an OUT param
> @@ -105,6 +123,13 @@
>      $result = t_output_helper(
>          $result,
>          SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
> +}
> +%typemap(java,argout) apr_file_t ** {
> +    /* HELP: Is there a JNI equivalent of SWIG_NewPointerObj, or is
> +       this actually a cross-language typemap? */
> +    $result = t_output_helper(
> +        $result,
> +        SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
>  }
>
>  /*
> ----------------------------------------------------------------------- */
> Index: ./Makefile
> ===================================================================
> --- ./Makefile
> +++ ./Makefile	Wed Oct 16 09:14:06 2002
> @@ -0,0 +1,15 @@
> +# TODO: Use -swiglig argument to avoid the need for SWIG-internal paths.
> +SWIG_CMD=/usr/local/swig/bin/swig -c -java -noproxy -module
> 'svn_jni' -I'.' -I'../../include'
> -I'/home/dlr/src/apache.org/apr/include'
> -I'/usr/local/swig/lib/swig1.3' -I'/usr/local/swig/lib/swig1.3/java'
> +
> +build-java: swig-java
> +
> +swig-java:
> +	for source in *.i; do \
> +	  target="`echo -n $$source | perl -pe 's/..$$/.jni.c/'`"; \
> +	  $(SWIG_CMD) -o $$target $$source; \
> +	done; unset target source
> +
> +clean: swig-java-clean
> +
> +swig-java-clean:
> +	rm -f *.jni.c *.java
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
> For additional commands, e-mail: dev-help@subversion.tigris.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: SWIG Java bindings

Posted by Daniel Rall <dl...@finemaltcoding.com>.
Morten Ludvigsen <mo...@yahoo.co.uk> writes:

> Is anyone actively working on SWIG-Java bindings?
> 
> If not I think I will take a crack at it :-)

Hi Morten.  I've done a small amount of work on them.  What I have is
swigging successfully, but may not compile (haven't tried yet) and
surely won't run (a lot of it is still incomplete/stubbed/broken).  I
hope it's a useful starting place for you, and am very interested in
seeing some diffs with what ever progress you find time to make.
Hopefully I'll have time to help out a little more as well.
-- 

Daniel Rall <dl...@finemaltcoding.com>



Index: ./svn_types.i
===================================================================
--- ./svn_types.i
+++ ./svn_types.i	Wed Oct 16 09:01:38 2002
@@ -83,6 +83,9 @@
     $1 = PyString_AS_STRING($input);
     $2 = PyString_GET_SIZE($input);
 }
+%typemap(java, in) (const char *PTR, apr_size_t LEN) {
+    /* FIXME: This is just a stub -- implement JNI code! */
+}
 
 /* -----------------------------------------------------------------------
    Define a generic arginit mapping for pools.
Index: ./svn_string.i
===================================================================
--- ./svn_string.i
+++ ./svn_string.i	Wed Oct 16 09:01:03 2002
@@ -42,6 +42,10 @@
     }
     $result = t_output_helper($result, s);
 }
+%typemap(java,argout,fragment="t_output_helper") RET_STRING {
+    /* FIXME: This is just a stub -- implement JNI code! */
+    return NULL;
+}
 
 /* -----------------------------------------------------------------------
    TYPE: svn_stringbuf_t
@@ -137,5 +141,8 @@
     if ($1 == NULL)
         return NULL;
 }
+%typemap(java,in) const apr_array_header_t *STRINGLIST {
+    /* FIXME: This is just a stub -- implement JNI code! */
+}
 
 /* ----------------------------------------------------------------------- */
Index: ./svn_fs.i
===================================================================
--- ./svn_fs.i
+++ ./svn_fs.i	Fri Oct 11 19:46:41 2002
@@ -113,4 +113,8 @@
 #ifdef SWIGPYTHON
 #include "swigutil_py.h"
 #endif
+
+#ifdef SWIGJAVA
+#include "swigutil_java.h"
+#endif
 %}
Index: ./swigutil_java.c
===================================================================
--- ./swigutil_java.c
+++ ./swigutil_java.c	Fri Oct 11 19:24:04 2002
@@ -0,0 +1,602 @@
+/*
+ * swigutil_java.c: utility functions for the SWIG Java bindings
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+#include <jni.h>
+
+#include <apr_pools.h>
+#include <apr_hash.h>
+
+#include "svn_string.h"
+#include "svn_delta.h"
+
+#include "swigutil_java.h"
+
+
+/* this baton is used for the editor, directory, and file batons. */
+typedef struct {
+  jobject editor;     /* the editor handling the callbacks */
+  jobject baton;      /* the dir/file baton (or NULL for edit baton) */
+  apr_pool_t *pool;     /* pool to use for errors */
+} item_baton;
+
+typedef struct {
+  jobject handler;    /* the window handler (a callable) */
+  apr_pool_t *pool;     /* a pool for constructing errors */
+} handler_baton;
+
+
+static jobject make_pointer(const char *typename, void *ptr)
+{
+  /* ### cache the swig_type_info at some point? */
+  return SWIG_NewPointerObj(ptr, SWIG_TypeQuery(typename), 0);
+}
+
+/* for use by the "O&" format specifier */
+static jobject make_ob_pool(void *ptr)
+{
+  return make_pointer("apr_pool_t *", ptr);
+}
+
+/* for use by the "O&" format specifier */
+static jobject make_ob_window(void *ptr)
+{
+  return make_pointer("svn_txdelta_window_t *", ptr);
+}
+
+static jobject convert_hash(apr_hash_t *hash,
+                            jobject  (*converter_func)(void *value,
+                                                       void *ctx),
+                            void *ctx)
+{
+  apr_hash_index_t *hi;
+  jclass cls = JCALL1(FindClass, jenv, "java/util/HashMap");
+  jobject dict = JCALL3(NewObject, jenv, cls,
+                        JCALL3(GetMethodID, jenv, cls, "<init>", "(I)V"),
+                        (jint) apr_hash_count(hash));
+  jmethoID put = JCALL3(GetMethodID, jenv, cls, "put",
+                        "(Ljava/lang/Object;Ljava/lang/Object;)"
+                        "Ljava/lang/Object;"),
+
+  if (dict == NULL)
+    return NULL;
+
+  for (hi = apr_hash_first(NULL, hash); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      jobject value;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      value = (*converter_func)(val, ctx);
+      JCALL3(CallObjectMethod, jenv, put,
+              JCALL2(NewString, jenv, key, strlen(key)), value);
+      JCALL1(DeleteLocalRef, jenv, value);
+    }
+
+  return dict;
+}
+
+static jobject convert_to_swigtype(void *value, void *ctx)
+{
+  /* ctx is a 'swig_type_info *' */
+  return SWIG_NewPointerObj(value, ctx, 0);
+}
+
+static jobject convert_svn_string_t(void *value, void *ctx)
+{
+  JNIEnv *jenv = (JNIEnv *) ctx;
+  const svn_string_t *s = value;
+
+  /* ### borrowing from value in the pool. or should we copy? note
+     ### that copying is "safest" */
+
+  return JCALL2(NewString, jenv, s->data, s->len);
+}
+
+
+jobject svn_swig_java_prophash_to_dict(JNIEnv *jenv, apr_hash_t *hash)
+{
+  return convert_hash(hash, convert_svn_string_t, jenv);
+}
+
+jobject svn_swig_java_convert_hash(JNIEnv *jenv, apr_hash_t *hash, swig_type_info *type)
+{
+  return convert_hash(hash, convert_to_swigtype, type);
+}
+
+jobject svn_swig_java_c_strings_to_list(JNIEnv *jenv, char **strings)
+{
+  jclass cls = JCALL1(FindClass, jenv, "java/util/ArrayList");
+  jobject list = JCALL2(NewObject, jenv, cls,
+                        JCALL3(GetMethodID, jenv, cls, "<init>", "()V"));
+  jmethodID add = JCALL3(GetMethodID, jenv, cls, "add", "(Ljava/lang/Object;)Z");
+  char *s;
+  jobject obj;
+  while ((s = *strings++) != NULL)
+    {
+      obj = JCALL2(NewString, jenv, s, strlen(s));
+
+      if (obj == NULL)
+          goto error;
+
+      JCALL3(CallBooleanMethod, jenv, list, add, obj);
+
+      JCALL1(DeleteLocalRef, jenv, obj);
+    }
+
+  return list;
+
+ error:
+  JCALL1(DeleteLocalRef, jenv, list);
+  return NULL;
+}
+
+jobject svn_swig_java_array_to_list(JNIEnv *jenv, const apr_array_header_t *strings)
+{
+  jclass cls = JCALL1(FindClass, jenv, "java/util/ArrayList");
+  jobject list = JCALL3(NewObject, jenv, cls,
+                        JCALL3(GetMethodID, jenv, cls, "<init>", "(I)V"),
+                        strings->nelts);
+  int i;
+  jobject obj;
+
+  for (i = 0; i < strings->nelts; ++i)
+    {
+      const char *s;
+
+      s = APR_ARRAY_IDX(strings, i, const char *);
+      obj = JCALL2(NewString, jenv, s, strlen(s));
+      if (obj == NULL)
+        goto error;
+      PyList_SET_ITEM(list, i, obj);
+      JCALL1(DeleteLocaleRef, jenv, obj);
+    }
+
+  return list;
+
+ error:
+  JCALL1(DeleteLocaleRef, jenv, list);
+  return NULL;
+}
+
+const apr_array_header_t *svn_swig_java_strings_to_array(JNIEnv *jenv,
+                                                         jobject source,
+                                                         apr_pool_t *pool)
+{
+  int targlen;
+  apr_array_header_t *temp;
+
+  jclass cls = JCALL1(FindClass, jenv, "lang/util/List");
+  jmethodID size = JCALL3(GetMethodID, jenv, cls, "size", "()I");
+  jmethodID get = JCALL3(GetMethodID, jenv, cls, "get",
+                         "(I)Ljava/lang/Object;");
+  if (!JCALL2(IsInstanceOf, jenv, source, cls))
+    {
+      /* FIXME: Resport by error (perhaps by throw an Exception)
+         PyErr_SetString(PyExc_TypeError, "not a sequence"); */
+      return NULL;
+    }
+  targlen = JCALL2(CallIntegerMethod, jenv, source, size);
+  temp = apr_array_make(pool, targlen, sizeof(const char *));
+  while (targlen--)
+    {
+      jobject o = JCALL3(CallObjectMethod, jenv, source, get, targlen);
+      if (o == NULL)
+          return NULL;
+      if (!PyString_Check(o))
+        {
+          JCALL1(DeleteLocalRef, jenv, o);
+          /* FIXME: Resport by error (perhaps by throw an Exception)
+             PyErr_SetString(PyExc_TypeError, "not a sequence"); */
+          return NULL;
+        }
+      APR_ARRAY_IDX(temp, targlen, const char *) = PyString_AS_STRING(o);
+      JCALL1(DeleteLocalRef, jenv, o);
+    }
+  return temp;
+}
+
+
+static svn_error_t * convert_java_error(JNIEnv *jenv, apr_pool_t *pool)
+{
+  /* ### need to fetch the Python error and map it to an svn_error_t */
+
+  return svn_error_create(APR_EGENERAL, 0, NULL, pool,
+                          "the Python callback raised an exception");
+}
+
+static item_baton * make_baton(JNIEnv *jenv, apr_pool_t *pool,
+                               jobject editor, jobject baton)
+{
+  item_baton *newb = apr_palloc(pool, sizeof(*newb));
+
+  /* one more reference to the editor. */
+  Py_INCREF(editor);
+
+  /* note: we take the caller's reference to 'baton' */
+
+  newb->editor = editor;
+  newb->baton = baton;
+  newb->pool = pool;
+
+  return newb;
+}
+
+static svn_error_t * close_baton(JNIEnv *jenv, void *baton, const char *method)
+{
+  item_baton *ib = baton;
+  jobject result;
+
+  /* If there is no baton object, then it is an edit_baton, and we should
+     not bother to pass an object. Note that we still shove a NULL onto
+     the stack, but the format specified just won't reference it.  */
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)method,
+                                    ib->baton ? (char *)"O" : NULL,
+                                    ib->baton)) == NULL)
+    {
+      return convert_python_error(ib->pool);
+    }
+
+  /* there is no return value, so just toss this object (probably Py_None) */
+  Py_DECREF(result);
+
+  /* We're now done with the baton. Since there isn't really a free, all
+     we need to do is note that its objects are no longer referenced by
+     the baton.  */
+  Py_DECREF(ib->editor);
+  Py_XDECREF(ib->baton);
+
+#ifdef SVN_DEBUG
+  ib->editor = ib->baton = NULL;
+#endif
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_set_target_revision(void *edit_baton,
+                                               svn_revnum_t target_revision)
+{
+  item_baton *ib = edit_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"set_target_revision",
+                                    (char *)"l", target_revision)) == NULL)
+    {
+      return convert_python_error(ib->pool);
+    }
+
+  /* there is no return value, so just toss this object (probably Py_None) */
+  Py_DECREF(result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_open_root(void *edit_baton,
+                                     svn_revnum_t base_revision,
+                                     apr_pool_t *dir_pool,
+                                     void **root_baton)
+{
+  item_baton *ib = edit_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"open_root",
+                                    (char *)"lO&", base_revision,
+                                    make_ob_pool, dir_pool)) == NULL)
+    {
+      return convert_python_error(dir_pool);
+    }
+
+  /* make_baton takes our 'result' reference */
+  *root_baton = make_baton(dir_pool, ib->editor, result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_delete_entry(const char *path,
+                                        svn_revnum_t revision,
+                                        void *parent_baton,
+                                        apr_pool_t *pool)
+{
+  item_baton *ib = parent_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"delete_entry",
+                                    (char *)"slOO&", path, revision, ib->baton,
+                                    make_ob_pool, pool)) == NULL)
+    {
+      return convert_python_error(pool);
+    }
+
+  /* there is no return value, so just toss this object (probably Py_None) */
+  Py_DECREF(result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_add_directory(const char *path,
+                                         void *parent_baton,
+                                         const char *copyfrom_path,
+                                         svn_revnum_t copyfrom_revision,
+                                         apr_pool_t *dir_pool,
+                                         void **child_baton)
+{
+  item_baton *ib = parent_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"add_directory",
+                                    (char *)"sOslO&", path, ib->baton,
+                                    copyfrom_path, copyfrom_revision,
+                                    make_ob_pool, dir_pool)) == NULL)
+    {
+      return convert_python_error(dir_pool);
+    }
+
+  /* make_baton takes our 'result' reference */
+  *child_baton = make_baton(dir_pool, ib->editor, result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_open_directory(const char *path,
+                                          void *parent_baton,
+                                          svn_revnum_t base_revision,
+                                          apr_pool_t *dir_pool,
+                                          void **child_baton)
+{
+  item_baton *ib = parent_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"open_directory",
+                                    (char *)"sOlO&", path, ib->baton,
+                                    base_revision,
+                                    make_ob_pool, dir_pool)) == NULL)
+    {
+      return convert_python_error(dir_pool);
+    }
+
+  /* make_baton takes our 'result' reference */
+  *child_baton = make_baton(dir_pool, ib->editor, result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_change_dir_prop(void *dir_baton,
+                                           const char *name,
+                                           const svn_string_t *value,
+                                           apr_pool_t *pool)
+{
+  item_baton *ib = dir_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"change_dir_prop",
+                                    (char *)"Oss#O&", ib->baton, name,
+                                    value->data, value->len,
+                                    make_ob_pool, pool)) == NULL)
+    {
+      return convert_python_error(pool);
+    }
+
+  /* there is no return value, so just toss this object (probably Py_None) */
+  Py_DECREF(result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_close_directory(void *dir_baton)
+{
+  return close_baton(dir_baton, "close_directory");
+}
+
+static svn_error_t * thunk_add_file(const char *path,
+                                    void *parent_baton,
+                                    const char *copyfrom_path,
+                                    svn_revnum_t copyfrom_revision,
+                                    apr_pool_t *file_pool,
+                                    void **file_baton)
+{
+  item_baton *ib = parent_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"add_file",
+                                    (char *)"sOslO&", path, ib->baton,
+                                    copyfrom_path, copyfrom_revision,
+                                    make_ob_pool, file_pool)) == NULL)
+    {
+      return convert_python_error(file_pool);
+    }
+
+  /* make_baton takes our 'result' reference */
+  *file_baton = make_baton(file_pool, ib->editor, result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_open_file(const char *path,
+                                     void *parent_baton,
+                                     svn_revnum_t base_revision,
+                                     apr_pool_t *file_pool,
+                                     void **file_baton)
+{
+  item_baton *ib = parent_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"open_file",
+                                    (char *)"sOlO&", path, ib->baton,
+                                    base_revision,
+                                    make_ob_pool, file_pool)) == NULL)
+    {
+      return convert_python_error(file_pool);
+    }
+
+  /* make_baton takes our 'result' reference */
+  *file_baton = make_baton(file_pool, ib->editor, result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_window_handler(svn_txdelta_window_t *window,
+                                          void *baton)
+{
+  handler_baton *hb = baton;
+  jobject result;
+
+  if (window == NULL)
+    {
+      /* the last call; it closes the handler */
+
+      /* invoke the handler with None for the window */
+      /* ### python doesn't have 'const' on the format */
+      result = PyObject_CallFunction(hb->handler, (char *)"O", Py_None);
+
+      /* we no longer need to refer to the handler object */
+      Py_DECREF(hb->handler);
+    }
+  else
+    {
+      /* invoke the handler with the window */
+      /* ### python doesn't have 'const' on the format */
+      result = PyObject_CallFunction(hb->handler,
+                                     (char *)"O&", make_ob_window, window);
+    }
+
+  if (result == NULL)
+    return convert_python_error(hb->pool);
+
+  /* there is no return value, so just toss this object (probably Py_None) */
+  Py_DECREF(result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_apply_textdelta(
+    void *file_baton, 
+    svn_txdelta_window_handler_t *handler,
+    void **h_baton)
+{
+  item_baton *ib = file_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"apply_textdelta",
+                                    (char *)"O", ib->baton)) == NULL)
+    {
+      return convert_python_error(ib->pool);
+    }
+
+  if (result == Py_None)
+    {
+      Py_DECREF(result);
+      *handler = NULL;
+      *h_baton = NULL;
+    }
+  else
+    {
+      handler_baton *hb = apr_palloc(ib->pool, sizeof(*hb));
+
+      /* return the thunk for invoking the handler. the baton takes our
+         'result' reference. */
+      hb->handler = result;
+      hb->pool = ib->pool;
+
+      *handler = thunk_window_handler;
+      *h_baton = hb;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_change_file_prop(void *file_baton,
+                                            const char *name,
+                                            const svn_string_t *value,
+                                            apr_pool_t *pool)
+{
+  item_baton *ib = file_baton;
+  jobject result;
+
+  /* ### python doesn't have 'const' on the method name and format */
+  if ((result = PyObject_CallMethod(ib->editor, (char *)"change_file_prop",
+                                    (char *)"Oss#O&", ib->baton, name,
+                                    value->data, value->len,
+                                    make_ob_pool, pool)) == NULL)
+    {
+      return convert_python_error(pool);
+    }
+
+  /* there is no return value, so just toss this object (probably Py_None) */
+  Py_DECREF(result);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t * thunk_close_file(void *file_baton)
+{
+  return close_baton(file_baton, "close_file");
+}
+
+static svn_error_t * thunk_close_edit(void *edit_baton)
+{
+  return close_baton(edit_baton, "close_edit");
+}
+
+static svn_error_t * thunk_abort_edit(void *edit_baton)
+{
+  return close_baton(edit_baton, "abort_edit");
+}
+
+static const svn_delta_editor_t thunk_editor = {
+  thunk_set_target_revision,
+  thunk_open_root,
+  thunk_delete_entry,
+  thunk_add_directory,
+  thunk_open_directory,
+  thunk_change_dir_prop,
+  thunk_close_directory,
+  thunk_add_file,
+  thunk_open_file,
+  thunk_apply_textdelta,
+  thunk_change_file_prop,
+  thunk_close_file,
+  thunk_close_edit,
+  thunk_abort_edit
+};
+
+void svn_swig_java_make_editor(JNIEnv *jenv,
+                               const svn_delta_editor_t **editor,
+                               void **edit_baton,
+                               jobject java_editor,
+                               apr_pool_t *pool)
+{
+  *editor = &thunk_editor;
+  *edit_baton = make_baton(pool, java_editor, NULL);
+}
+
+/* ----------------------------------------------------------------
+ * local variables:
+ * eval: (load-file "../../../tools/dev/svn-dev.el")
+ * end:
+ */
Index: ./svn_client.i
===================================================================
--- ./svn_client.i
+++ ./svn_client.i	Wed Oct 16 09:15:22 2002
@@ -98,6 +98,12 @@
     }
     $result = t_output_helper($result, list);
 }
+%typemap(java,argout) apr_hash_t **statushash {
+    /* FIXME: Use JNI equiv of Java type SWIGTYPE_p_svn_wc_status_t */
+    $result = t_output_helper(
+        $result,
+        svn_swig_java_convert_hash(*$1, SWIGTYPE_p_svn_wc_status_t));
+}
 
 /* -----------------------------------------------------------------------
    handle the "statushash" OUTPUT param for svn_client_status()
@@ -128,6 +134,10 @@
 #ifdef SWIGPYTHON
 #include "swigutil_py.h"
 #endif
+
+#ifdef SWIGJAVA
+#include "swigutil_java.h"
+#endif
 %}
 
 %include svn_client.h
Index: ./swigutil_java.h
===================================================================
--- ./swigutil_java.h
+++ ./swigutil_java.h	Fri Oct 11 19:24:04 2002
@@ -0,0 +1,103 @@
+/*
+ * swigutil_java.h :  utility functions and stuff for the SWIG Java bindings
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+#ifndef SVN_SWIG_SWIGUTIL_JAVA_H
+#define SVN_SWIG_SWIGUTIL_JAVA_H
+
+#include <jni.h>
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+#include <apr_hash.h>
+#include <apr_tables.h>
+
+#include "svn_types.h"
+#include "svn_string.h"
+#include "svn_delta.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* If this file is being included outside of a wrapper file, then need to
+   create stubs for some of the SWIG types. */
+
+/* if SWIGEXPORT is defined, then we're in a wrapper. otherwise, we need
+   the prototypes and type definitions. */
+#ifndef SWIGEXPORT
+#define SVN_NEED_SWIG_TYPES
+#endif
+
+#ifdef SVN_NEED_SWIG_TYPES
+
+typedef struct _unnamed swig_type_info;
+jobject *SWIG_NewPointerObj(JNIEnv *jenv, void *, swig_type_info *, int own);
+swig_type_info *SWIG_TypeQuery(JNIEnv *jenv, const char *name);
+
+#endif /* SVN_NEED_SWIG_TYPES */
+
+
+/* helper function to convert an apr_hash_t* (char* -> svnstring_t*) to
+   a Java Map */
+jobject svn_swig_java_prophash_to_dict(JNIEnv *jenv, apr_hash_t *hash);
+
+/* convert a hash of 'const char *' -> TYPE into a Java Map */
+jobject svn_swig_java_convert_hash(JNIEnv *jenv, apr_hash_t *hash,
+                                   swig_type_info *type);
+
+/* helper function to convert a 'char **' into a Java List of String
+   objects */
+jobject svn_swig_java_c_strings_to_list(JNIEnv *jenv, char **strings);
+
+/* helper function to convert an array of 'const char *' to a Java List of
+   String objects */
+jobject svn_swig_java_array_to_list(JNIEnv *jenv,
+                                    const apr_array_header_t *strings);
+
+/* helper function to convert a Java List of String objects into an
+   'apr_array_header_t *' of 'const char *' objects.  Note that the
+   objects must remain alive -- the values are not copied. This is
+   appropriate for incoming arguments which are defined to last the
+   duration of the function's execution.  */
+const apr_array_header_t *svn_swig_java_strings_to_array(JNIEnv *jenv,
+                                                         jobject source,
+                                                         apr_pool_t *pool);
+
+/* make a editor that "thunks" from C callbacks up to Java */
+void svn_swig_java_make_editor(JNIEnv *jenv,
+                               const svn_delta_editor_t **editor,
+                               void **edit_baton,
+                               jobject java_editor,
+                               apr_pool_t *pool);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* SVN_SWIG_SWIGUTIL_JAVA_H */
+
+
+/* ----------------------------------------------------------------
+ * local variables:
+ * eval: (load-file "../../../tools/dev/svn-dev.el")
+ * end:
+ */
Index: ./util.i
===================================================================
--- ./util.i
+++ ./util.i	Fri Oct 11 19:46:41 2002
@@ -189,4 +189,8 @@
 #ifdef SWIGPYTHON
 #include "swigutil_py.h"
 #endif
+
+#ifdef SWIGJAVA
+#include "swigutil_java.h"
+#endif
 %}
Index: ./svn_repos.i
===================================================================
--- ./svn_repos.i
+++ ./svn_repos.i	Fri Oct 11 19:46:41 2002
@@ -62,4 +62,8 @@
 #ifdef SWIGPYTHON
 #include "swigutil_py.h"
 #endif
+
+#ifdef SWIGJAVA
+#include "swigutil_java.h"
+#endif
 %}
Index: ./svn_delta.i
===================================================================
--- ./svn_delta.i
+++ ./svn_delta.i	Fri Oct 11 19:46:41 2002
@@ -82,4 +82,8 @@
 #ifdef SWIGPYTHON
 #include "swigutil_py.h"
 #endif
+
+#ifdef SWIGJAVA
+#include "swigutil_java.h"
+#endif
 %}
Index: ./apr.i
===================================================================
--- ./apr.i
+++ ./apr.i	Wed Oct 16 08:15:40 2002
@@ -62,6 +62,12 @@
 %typemap(python,argout,fragment="t_output_helper") apr_time_t * {
     $result = t_output_helper($result, PyLong_FromLongLong(*$1));
 }
+%typemap(java,argout) apr_time_t * {
+    jclass cls = JCALL1(FindClass, jenv, "java/lang/Long");
+    jmethodID ctor = JCALL3(GetMethodID, jenv, cls, "<init>", "(J)V");
+    jobject l = JCALL3(NewObject, jenv, cls, ctor, (jlong) *$1);
+    $result = t_output_helper($result, JCALL1(NewGlobalRef, jenv, l));
+}
 
 /* -----------------------------------------------------------------------
    create some INOUT typemaps for apr_size_t
@@ -73,6 +79,12 @@
     temp = (apr_size_t) PyInt_AsLong($input);
     $1 = &temp;
 }
+%typemap(java,in) apr_size_t *INOUT (apr_size_t temp) {
+    jclass cls = JCALL1(FindClass, jenv, "java/lang/Long");
+    jmethodID mid = JCALL3(GetStaticMethodID, jenv, cls, "longValue", "()J");
+    temp = (apr_size_t) JCALL2(CallStaticLongMethod, jenv, mid, $input);
+    $1 = &temp;
+}
 
 /* -----------------------------------------------------------------------
    create an OUTPUT argument typemap for an apr_hash_t **
@@ -93,6 +105,12 @@
     Py_DECREF($result);
     $result = svn_swig_py_prophash_to_dict(*$1);
 }
+%typemap(java,argout) apr_hash_t **PROPHASH {
+    /* toss prior result, get new result from the hash */
+    JCALL1(DeleteGlobalRef, jenv, $result);
+    $result = JCALL1(NewGlobalRef, jenv,
+                     svn_swig_java_prophash_to_dict(jenv, *$1));
+}
 
 /* -----------------------------------------------------------------------
    apr_file_t ** is always an OUT param
@@ -105,6 +123,13 @@
     $result = t_output_helper(
         $result,
         SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
+}
+%typemap(java,argout) apr_file_t ** {
+    /* HELP: Is there a JNI equivalent of SWIG_NewPointerObj, or is
+       this actually a cross-language typemap? */
+    $result = t_output_helper(
+        $result,
+        SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
 }
 
 /* ----------------------------------------------------------------------- */
Index: ./Makefile
===================================================================
--- ./Makefile
+++ ./Makefile	Wed Oct 16 09:14:06 2002
@@ -0,0 +1,15 @@
+# TODO: Use -swiglig argument to avoid the need for SWIG-internal paths.
+SWIG_CMD=/usr/local/swig/bin/swig -c -java -noproxy -module 'svn_jni' -I'.' -I'../../include' -I'/home/dlr/src/apache.org/apr/include' -I'/usr/local/swig/lib/swig1.3' -I'/usr/local/swig/lib/swig1.3/java'
+
+build-java: swig-java
+
+swig-java:
+	for source in *.i; do \
+	  target="`echo -n $$source | perl -pe 's/..$$/.jni.c/'`"; \
+	  $(SWIG_CMD) -o $$target $$source; \
+	done; unset target source
+
+clean: swig-java-clean
+
+swig-java-clean:
+	rm -f *.jni.c *.java

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: SWIG Java bindings

Posted by cm...@collab.net.
Morten Ludvigsen <mo...@yahoo.co.uk> writes:

> Is anyone actively working on SWIG-Java bindings?

I don't think anyone has *ever* worked on our SWIG/Java bindings.

> If not I think I will take a crack at it :-)

Sweet!  We'll look forward to you patches.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org