Magik on Java runtime

You can access the Magik on Java runtime either though the limited Magik on Java console, or by using GNU Emacs with the standard Smallworld extensions.

Using the console

Run start_magik_console.bat to start the console. This console has limited functionality, but it does:

  • provide a command history
  • allow you to enter commands over multiple lines (and will tell you what closing keyword it expects to see next in the window’s title bar)
  • provide standard cut-and-paste functionality

Using Emacs

It is possible to use Magik on Java via the standard Emacs GIS mode. Type F2 Z and then run start_magik_cli.bat in the correct directory:

[<installation directory>] <installation directory>/start_magik_cli.bat

A few things to note for using Emacs are:

  • You might need to select Java installation—ensure that Emacs starts with PATH which points to the correct version of Java. See Troubleshooting your Java installation.
  • The Class Browser is not supported.

Executing Magik code

You can execute Magik (but there are some limitations).

Command Description
quit() close the console
load_file("filename") load a file
smallworld_product.add_product(path to product.def) add a product
sw_module_manager.load_module(image_name) load a module

Products and modules

You can add products and load modules in the standard Magik way. Here’s how you use Magik on Java to load all code in the base_image module using an existing Core 4.3.0 installation (other modules and TSB versions of Core 4.3.0 may not work):

sw_module_manager.load_module(:base_image)

You will not always be expected to load the base_image module yourself from source: later releases will ship with precompiled versions of all Core code, and provide mechanisms for you to compile your own application code. The functionality in this release is just the first step towards being able to load all Core product and application modules, and also developing support for replacements for closed and open images.

In the meantime, feel free to try loading more modules on top of base, but do expect things to fall over in places. As always, we would appreciate your feedback and bug reports to help us determine the areas that we should work over the next few releases.

Note At this release, we claim to load the source for some modules which aren’t actually loaded. This is needed to work round some outstanding language or low-level library limitations in Magik on Java. See Limitations for a list of these modules.

Troubleshooting out of memory errors

In case you get an out of memory error while loading more modules, you can work around it for now by increasing the Java permGen memory in the <installation directory>/start_magik_console.bat when using the console, or <installation directory>/start_magik_cli.bat when using Emacs.

You can do it by changing the value of the -XX:MaxPermSize parameter to say something greater than the current 256M.

set ALCHEMY_ARGS=%javaOptions% -Xmx1g -XX:MaxPermSize=256M 

-Dmagik.readClasses=true -jar libs/org.eclipse.osgi_3.8.0.v20111025-1330.jar
-configuration libs/magikConsoleConfig %1

Supported Magik APIs

Datastore support

Magik on Java provides access to datastore functionality via low-level exemplars such as ds_version_view or database_view, and to whole databases via gis_program_manager.open_database().

Datastore files can be accessed using the Smallworld Datastore Server, swmfs, or in single-user mode by passing :concurrency_mode, :single_user to, for example, ds_version_view.add_file().

For example, to open the Cambridge Database and access the sector of an object, such as min_road, execute the following in the console:

gis_program_manager.open_database("C:<path_to_cambridge_db>\ds\ds_admin")
min_road << gis_program_manager.cached_dataset(:gis).collection(:min_road)
centre_line_sector_rope << min_road.an_element().centre_line.sectors

The majority of non-administrative functions are working. This functionality has been extensively tested by in-house automated functionality and stress tests and so is ready for detailed experimentation.

Alternatives and checkpoints are supported.

Graphics support

Magik on Java provides some graphics support. The following example displays a window containing a diagonal line, and the line adjusts when the window is resized (although the drawing canvas will not).

def_slotted_exemplar(:graphics_base,
	{
        {:canvas1,     _unset },
        {:background?, _false },
        {:bg_style,    _unset },
        {:styles,      _unset }
	},
	{:model} )
$
graphics_base.define_slot_access(:background?, :writable)
$

graphics_base.define_shared_constant(:canvas_width, 600, _false )
$

graphics_base.define_shared_constant(:canvas_height, 450, _false )
$

_private _method graphics_base.activate_in(f)
	## create the user interface. Simply creates a canvas on which
	## to install the popup menu.
	
	a << canvas_agent.new(_unset)
	.canvas1 << canvas.new(f,_self.canvas_width,_self.canvas_height,a)	
	a.define_redraw(:|redraw()|, _self)
_endmethod
$

_method graphics_base.redraw(window, _optional bnds)
	## This method is the default redraw method, it tests the
	## damage area as specified in the BNDS argument. The indicated
	## area should match the occluding window.
	##
	endPts << short_integer_vector.new_with(0,0, window.width, window.height)
	style << line_style.new(colour.called("green"), 4)
	
	window.clear()
	window.draw_rline(style, 10, 10, endPts)
_endmethod
$

g << graphics_base.new()
g.open()

We support mouse events and more and more drawing surface primitives. Please try it and if it doesn’t work let us know.


Java interoperability

Magik on Java provides interoperability with Java, although this feature will continue to be fleshed out in future releases. All APIs are subject to change—feedback welcome!

Java methods as Magik procedures

It's simple to create a method in Java and make that available as a procedure in the Magik on Java runtime:

  1. Write and compile the Java code.
  2. Import it into Magik using the procedures load_jar() and load_java_class().

Writing a Magik procedure as a Java method

The @MagikProc annotation informs Magik on Java that, when the surrounding Java class is loaded, a Magik procedure is created that calls this method when it is invoked. The annotation’s name parameter is the name the procedure is given in the top-level Magik package.

public class MyProc {
  @MagikProc(name="my_proc")
  public static Object javaMethodName(
    Object proc, Object mandatoryParam, 
    @Optional Object optionalParam, Object optionalParam2) 
  {
    // do something
    return null;
  }
}

The first parameter of the Java method must be provided, and will always be populated with the procedure object itself. All parameters after that will be populated with the values supplied when the procedure is invoked in Magik. Any parameters after the @Optional annotation are not mandatory and will default to null if they are not supplied by Magik.

The MagikProc and Optional annotations are both in the Java package com.gesmallworld.magik.commons.runtime.annotations.

Magik types in Java

This table shows how different types of object in Magik appear in Java.

Magik exemplar Java type
_unset null
integer java.lang.Integer
bignum java.math.BigInteger
character java.lang.Character
float java.lang.Double
simple_vector Object[]
char16_vector com.gesmallworld.magik.commons.runtime.objects.Char16Vector

This type is not available to your Java code, but Java can access the contents of the Magik string using the standard Java toString() method.

symbol com.gesmallworld.magik.commons.runtime.objects.Symbol

Type not available; use toString() to access the symbol’s value.

Other Magik exemplars can be passed to Java, but they do not appear as well-known Java types and there is currently no API for interacting with them.

Examples of procedure calls

Some examples showing how different Magik calls to the above Java-defined procedure appear on the Java side:

Magik: my_proc(1,2)
where:
proc will be the procedure object
mandatoryParam will be 1, type java.lang.Integer
optionalParam will be 2, type java.lang.Integer
optionalParam2 will be null

Magik: my_proc(“abcdef”)
where:
proc will be the procedure object
mandatoryParam will be a Char16Vector; call toString() on it to obtain “abcdef” as a java.lang.String
optionalParam will be null
optionalParam2 will be null

Magik: my_proc({1, 1.0}, :hi, %e)
where:
proc will be the procedure object
mandatoryParam will be an java.lang.Object[] consisting of:
  • 1 – java.lang.Integer
  • 1.0 – java.lang.Double
optionalParam will be a Symbol; call toString() on it to obtain “hi” as a java.lang.String
optionalParam2 will be ‘e’, type java.lang.Character

Magik: my_proc()
This will cause Magik to raise too_few_arguments as the mandatory parameter hasn’t been provided.

Importing the procedure into Magik

To use this procedure in Magik, you need to load the class within which the method is defined. The class must appear on the JVM’s classpath.

Two new Magik procedures have been added to help load JARs and classes:

  • load_jar(“path/to/Java/JAR/file”)
  • load_java_class(“name.of.JavaClass”)

Demonstration Java project

An Eclipse project has been supplied to demonstrate both Java interoperability and datastore support. The project can be found in the demo folder, along with a copy of the rwo.ds datastore file taken from the Cambridge Database.

The demonstration uses JFreeChart, a free charting library for Java, to draw charts based on information extracted from the rwo.ds datastore. You can open the project to inspect the code.

To run the demonstration, first compile the project into a Jar using Ant.

cd demo\interop.demo
ant jar

Then start the console, and try a simple example (this code can be found in demo\interop.demo\src\main\magik\simple_demo.magik).

# load the required jars and classes
load_jar("demo/interop.demo/build/magik.interop.jar")
load_java_class("com.gesmallworld.magik.interop.ChartProcs")
load_jar("demo/interop.demo/lib/jcommon-1.0.17.jar")
load_jar("demo/interop.demo/lib/jfreechart-1.0.14.jar")

# now draw a pie chart!
draw_pie_chart({{"magik", 80}, {"Java", 20}}, "chart", "window")

Now try a more complex example:

load_file("demo/interop.demo/src/main/magik/ds_demo.magik")

This example loads the rwo.ds datastore file (found in the demo folder) and gets some information from the min_roads table. It then displays this information in a pie chart and a bar chart.


Feedback magikonjava.feedback@ge.com

Copyright 1998-2013 General Electric Company. All Rights Reserved. GE and the GE Monogram are trademarks and service marks of General Electric Company.