Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

Java Peer Framework


Classes

class  xmog_peer
 A utility class that provides access to the Java interface com.codemesh.peer.PeerType. More...
class  xmog_peer_value
 The wrapper class for the builtin Java com.codemesh.peer.Value type. More...
class  xmog_serializable
 A utility class that provides easy access to the Java type com.codemesh.peer.SerializablePeer. More...
class  com::codemesh::peer::AbstractPeerType
 A Java class that acts as a baseclass for concrete peer type implementations. More...
class  com::codemesh::peer::PeerException
 The exception type that is thrown when something goes wrong during peer operations. More...
interface  com::codemesh::peer::PeerType
 A Java interface that may be implemented by concrete Java peer types. More...
class  com::codemesh::peer::SerializablePeer
 A Java type implementing java.io.Serializable and offering convenient methods for reading and writing native fields from and to an instance of this type. More...
class  com::codemesh::peer::Value
 A generic value object that is used to polymorphically represent the different Java types. More...

Typedefs

typedef void *(XMOG_CALLING_CONVENTION * XMOG_PEER_UNMARSHAL_METHOD )(xmog_base &peer, xmog_java_class *peerClass, const char *cppType, xmog_localenv *env)
 The peer unmarshalling callback.
typedef jint(JNICALL * XMOG_CALLBACK_METHOD )(xmog_base &peer, jlong pInst, xmog_peer_value &retexc, xmog_java_array_template< xmog_peer_value > &args, xmog_localenv *env)
 The callback function type.

Functions

virtual xmog_java_classxmog_base::xmog_get_java_peer (xmog_localenv *env=NULL)
 Returns NULL if the type does not have a Java peer type, a pointer to the type's xmog_java_class otherwise.
virtual int xmog_base::xmog_create_java_peer (xmog_java_class *clazz, xmog_localenv *env=NULL, xmog_flags flags=xmog_base::GLOBAL)
 Creates a Java peer instance for this type.
virtual int xmog_base::xmog_to_java_peer (xmog_localenv *env=NULL)
 Sets the native instance's state into the Java peer instance.

Detailed Description

Introduction

Java peers are an advanced feature that was introduced with version 3.0 of Codemesh's Java/C++ integration product. Under most circumstances, a C++ developer will only use the generated C++ proxy classes. Under some circumstances though, it might be necessary or desirable for a C++ developer to extend the generated proxy types on the native side.

For example, you might have generated a proxy type for the java.io.Serializable interface and you wish to create C++ implementations of that interface. Of course you would expect that the data that these C++ types contain will get serialized when you pass an instance of your custom C++ type to a Java output stream.

This is of course not what's going to happen unless you help the framework a little bit. You will need to make sure that a C++ instance knows which information to stash into a Java object in which way. In the general case, your C++ instance will also need to know what Java type is its peer type.

Using C++ types with the framework

Let's take the example from above and define a C++ type that we wish to use with Java. The following snippet omits all the usual things like constructors, destructor, or methods and just focuses on the data declarations.

      class MySerializable : public java::io::Serializable
      {
      private:
        int     anIntField;
        long    aLongField;
        char*   aStringField;
      };

Clearly, the C++ fields are totally unknown to the Java side and will consequently not be serialized when this object is written to a Java stream. In order to solve this problem, there are three problems that need to be solved:

  1. we need to make available a Java type that can be used in any place where a Java Serializable instance can be used and that can hold the data from the C++ side
  2. we need to create an instance of that Java type
  3. we need to copy the C++ data into the newly created Java instance so that the Java serialization framework can take advantage of the information

These three tasks are achieved with the help of three framework methods declared by the xmog_base class. In general, you will have to provide at least the first and the third method and can use the second method that is provided by the default implementation.

Let's extend the above example by providing the necessary framework method to allow a developer to use the MySerializable type as expected:

      xmog_java_class * MySerializable::xmog_get_java_peer( xmog_localenv * env )
      {
         static xmog_java_class * clazz = xmog_serializable::get_class();
   
         return clazz;
      }
   
      int MySerializable::xmog_to_java_peer( xmog_localenv * env )
      {
        xmog_serializable::set_typeInfo( this, "MySerializable", env );
   
        xmog_serializable::set_int( this, "anIntField", anIntField, env );
        xmog_serializable::set_long( this, "aLongField", aLongField, env );
        xmog_serializable::set_Object( this, "aStringField", aStringField, env );
   
        return 0;
      }

In the above snippet, the first method indicates that we wish to use the built-in utility type xmog_serializable as the Java peer, but you could use your own Java peer types as well. In the second method, we copy the C++ instance's data into the peer instance by using the instance's hashtable to hold the data with the field names as keys. We could also have chosen to use a binary data representation for the C++ data, which would probably give us higher performance, but also put a bigger implementation burden on us.

What do you have to do when you have an inheritance hierarchy on the C++ side? You simply override the xmog_java_to_peer method and have it call its superclass' implementation as the very first thing:

      int MySubSerializable::xmog_to_java_peer( xmog_localenv * env )
      {
        this->MySerializable::xmog_to_java_peer( env );
   
        //override the typeinfo so that we know that this is a derived object
        xmog_serializable::set_typeInfo( this, "MySubSerializable", env );
   
        xmog_serializable::set_int( this, "anotherIntField", anotherIntField, env );
        xmog_serializable::set_long( this, "anotherLongField", anotherLongField, env );
   
        return 0;
      }

It is a little wasteful to override the typeinfo assignment in the derived type but in the larger scheme that should hardly matter all too much.

The above example illustrates the peer framework usage for the common example of a java.io.Serializable peer. In general, you can use the xmog_peer utility type to get access to an xmog_java_class instance and to methods that allow you to invoke all com.codemesh.peer.PeerType interface methods to get and set data from and to a peer instance. Here's an example of a custom peer type:

      xmog_java_class * MySerializable::xmog_get_java_peer( xmog_localenv * env )
      {
         static xmog_java_class * clazz = xmog_peer::get_class( "com.biz.MyPeerType", env );
   
         return clazz;
      }
   
      int MySerializable::xmog_to_java_peer( xmog_localenv * env )
      {
        xmog_peer::set_typeInfo( this, "MySerializable", env );
        xmog_peer::set_binaryData( this, "xcvfg", 5, env );
   
        return 0;
      }

Java Peer Type Requirements

One question that we glossed over a little bit is what the Java peer type should look like and where it is coming from. The latter question is easy to answer: you can deploy the peer type with the other Java classes that make up your application. The former question is a little more complex to answer. In the above example, we used the scenario where the user wanted to implement the java.io.Serializable interface in C++. This is something that Codemesh has come to understand as a pretty basic requirement and we have therefore created a peer type for just that purpose. That peer type is tucked away in the runtime library and injected into the JVM when required. You can use this peer type in all scenarios where the Java peer instance is used in a place that expects a java.io.Serializable or a java.lang.Object instance. You cannot use that peer type in scenarios where the Java side would expect any other types. You have to create your own peer types to accommodate these otehr scenarios.

It's completely up to you on how these peer types store the information, but if your peer types implement the com.codemesh.peer.PeerType interface you can use the xmog_peer utility class from your C++ application. This can make your implementation task much easier because you don't have to worry about using a custom Java type from C++ and you don't have to create custom integration infrastructure which you will need to maintain. Several implementations of peer types for commonly used interfaces are available as part of the com.codemesh.peer package and there is also an abstract class that you can use as the basis for your specific interface implementation.

If it is your intent to also use the supplied peer types from a Java application, you can deploy the xmog_peer.jar file as part of your Java application.

Note:
It is not necessary to deploy the xmog_peer.jar file as part of your C++ application. All supplied peer types are available via the runtime library.

Typedef Documentation

typedef jint(JNICALL * XMOG_CALLBACK_METHOD)(xmog_base &peer, jlong pInst, xmog_peer_value &retexc, xmog_java_array_template< xmog_peer_value > &args, xmog_localenv *env)
 

The callback function type.

This is the prototype of the function that is called by the universal callback entry point. Every callback corresponds with one such method. This method then typically delegates to a virtual instance method on the instance represented by pInst. It should be noted that it is not required that the callback method be implemented in this fashion even though the code generator only generates code in this fashion. A callback could theoretically be implemented without any further delegation to an instance method.

Parameters:
peer the Java object acting as a stand-in for the callback receiver.
pInst an integer that typically holds a pointer to a C++ object to whose instance method we delegate.
retexc an instance that will hold the result or the exception that was thrown during callback execution.
args the array of arguments that are passed to the callback.
env the local call environment.

typedef void*(XMOG_CALLING_CONVENTION * XMOG_PEER_UNMARSHAL_METHOD)(xmog_base &peer, xmog_java_class *peerClass, const char *cppType, xmog_localenv *env)
 

The peer unmarshalling callback.

This is the prototype of the function that is called when a returned Java object is a peer type that needs to be converted back to a C++ object. Clearly, the returned C++ object needs to be dynamically allocated and we can only return it through a void * because we know absolutely nothing about it.

In theory, we only need to pass the Java object reference to the unmarshalling method because we've already identified the proper unmarshalling method and it should know how to deal with the Java object. In practice, you might wish to have one peer unmarshalling method that knows how to deal with a variety of C++ types. To support this scenario, the unamrshalling method is also provided with access to the Java peer class and the retrieved C++ typename, thereby saving another query.

A typical implementation of the unmarshalling method follows the following blueprint:

  • create a heap-allocated C++ instance using the "from existing Java object" constructor
  • call xmog_peer helper methods to extract the data from the Java object and set it into the C++ object
  • return the C++ instance

Here's an example:

      void * XMOG_CALLING_CONVENTION   myUnmarshaller( xmog_base & peer, xmog_java_class * peerClass,
                                                       const char * cppType, xmog_localenv * env )
      {
          xmog_base *    result = NULL;
   
          if( !strcmp( cppType, "type1" ) )
          {
              result = new MyType( peer.get_jobject_( env ), xmog_base::GLOBAL );
   
              xmog_peer::get_int( result, "age", &result->age, env );
              xmog_peer::get_int( result, "id", &result->id, env );
          }
          else if( !strcmp( cppType, "type2" ) )
          {
              result = new TotallyDifferentType( peer.get_jobject_( env ), xmog_base::GLOBAL );
              
              MyDataStruct data;
              xmog_peer::get_binaryData( result, (jbyte*)&data, sizeof(data), env );
   
              result->setAge( data.age );
              result->setID( data.id );
          }
   
          return result;
      }

In the above exmaple, we show how the C++ type identifier is used to distinguish between two different C++ types that are handled by the same unmarshaller. If the unmarshaller returns NULL, it did not handle the C++ type and the runtime will look for another unamrshaller that might.

Parameters:
peer the Java peer object.
peerClass the Java class of the peer object.
cppType the C++ type identifier.
env the local call environment.


Function Documentation

virtual int xmog_base::xmog_create_java_peer xmog_java_class clazz,
xmog_localenv env = NULL,
xmog_flags  flags = xmog_base::GLOBAL
[virtual, inherited]
 

Creates a Java peer instance for this type.

This method is implemented to return an instance of Codemesh's Serializable type. The Serializable type supports storage of

  • native type information
  • binary data
  • typed field data (name/value pairs in a Hashtable)

This method will only be called under the following circumstances:

  • the proxy instance is a stand-alone NULL reference.
  • the xmog_get_java_peer() method for the type returns non-NULL.

This method is part of the Java Peer Framework.

Parameters:
clazz the peer class we need to instantiate.
env the local call environment. The default value is NULL.
flags the flags governing reference type and other housekeeping information. The default value is xmog_base::GLOBAL.
Returns:
0 if the method completed OK, -1 if an error occurred.

virtual xmog_java_class* xmog_base::xmog_get_java_peer xmog_localenv env = NULL  )  [virtual, inherited]
 

Returns NULL if the type does not have a Java peer type, a pointer to the type's xmog_java_class otherwise.

A user-written native type that needs to be represented by a specific Java peer type should override this method to return a pointer to that type's xmog_java_class. Generated proxy classes inherit the default implementation which always returns NULL.

Parameters:
env the local call environment. May be NULL.
Returns:
NULL if the type does not have to instantiate a Java peer type, a pointer otherwise.

virtual int xmog_base::xmog_to_java_peer xmog_localenv env = NULL  )  [virtual, inherited]
 

Sets the native instance's state into the Java peer instance.

This method needs to be overridden in order to set native information into the Java peer instance. There are two separate methods for creation and "serialization" with the latter being handled by this method.

The default implementation of this method does nothing. Your native type needs to override this method to set the instance's C++ data into the Java peer instance.

Parameters:
env the local call environment. May be NULL.
Returns:
0 if the method completed OK, -1 if an error occurred.


Generated on Wed May 31 14:01:36 2006 for Shared Codemesh Runtime Library API Reference by  doxygen 1.4.1