| 1 | |
| 2 | = !MapGuide RFC 129 - SWIG/IMake enhancements and enhanced Java wrapper API = |
| 3 | |
| 4 | This page contains a change request (RFC) for the !MapGuide Open Source project. |
| 5 | More !MapGuide RFCs can be found on the [wiki:MapGuideRfcs RFCs] page. |
| 6 | |
| 7 | |
| 8 | == Status == |
| 9 | |
| 10 | ||RFC Template Version||(1.0)|| |
| 11 | ||Submission Date||29 Nov 2012|| |
| 12 | ||Last Modified|||| |
| 13 | ||Author||Jackie Ng|| |
| 14 | ||RFC Status||draft|| |
| 15 | ||Implementation Status|||| |
| 16 | ||Proposed Milestone||2.5|| |
| 17 | ||Assigned PSC guide(s)||(when determined)|| |
| 18 | ||'''Voting History'''||(vote date)|| |
| 19 | ||+1|||| |
| 20 | ||+0|||| |
| 21 | ||-0|||| |
| 22 | ||-1|||| |
| 23 | ||no vote|| || |
| 24 | |
| 25 | == Overview == |
| 26 | |
| 27 | This RFC proposes to add enhancments to SWIG/IMake to support an enhanced Java wrapper API as well as supporting the preservation/conversion of doxygen API documentation fragments for Java and .net |
| 28 | |
| 29 | == Motivation == |
| 30 | |
| 31 | The problems with the current Java wrapper API are [http://trac.osgeo.org/mapguide/ticket/9 well documented]: |
| 32 | |
| 33 | * Java method names are in UpperCamelCase (verbatim copy from MapGuide's C++ classes) instead of lowerCamelCase |
| 34 | * MgException is a checked exception. All java methods have the "throws MgException" clause forcing the user to either implement a (possibly un-necessary try/catch block) or to add their own "throws MgException" clause in their calling method |
| 35 | * MapGuide collection classes (eg. MgStringCollection) not implementing the java.util.Collection interface |
| 36 | * Lack of integrated javadoc comments in java proxy source files due to doxygen comments being lost in the SWIG build/translation process |
| 37 | |
| 38 | == Proposed Solution == |
| 39 | |
| 40 | To address these issues, modifications will be made to our internal copy of SWIG and IMake to enable the creation of an "enhanced" Java wrapper API |
| 41 | |
| 42 | === Add a JavaApiEx project to the WebTier solution === |
| 43 | |
| 44 | This is a copy of the JavaApi directory with a set of SWIG macros/customizations/typemaps to facilitiate the implemenation of java.util.Collection and java.util.Iterable for proxy classes that require such interfaces |
| 45 | |
| 46 | Classes which are currently slated for java.util.Collection support include: |
| 47 | |
| 48 | * MgClassDefinitionCollection (as Collection<MgClassDefinition>) |
| 49 | * MgFeatureSchemaCollection (as Collection<MgFeatureSchema>) |
| 50 | * MgPropertyDefinitionCollection (as Collection<MgPropertyDefinition>) |
| 51 | * MgPropertyCollection (as Collection<MgProperty>) |
| 52 | * MgStringCollection (as Collection<java.lang.String>) |
| 53 | * MgLayerCollection (as Collection<MgLayerBase>) |
| 54 | * MgLayerGroupCollection (as Collection<MgLayerGroup>) |
| 55 | |
| 56 | The following collection classes will not implement the java.util.Collection interface due to disparity in interface and implementation |
| 57 | |
| 58 | * MgIntCollection (int is not an object in Java) |
| 59 | * MgBatchPropertyCollection (can't implement as Collection<MgPropertyCollection> due to a different contains() API) |
| 60 | |
| 61 | Classes which are currently slated for java.util.Iterable support include: |
| 62 | |
| 63 | * MgReadOnlyLayerCollection |
| 64 | |
| 65 | The following classes will have special implementations of equals() and hashCode() needed for item containment logic to properly work in the java.util.Collection API |
| 66 | |
| 67 | * MgClassDefinition |
| 68 | * MgFeatureSchema |
| 69 | * MgPropertyDefinition |
| 70 | * MgProperty |
| 71 | * MgLayerBase |
| 72 | * MgLayerGroup |
| 73 | |
| 74 | Classes that implement java.util.Collection or java.lang.Iterable can be iterated with java's enhanced for loop: |
| 75 | |
| 76 | {{{ |
| 77 | MgClassDefinitionCollection classes = ... |
| 78 | for (MgClassDefinition clsDef : classes) { |
| 79 | ... |
| 80 | } |
| 81 | }}} |
| 82 | |
| 83 | To distinguish this wrapper from the original, this project will output MapGuideJavaApiEx.dll as the JNI glue library and MapGuideApiEx.jar as the Java wrapper API jar. |
| 84 | |
| 85 | The pre-defined AppThrowable java exception class will now extend from java.lang.RuntimeException, making all subclasses (MgException and co) unchecked exceptions |
| 86 | |
| 87 | === Modify swig to support 2 new java-specific command-line options (-mgjavacasing and -mgjavanothrow) === |
| 88 | |
| 89 | With the -mgjavacasing option given, all method names will be re-written with the first letter lower-cased by SWIG |
| 90 | |
| 91 | With the -mgjavanothrow option given, the "throws MgException" clause is omitted from all Java method declarations |
| 92 | |
| 93 | The JavaApi project will invoke SWIG as before. The JavaApiEx project will invoke SWIG with these 2 new options |
| 94 | |
| 95 | === Use the SWIG modifier directives as a means of transplanting documentation / deprecation === |
| 96 | |
| 97 | Using the `%typemap(javaclassmodifiers)` and `%javamethodmodifiers` directives (for .net, this is `%typemap(csclassmodifiers)` and `%csmethodmodifiers`), we can attach documentation blocks and any attributes to our Java/C# proxy class methods |
| 98 | |
| 99 | For example a deprecated API like the [http://trac.osgeo.org/mapguide/wiki/MapGuideRfc9 blank MgMap constructor] can be decorated like so |
| 100 | |
| 101 | {{{ |
| 102 | //Java |
| 103 | %javamethodmodifiers MgMap::MgMap() %{/** |
| 104 | * This constructor is deprecated. Use MgMap(MgSiteConnection) instead |
| 105 | */ |
| 106 | @Deprecated public%} |
| 107 | |
| 108 | //C# |
| 109 | %csmethodmodifiers MgMap::MgMap() %{///<summary> |
| 110 | /// This constructor is deprecated. Use MgMap(MgSiteConnection) instead |
| 111 | // </summary> |
| 112 | [Obsolete(\"This API is deprecated\")] public%} |
| 113 | }}} |
| 114 | |
| 115 | Which will cause SWIG to generate the following proxy class method declarations |
| 116 | |
| 117 | {{{ |
| 118 | //Java |
| 119 | public class MgMap |
| 120 | { |
| 121 | /** |
| 122 | * This constructor is deprecated. Use MgMap(MgSiteConnection) instead |
| 123 | */ |
| 124 | @Deprecated public MgMap() { |
| 125 | ... |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | //C# |
| 130 | public class MgMap |
| 131 | { |
| 132 | ///<summary> |
| 133 | /// This constructor is deprecated. Use MgMap(MgSiteConnection) instead |
| 134 | ///</summary> |
| 135 | [Obsolete("This API is deprecated")] public MgMap() { |
| 136 | ... |
| 137 | } |
| 138 | } |
| 139 | }}} |
| 140 | |
| 141 | In addition to documentation, this also gives us the ability to transfer C++ API deprecation intent to the target languages as well, allowing for csc and javac to trigger compiler warnings regarding use of deprecated APIs. |
| 142 | |
| 143 | As long as the deprecated C++ API(s) are marked up with the doxygen \deprecated directive, they will properly transfer across as @Deprecated in Java and ObsoleteAttribute in .net |
| 144 | |
| 145 | === Modify IMake to collect doxygen fragments of input headers and output the translated version in the target language === |
| 146 | |
| 147 | It is obviously impractical to manually write out these SWIG modifier directives by hand. So we'll modify IMake to do this for us. |
| 148 | |
| 149 | IMake already does some sort of documentation collection when it writes out the constants source files for PHP/Java/.net. Unfortunately this is a verbatim doxygen dump which renders these blocks un-usable when used for auto-completion within an IDE |
| 150 | |
| 151 | So IMake will be modified as follows: |
| 152 | |
| 153 | * Retain the documentation collection logic when the input file is not Constants.xml |
| 154 | * Add methods to convert the collected doxygen documentation to the target language's documentation format (JavaDoc for Java, XML documentation for .net) |
| 155 | * Write these converted fragments out as the aforementioned SWIG modifier directives for the target language. |
| 156 | |
| 157 | These IMake changes only apply for Java and .net. See implications |
| 158 | |
| 159 | === Update the *ApiGen.xml files === |
| 160 | |
| 161 | All these files require a new DocTarget element, which specifies the output file that IMake will write these SWIG modifier directives to. |
| 162 | |
| 163 | This file is %include'd into the MapGuideApi.i (the split one for .net) that IMake generates for SWIG, allowing for the documentation to be transferred over to the proxy classes of the target language |
| 164 | |
| 165 | === Modify the .net and Java API build process === |
| 166 | |
| 167 | The nmake files for the .net API will be modified so that the csc.exe call includes the /doc parameter. Allowing for Visual Studio intellisense files to be created for each OSGeo.MapGuide assembly |
| 168 | |
| 169 | The JavaApi and JavaApiEx pre-build events will be modified to include an extra step to build a -source jar file, allowing for similar integrated auto-complete API documentation in the major Java IDEs |
| 170 | |
| 171 | All of the above changes have been implemented in [http://trac.osgeo.org/mapguide/browser/sandbox/jng/swig-java this sandbox]. Upon adoption of this RFC, the changes in this sandbox will be merged back into the trunk code stream. |
| 172 | |
| 173 | == Implications == |
| 174 | |
| 175 | The existing API wrappers (including the existing Java one) are not affected by these changes. |
| 176 | |
| 177 | In fact for some languages (Java/.net), they will be getting the extra benefit of integrated API documentation and compiler warnings on use of deprecated APIs |
| 178 | |
| 179 | This RFC has zero effect (positive or negative) on the PHP wrapper. This is due to SWIG not generating any source PHP files for PHP proxy classes, so there is no actual target to drop in the converted doxygen fragments. Also there is no official way to document PHP code, so trying to bring these same integrated API documentation benefits over to PHP is currently a fruitless endeavour. |
| 180 | |
| 181 | The DoxyTransform build tool which is currently employed to convert doxygen API documentation to Visual Studio intellisense xml files will be removed as this RFC renders that tool obsolete, and this RFC supports API documentation transfer to both .net and Java instead of just .net |
| 182 | |
| 183 | For the "enhanced" Java wrapper, the conversion of method names to lowerCamelCase has exposed some API naming conflicts: |
| 184 | |
| 185 | * The converted MgException.getStackTrace() conflicts with java.lang.Throwable.getStackTrace() |
| 186 | * The converted MgPropertyDefinition.delete() conflicts with the SWIG-generated delete() method for finalization |
| 187 | * The converted MgClassDefinition.delete() conflicts with the SWIG-generated delete() method for finalization |
| 188 | * The converted MgFeatureSchema.delete() conflicts with the SWIG-generated delete() method for finalization |
| 189 | * The converted add() method of any MapGuide collection class conflicts with the add() method as specified in the java.util.Collection interface (MapGuide's add() returns void, java.util.Collection's add() returns boolean) |
| 190 | |
| 191 | Since this "enhanced" Java wrapper will be a new wrapper API, there is no compatibility history to deal with unlike the other wrappers so as a result it is much safer and easier to rename the conflicting methods in this enhanced wrapper than to rename the conflicting APIs in the C++ classes (as was the case for [wiki:MapGuideRfc89]) |
| 192 | |
| 193 | The conflicting methods will be renamed in the wrapper as so: |
| 194 | |
| 195 | * MgException::getStackTrace() will become MgException.getExceptionStackTrace() |
| 196 | * MgPropertyDefinition.delete() will become MgPropertyDefinition.markAsDeleted() |
| 197 | * MgClassDefinition.delete() will become MgClassDefinition.markAsDeleted() |
| 198 | * MgFeatureSchema.delete() will become MgFeatureSchema.markAsDeleted() |
| 199 | * The add() method of any MapGuide collection class implementing java.util.Collection will become addItem() |
| 200 | |
| 201 | The Java variant of the AJAX viewer will still use the existing Java wrapper. There are no plans in this RFC to convert the Java AJAX viewer to use the enhanced Java wrapper. It is envisioned that this enhanced Java wrapper will be made available in the 2.5 timeframe as a "developer preview" option. Whether this will replace the existing Java wrapper will be the scope for a future RFC. |
| 202 | |
| 203 | == Test Plan == |
| 204 | |
| 205 | Add a java test application to exercise the classes in the enhanced java wrapper that implement java.util.Collection and java.lang.Iterable |
| 206 | |
| 207 | Test/verify functionality of existing viewers in both Windows/Linux to confirm the SWIG/IMake changes have no adverse effects on the existing wrapper APIs |
| 208 | |
| 209 | == Funding / Resources == |
| 210 | |
| 211 | Community |