Hi, I am planning on starting work on the non-CORBA Java bindings for the official CellML API implementation (http://www.cellml.org/tools/api/) at some point within the next few weeks.
As I have not done any significant work on the Java binding, there is still time for changes to the API to be made. I would be keen to get any feedback from potential users of the API (especially those who currently have their own CellML API implementation in Java, and would benefit from being able to access the CellML API). I have detailed a rough proposal as to how it should be done below. Please let me know if you disagree with anything in the proposal (I would also be interested for feedback if you think this would be useful for you and you would use it). Please also forward this on if you know of a group working with CellML from Java who isn't on the To: list. Proposal: 1) The Java API bindings will simply forward calls between Java and the existing implementation in C++, PCM (Physiome CellML Mapping) (i.e. there is no plan to write a 100% pure Java implementation). 2) The interface will be defined using Java Native Interface (JNI). The bindings will target JDK 1.2 (or 1.1?) and earlier. It will attempt to avoid any non-portable C++ code, although binaries will need to be recompiled on each platform. 3) The general structure of the API will follow the existing specification described in the API document https://svn.physiomeproject.org/svn/physiome/CellML_DOM_API/trunk/interfaces/CellML_APISPEC.idl and the associated IDL files. 4) The bindings will be generated automatically from the IDL files. The code that will be written to support this will therefore take an IDL file as an input, and generate Java and C++ code to bridge between the existing API implementation and Java. The only code hand-written for the API will be the bootstrap code, used to get hold of the initial CellMLBootstrap object. 5) The code generator will be written in Python, extending the existing omniidl tool that comes with omniORB (http://omniorb.sourceforge.net). 6) The code generator will generate the following outputs: a) A Java interface file. There will be one public Java interface for each interface defined in the IDL files. b) A Java class file (one per interface) 'implementing' the interface. This class will define all methods as native. c) A C++ file acting as a Java->C++ bridge. This implements the native methods in b above, by calling the C++ API for them. d) A C++ file acting as a C++->Java bridge. This implements the interfaces defined in the IDL (in the form used by the existing API implementation), and uses JNI to invoke Java methods on classes implementing interfaces defined in a. 7) The base of all interfaces in the IDL definition, XPCOM::IObject, will have a corresponding Java interface (which is distinct from java.lang.Object), called XPCOM.IObject. This interface will expose query_interface (which will be renamed to queryInterface in the Java mapping) and the objid getter on the base object. However, as a special case, add_ref and release_ref will not be exposed to Java code. The rationale for this is that add_ref / release_ref are of no use to Java code, because the bindings will automatically create Java references to objects, allowing normal Java garbage collection to work as expected (subject to the caveat that no reference loop involving CellML API objects should be left around). 8) Because multiple inheritance of classes is not allowed in Java (and it would cause an explosion in code size if we generated all bindings for base interfaces on every implementation class). Therefore, where an interface has multiple base interfaces, the first interface in the list is selected, and all other base interfaces are not supported by the binding class. However, a new binding class can be obtained for the same underlying object using QueryInterface. For example, MathMLContentContainer inherits both MathMLContentElement and MathMLContainer. If you have a MathMLContentContainer called cc, and you want to access getNArguments() on MathMLContainer, you would have to write ((MathMLContainer)cc.queryInterface("mathml_dom.MathMLContainer")).getNArguments(). 10) The concrete implementation of XPCOM::IObject (C++->Java) overrides java.lang.Object.equals(java.lang.Object) for the the case that the argument is an XPCOM::IObject. In this case, it performs the comparison using getObjid() on XPCOM::IObject. Likewise, hashCode is implemented to hash the objid, and toString to contain the objid. This ensures that Java data-structures can be used together with CellML API objects. 11) The reference counting system used in the CellML API interacts with the garbage collection used in Java as follows: Every Java=>C++ wrapper has an associated strong reference (i.e. reference count incremented) to the underlying C++ object. This is stored in a private field. Upon finalisation of the C++ wrapper by the garbage collector, this reference is released. Every C++=>Java wrapper holds a JNI global reference to the Java object. This global reference is released from the destructor of the wrapper. This means that as long as the API holds a reference to a Java object, it will not be eligible to be garbage collected. 12) The API currently has thread-safety issues if used from multiple threads (it doesn't use mutexes to protect data structures), so as an interim solution, users will be advised not to call the API from more than one thread in Java, unless green-threads are in use. 13) Interface packages will be as follows: module(.module)*. Interface names will be taken directly from the IDL. For example, the FQN of model interface will be cellml_api.Model. 14) Implementation classes will take the same name as the interface, but the package will be prefixed with "impl.". 15) Attributes in the IDL will map to getters (and setters for non-readonly attributes): The first letter of the name will be up-cased, with the prefix 'get' or 'set' applied. For example, the following attribute: attribute CellMLAttributeString cmetaId; maps to: String getCmetaId() void setCmetaId(String arg); 16) Both UTF16 and UTF8 strings map to java.lang.String, converted as appropriate. Other basic types map as follows: PCM IDL Java uint32_t unsigned long int uint16_t unsigned short short uint8_t unsigned char byte double double double float float float 17) All sequences in IDL map to the array of the underlying type in Java. 18) Java objects map to wrappers of that object in PCM. PCM objects map to wrappers of the object in Java. 19) As an exception to 18, Java objects which are wrappers of PCM objects are unwrapped instead of double wrapped, and likewise for PCM objects which are wrappers of Java objects. More than likely, more similar types of rules will become necessary when I actually start work. If you can think of any now, or see something that is unclear, please let me know. Best regards, Andrew Miller _______________________________________________ cellml-discussion mailing list [email protected] http://www.cellml.org/mailman/listinfo/cellml-discussion
