2.24. Using existing java code in Kermeta

[Warning]Text not verified for kermeta 2

If you have existing code that you want to run in a Kermeta program, you can use one of those two mechanisms : extern call or seamless require.

The extern call is currently the more robust approach as it is used internally by Kermeta to implement some part of its framework. It also helps to clearly specify the border between java and Kermeta.

The seamless java require is more straitghforward to use (no wrapper to write) but is still in prototype (v0.4.2) and still have several limitations.

2.24.1. Using extern to call java code

The extern allows you to call a java static method from Kermeta. But, to do that, you will have firstly to create a Java wrapper, that will be able to manipulate correctly the Java objects, and secondly to add this wrapper in your java global classpath.

Then, from this method you can access all your java libraries. One task of the static method will be to convert the basic types like Integer or String.

You'll need to refer to the Javadoc of the interpreter in order to know how to access the internal RuntimeObject of Kermeta.

Example 1 : sample of Kermeta code using extern (io.kmt):

/** * An implementation of a StdIO class in Kermeta using existing Java: standard * input/output */
class StdIO
{
 /** * write the object to standard output */ 
 operation write(object : Object) : Void is do
   result ?= extern fr::irisa::triskell::kermeta::runtime::basetypes::StdIO.write(object)
 end
 
 /** * writeln the object to standard output */ 
 operation writeln(object : Object) : Void is do
   result ?= extern fr::irisa::triskell::kermeta::runtime::basetypes::StdIO.writeln(object)
 end
 
 /** * read an object from standard input */ 
 operation read(prompt : String) : String is do
   result ?= extern fr::irisa::triskell::kermeta::runtime::basetypes::StdIO.read(prompt)
 end

}

Example 2 : sample of Java code ("wrapper") called by the Kermeta extern:

/** Implementation of input and output methods */
   public class StdIO{ 
      // Implementation of method write called as :
      // extern fr::irisa::triskell::kermeta::runtime::basetypes::Io.write(output) 
      public static RuntimeObject write(RuntimeObject output) {
         output.getFactory().getKermetaIOStream().print(output.getData().get("StringValue")); 
      return output.getFactory().getMemory().voidINSTANCE; 
      } 
      // Implementation of method writeln called as : // extern fr::irisa::triskell::kermeta::runtime::basetypes::Io.writeln(output) 
      public static RuntimeObject writeln(RuntimeObject output) {
         write(output); 
         output.getFactory().getKermetaIOStream().print("\n"); 
      return output.getFactory().getMemory().voidINSTANCE; 
      } 
      // Implementation of method writeln called as : // extern fr::irisa::triskell::kermeta::runtime::basetypes::Io.read(output) 
      public static RuntimeObject read(RuntimeObject prompt) {
         java.lang.String input = null; 
         // We also have our own String wrapper 
      if (String.getValue(prompt).length()>0) 
         prompt.getFactory().getKermetaIOStream().print(String.getValue(prompt)); 
      // FIXME : dirty cast.. read returns a String or could return smthg else? 
      input = (java.lang.String)prompt.getFactory().getKermetaIOStream().read( String.getValue(prompt)); 
      RuntimeObject result = String.create(input, prompt.getFactory()); 
      return result; 
   }
[Tip]Tip

This method is used to implement Kermeta framework. You'll find much more code samples of extern call in its sources.

2.24.2. Requiring jar file to call java code

[Warning]Warning

This feature is still a prototype and still have many limitations. The first version is already available but any help is welcome to help us to improve it.

The basic principle, is to simply require your jar file.

 require "yourjar.jar" 

Then Kermeta automatically retreive the class definition it contains to be used from Kermeta code. However, as java and Kermeta have different language constraints, some adaptation are automatically made.

If there is several operations with the same name (as this is legal in Java but not in Kermeta) they are renamed. (Please use the outline to find the new name of the operation you want)

Java contructors are generated as "initialize" operation.

When creating a new java object from Kermeta, a call to new is not enough, you also need to call one of the "initialize" operation in order to correctly create it.

In order to get the standard library direclty from your running java, you can require java_rt_jar but as this library is really big and as you probably don't need all java from Kermeta ;-) then you must use the includeFilter and excludeFilter.

Sample using java.io from java Standard library

 
require kermeta

require java_rt_jar includeFilter ("java::io")   // the filter ensure we don't get all java

using java::io
using kermeta::kunit
class testRequireJava inherits kermeta::kunit::TestCase
{
	operation main() : Void is do
		var tr : TestRunner init TestRunner.new
		tr.run(testRequireJava)
		tr.printTestResult
	end	
	
	operation testmain() : Void is do 
	
		// create and initialize a File with the String
		var f : File init File.new.initialize_String("c:/temp/test.txt")
		var f2 : File
		// create and initialize a FileWriter with the File
		var fwriter : FileWriter init FileWriter.new.initialize_File(f)
		if (f.exists) then 
			stdio.writeln(f.toString + " already exists")
		else
			stdio.writeln(f.createNewFile.toString)
		end
		fwriter.write_String("Hello world") 
		fwriter.close
		stdio.writeln("file written")
		stdio.writeln(fwriter.toString)
	    	    
		stdio.writeln(f.getPath)
		stdio.writeln(f.separator)
		f2 := f
		stdio.writeln(f2.createNewFile.toString)
		stdio.writeln((f2.equals(f)).toString)
		assert( f2.equals(f))
	    
		var fwriter2 : FileWriter
		fwriter2 :=  fwriter
		stdio.writeln((fwriter2.equals(fwriter)).toString)
		assert( fwriter2.equals(fwriter))
	    
		stdio.writeln(f.getPath)
		stdio.writeln(f.toString)
		stdio.writeln("End")
	end
} 
      		

includeFilter and excludeFilter accept a comma separated list of qualified name. includeFilter adds only elements whose qualified name start with one of the list. excludeFilter removes elements whose qualified name start with one of the list. If you use a combinaison of includeFilter and excludeFilter , then the includeFilter is applied before the excludeFilter (that'll remove element from the included one.

Currently known limitations: no support for java5 generics (they are ignored), requiring very big jar like the full java library end up with out of memory error (you need to use the includefilter and excludeFilter), some bugs with some primitives types (double/float)