Java Interface Library/en

Aus expecco Wiki (Version 2.x)
Version vom 10. April 2014, 20:54 Uhr von Cg (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „Documentation for expecco 2.1 == Introduction == The Java Interface is used to interact with Java objects inside an external JavaVM. The access to Java obje…“)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Documentation for expecco 2.1

Introduction[Bearbeiten]

The Java Interface is used to interact with Java objects inside an external JavaVM.

The access to Java objects, classes and programs is done via a framework called "Java-Bridge", which is similar in operation to the dotNET bridge. This framework implements transparent forwarding of function calls to Java objects, as existent in a local or remote Java virtual machine (JVM). Also, return values, callBacks and exception information are passed back from the Java program to expecco. A proxy-object mechanism, which catches all function calls, wraps the arguments and sends a datagram to the other bridge side. Thus, remote procedure calls are almost completely transparent to the Smalltalk/JavaScript code inside expecco. In your elementary code, you can write function calls as if they were to a local object.


Initializing / Releasing the Bridge[Bearbeiten]

Before any communication can take place between expecco and any Java object, the Java side of the bridge has to be started, and a communication has to be established. All of the bridges classes are in the JAVA namespace. The main interface class is "Java", in the "JAVA" namespace:

    java := JAVA::Java newWithServer.

or (in JavaScript):

    java = JAVA::Java.newWithServer();

This starts the Java-side of the bridge, and establishes a connection to the JavaVM.

Close the bridge if the bridge is no longer needed. Release the bridge with:

    java.closeBridge();

which terminates the connection.

Start and Connect Remote[Bearbeiten]

To start the bridge you must execute the JavaBridge.jar file on the remote machine. To pass parameters you must start it from a command line. Call:

   java -jar <PATH_TO_JAVABRIDGE.JAR> <PARAMETERS>

The JavaBridge.jar file can be found in the installation directory of expecco at:

   \exept\expecco\packages\exept\technologyBridge\javaBridge\javaBridge_Server_Client\JavaBridge.jar

When the bridge is running on the remote machine as server (default) use newConnectedTo:port:withTimeout: to connect to it.

   JAVA::Java newConnectedTo:'myHost' port:4567 withTimeout:30.

Or if started in client mode use newWaitingForConnectOnHost:port:withTimeout:.

   JAVA::Java newWaitingForConnectOnHost:'localhost' port:4567 withTimeout:30.

For more details see API

Startup Parameters[Bearbeiten]

You can use any parameter in any order. If no parameter is used then the bridge starts on localhost with port 14014 in server mode without keepAlive.

-help
  • Shows the help
-ip <aHostnameOrIP>
  • In client mode this specifies the ip or hostname to connect to.
-port <aPortNumber>
  • In client mode this specifies the port to connect to. In server mode this specifies the listening port.
-asClient
  • The bridge will start in client mode. If not set the bridge is started in server mode.
-keepAlive
  • By setting this flag the bridge will not exit after the connection has closed and starts to connect or listen again.

Loading Applications[Bearbeiten]

By accessing a classloader, additional classes, or applications as contained in JAR files can be loaded.

This can be used to add a JAR file to the class path:

    java addJarByPath:'pathToJarFile'.

Java Package import and Class access[Bearbeiten]

The import of required packages is done indirectly, when one of the package's classes is accessed for the very first time. Or in other words, if you access a class and the package of the class is not imported, then it is for the next class access in the same package and you don't need to specify the package again for the next class you use from the same package.


This code access the class JFrame from the "javax.swing" package for the first time. The whole class name in Java would be "javax.swing.JFrame". Note that the dots are replaced by underscores and the full class name is a message send to the Java handle.

    java javax_swing_JFrame. 

After that call the JavaVM now knows the package "javax.swing". Now we can access all classes of that package without specifying the package before the class name. For example we now want to access the class "javax.swing.JButton". The following code shows how to do this now in short form.

    java JButton. 

ATTENTION: If a classes short form exists more than one time on the Java side then you have to specify the full name of the class you want to use. Else the first matching class will be taken and thats probably not the class you was looking for.

Instantiating a Class[Bearbeiten]

Object instances are created via the "new"-message, sent to a proxy of a Java class. You can get this proxy as described in the previous section. For example we want to create a new instance of a JFrame and a JButton.

    frame := java javax_swing_JFrame new.
    button := java JButton new. 

The first statement results in an proxy object which represents the JFrame instance, this also does the import of the "javax.swing" package indirectly. The second line results in a proxy for a new JButton object.

Calling Methods[Bearbeiten]

A method call is done by a message send to a proxy object where the message is the method name to call. For example to call the "setVisible(boolean isVisible)" method on a JFrame object. First instantiate such an object and send the message to that proxy.

    frame setVisible:true.

To call a method with more than one parameter like "setSize(int width,int height)" on a JFrame we can write this.

    frame setSize:300 anyWord:200.

ATTENTION: The "anyWord:" in the message can be anything you want. In this example it could be useful to name it to height. (frame setSize:300 height:200)

Or for a method with 4 parameters it could look like this.

    frame setBounds:100 y:50 width:300 height:200.

ATTENTION: Also here the "y: width: height:" can be named as you want.

Calling static Methods[Bearbeiten]

Calling a static method on an object is not different from calling non static methods. In the most cases you will call a static method not on an object but directly on the class. This is done by just calling the method on the class object. For example we want to call the static method "isDefaultLookAndFeelDecorated()" of the JFrame class.

    java javax_swing_JFrame isDefaultLookAndFeelDecorated.
  
    or if the package is already loaded:
    java JFrame isDefaultLookAndFeelDecorated.

Accessing Fields[Bearbeiten]

Accessing a field of a Java object or class is not different from calling methods. To access a field of an object or a class we send the message to the object proxy where the message is the field name of the Java class. To access the field of a class the field must be static. For example we want to get the value of the static field "EXIT_ON_CLOSE" of the JFrame class.

    value := java javax_swing_JFrame EXIT_ON_CLOSE.
  
    or if the package is already loaded:
    value := java JFrame EXIT_ON_CLOSE.

Value now holds the integer value of the "EXIT_ON_CLOSE" constant.

Let us imagine that a JFrame object would have a field named "myField". To access this field we would write something like this.

    value := frame myField.

Value will now hold what ever "myField" returns. This could be another object or any primitive.

Callbacks from Java[Bearbeiten]

Sometimes we want to execute a small piece of smalltalk code during the execution of the Java code. For example if an observer notifies the smalltalk side or if a button on a Java GUI was pressed. The following code registers a smalltalk code block as a callback for an mouse pressed event of a button.

    listener := MouseListener new.
    listener mousePressed:[ Transcript showCR:'Hello from Java' ].

This creates the callback and the listener, which can now be registered on a button:

    button addMouseListener:listener.

When we now press the button the smalltalk block will be executed and writes "Hello from Java" on the smalltalk console.


Or another example with an observer would look like this.

    observer := java Observer new.
    observer update:[:sourceObservable :argument| 
        argument notNil ifTrue:[ Transcript showCR:('I was notifyed with: ',argument toString) ]
        ifFalse:[ Transcript showCR:'I was notifyed and the argument was nil' ].
    ].
    myObservable addObserver:observer.

When the observable calls "notifyObservers" the smalltalk block will be executed.


Examples[Bearbeiten]

This example creates a JFrame with one button on it. Then a Mouselistener is created and registered on the button. When the button is pressed the title of the window changes to "onPressed" and the transcript shows the message "onPressed". When the button is released, the title of the window changes to "onReleased" and the transcript shows "onReleased". If the button lost the mouse focus then the bridge will exit.

    |java frame button listener|
 
    "/getting a bridge
    java := JAVA::JavaBridge newWithServer.

    "/creating a new frame and button object
    frame := java javax_swing_JFrame new.
    button := java JButton new:'Click'.

    "/creating a new mouse listener and adding callback blocks
    listener := java MouseListener new.
    listener mousePressed:[ Transcript showCR:'onPress'. frame setTitle:'onPressed' ].
    listener mouseReleased:[ Transcript showCR:'onReleased'. frame setTitle:'onReleased' ].
    listener mouseExited:[ Transcript showCR:'onExited'. java closeBridge. ].

    "/register the mouse listener on the button and make the frame with button visible
    button addMouseListener:listener.
    frame add:button.
    frame setSize:300 y:100.
    frame setVisible: true.

Simple RMI Call[Bearbeiten]

The next example is written in javaScript syntax. It shows how a RMI host is queried for a RMI object and then the getHello method is called on it. You must replace the path to the compiled MyRemoteObject class by the directory containing the class file. And you have to replace the rmi host to a real one.

    var java, reg, myRemoteObject, callResult;

//Start a local JavaVM and connect the Communication-Bridge to it
    java = JAVA::Java.singletonInstance;  

//Add the class path where the description class of the shared RMI object can be found. RMI could also load the class from the server, but then we would need a RMI SecurityManager with download rights
    java.bridgeSide.addClassSearchPath("my\added\class\path"); 

//java.rmi.registry.LocateRegistry gets us the RMI Registry on the host
    reg = java.java_rmi_registry_LocateRegistry.getRegistry("rmiHost",4567);  

//get the rmi object
    myRemoteObject = reg.lookup("myObject");   

//get the hello string that was written by the RMI server into the rmi object
    callResult = myRemoteObject.getHello();

The RMI server written in Java:

RMIServer.java
    import java.rmi.AlreadyBoundException;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;

    public class RMIServer {

            public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {
                    int port = 4567;
                    if(args.length > 0)
                            port = Integer.parseInt(args[0]);
                    
                    Registry reg = LocateRegistry.createRegistry(port);
                    reg.bind("myObject", new MyRemoteObject("Hello from RMIServer: "+port));
                    while(true){
                            Thread.sleep(100);
                    }
            }

    }

The implementation of the shared RMI object written in Java:

MyRemoteObject.java
    import java.io.Serializable;
    import java.rmi.Remote;

    public class MyRemoteObject implements Remote,Serializable {
            
            private static final long serialVersionUID = 1L;
            
            private String hello;
            
            public MyRemoteObject(String hello) {
                    this.hello = hello;
            }

            public String getHello(){
                    return hello;
            }

    }


API[Bearbeiten]

JAVA::Java[Bearbeiten]

class[Bearbeiten]

newWithServer[Bearbeiten]
  • This will start a local JavaVM, running the JavaBridge, and establishes a connection on a random free port.
A new connected instance of JAVA::Java class is returned.
newWithServerForJavaPath:aJavaPathFilename[Bearbeiten]
  • This is the same as newWithServer but the path to the java executable can be specified. The JavaVM version must be 1.6 or higher to run the JavaBridge.
aJavaPathFilename - must be a instance of Filename
   Smalltalk: JAVA::Java newWithServerForJavaPath:('my\path\to\java.executable'asFilename).
   JavaScript: JAVA::Java.newWithServerForJavaPath("my\path\to\java.executable".asFilename());
newConnectedTo:aHhostString port:aPortNumber withTimeout:aTimeoutSeconds[Bearbeiten]
  • This is used to connect to a running JavaBridge on the network. The JavaBridge must be started in server mode on the remote host. After connecting a new connected instance of JAVA::Java is returned.
aHostString - the hostname or IP of the remote machine as String
aPortNumber - the port on which the remote machine is listening as Number
aTimeoutSeconds - a connect timeout in seconds as Number
   Smalltalk: JAVA::Java newConnectedTo:'myHostName' port:4567 withTimeout:30.
   JavaScript: JAVA::Java.newConnectedTo_port_withTimeout("myHostName",4567,30);
newWaitingForConnectOnHost:aListeningAddressString port:aListeningPortNumber withTimeout:aTimeoutSeconds[Bearbeiten]
  • This is used to wait for incomming connecions of a running JavaBridge on the network. The JavaBridge must be started in client mode on the remote host. After connecting a new connected instance of JAVA::Java is returned.
deprecated: aListeningAddressString - no longer used. Can be nil.
aListeningPortNumber - the port on which to listen for incomming connections as Number
aTimeoutSeconds - a connect timeout in seconds as Number, If nil it will wait endless.
singletonInstance[Bearbeiten]
  • This will call newWithServer for the first time and then always returns the same connected JAVA::Java instance until the connection was closed, then a new connected instance is returned.
exitAllInstances[Bearbeiten]
  • This will close all instances of JAVA::Java.

instance[Bearbeiten]

addJarByPath:aPath[Bearbeiten]
  • Adds a jar to the class path of the running JavaVM. If the jar depends on other jars or librarys you have to add them too.
aPath - the path to the jar file as String.
addLibraryByPath:aPath[Bearbeiten]
  • Adds a library to the library path of the running JavaVM. If the library depends on other librarys you have to add them too.
aPath - the path to the library file as String.
isAlive[Bearbeiten]
  • Tests if a connection is still responding.
return: - true if the connection is still alive, else false.
closeBridge[Bearbeiten]
  • This will close the bridge connection. Depending on in which mode the JavaBridge was started, the JavaVM is also closed (-keepAlive startparameter not set).
exit[Bearbeiten]
  • Same as closeBridge.

See Also[Bearbeiten]

The DOTNET Interface Plugin & Library, which implements a likewise interface for .NET applications/libraries.



Back to Online Documentation.



Copyright © 2014-2024 eXept Software AG