Getting started - Second step How to use the Java Scilab binding?

## Description

This tutorial follows the First step.

## Example 3: Working with Java objects in Scilab

For this example, we define a set of higher abstraction Java objects. Then we will use Scilab as a sort of Java scripting language apply various operations on these objects. A wide variation of Java functionality will be showcased such as; static methods (Factory construct), Enums, simple polymorphism, and scope of members/methods.

This wide variety of functionality will be demonstrated using a set of 7 simple classes that describe a simple house;

    // Save under the name House.java
    package com.foo;

    import java.util.Arrays;
    import java.util.LinkendList;
    import java.util.List;

    public class House {

        private Color           color;
        private Door            door;
        private List<IWindow>   windows = new LinkendList<IWindow>();

        public House(Color color, Door door, IWindow... windows) {
            this.color = color;
            this.door = door;
            this.windows.addAll(Arrays.asList(windows));
        }

        public void repaint() {
            swapDoorHouseColor();
        }

        private void swapDoorHouseColor() {
            Color doorColor = door.getColor();
            door.repaint(color);
            color = doorColor;
        }

        public void addWindow(IWindow window) {
            windows.add(window);
        }

        public void replaceDoor(Door newDoor) {
            this.door = newDoor;
        }

        @Override
        public String toString() {
            return String.format(
                    "This is a house painted in %s, has a %s door, and %d windows",
                    color.getDescr(), door.getColor().getDescr(), windows.size());
        }
    }

    package com.foo;

    public class HouseFactory {

        public static House basicHouse() {
            Door door = new Door(Color.WHITE);
            IWindow window = new RectangularWindow(2, 0.8);
            return new House(Color.WHITE, door, window);
        }

        public static House flashyHouse() {
            Door door = new Door(Color.random());
            IWindow window = new CircularWindow(1.2);
            return new House(Color.random(), door, window);
        }
    }

    package com.foo;

    import java.util.Random;

    public enum Color {

        BLACK("black"), BLUE("blue"), BROWN("brown"), GREEN("green"),
        ORANGE("orange"), RED("red"), WHITE("white"), YELLOW("yellow");

        public String   descr;

        private Color(String s) {
            descr = s;
        }

        public String getDescr() {
            return descr;
        }

        public static Color random() {
            Color[] allColors = values();
            return allColors[new Random().nextInt(values().length)];
        }
    }

    package com.foo;

    public class Door {

        private Color   color;

        public Door(Color color) {
            this.color = color;
        }

        public Color getColor() {
            return color;
        }

        public void repaint(Color newColor) {
            color = newColor;
        }
    }

    package com.foo;

    public interface IWindow {

        double getWindowArea();

    }

    package com.foo;

    public class RectangularWindow implements IWindow {

        double  length;
        double  width;

        public RectangularWindow(double length, double width) {
            this.length = length;
            this.width = width;
        }

        public double getWindowArea() {
            return length * width;
        }
    }

    package com.foo;

    public class CircularWindow implements IWindow {

        double  radius;

        public CircularWindow(double radius) {
            this.radius = radius;
        }

        public double getWindowArea() {
            return Math.PI * radius * radius;
        }
    }

    // The examples are shipped in the Scilab distribution.
    directory=SCI+"/modules/external_objects_java/examples/com/foo/"
    // Compile of all them
    jcompile(ls(directory + "/*.java"))

First, let's construct a basic factory house. For this, the HouseFactory should be imported and the static method basicHouse() should be invoked.

    --> jimport("com.foo.HouseFactory")

    --> house = HouseFactory.basicHouse()
    house  =
    This is a house painted in white, has a white door, and 1 windows

This shows that static methods can be called as one would in Java. Also keep in mind that this is equivalent to "jinvoke(HouseFactory, 'basicHouse')" Also the message of the object has changed from something like:

    com.foo.House@ae8022
    To
    This is a house painted in white, has a white door, and 1 windows

This is due to the fact that the House class has a non-default \cmd[toString] method. This `toString` is used to generate this representation. We can still get the actual type (class) of our House object by invoking jgetclassname

    --> jgetclassname(house)
    ans  =
    com.foo.House

What is also interesting to know is that we now have a description of a house, without having to import House into Scilab directly! Now that a house has been constructed, it is time to add another window to that house. For this purpose we need to create a new window and add it to the house using the function `addWindow(IWindow)`. `IWindow` is an abstract description of what a window should be and cannot be instantiated directly. There are however two implementations available that we can construct; `RectangularWindow` and `CircularWindow`. Since the house starts with a `RectangularWindow` from the factory, a new `CircularWindow` shall be made.

    --> jimport("com.foo.IWindow")

    --> IWindow.new()
    !--error 999
    Method invocation: An error occurred: Exception when calling Java method : No such constructor in the class com.foo.IWindow.

    --> jimport("com.foo.CircularWindow")

    -->  newWindow = CircularWindow.new(0.5)
    newWindow  =
    com.foo.CircularWindow@3e389405

    --> house.addWindow(newWindow);

    --> house
    house  =
    This is a house painted in white, has a white door, and 2 windows

A new window was made, and it's reference stored in the "newWindow" variable. Next, the window was directly added to the house, without any need to wrap the variable. It basically works as one would expect it to work. Finally, we notice that our house now has 2 windows.

However, we don't like the door, so let's change the door. To create a door, a color for that door needs to be picked. Color is of the Java Enum class type. Again as before, first the required variables need to be imported, new instances created and then the door of the house needs to be swapped out.

    --> jimport("com.foo.Color")

    --> jimport("com.foo.Door")

    --> newDoor = Door.new(Color.RED)
    newDoor  =
    com.foo.Door@54a5f709

    --> house.replaceDoor(newDoor);

    --> house
    house  =
    This is a house painted in white, has a red door, and 2 windows

Using Enum types is as straightforward as using classes! Their methods and members are subject to the same principles:

    --> c = Color.random()
    c  =
    BLACK

    --> c = Color.random()
    c  =
    BLUE

    --> c.getDescr()
    ans  =
    blue

The list of windows kept by that house is of type `IWindow`. From this it follows that under normal circumstances only windows may be added to the list. To test this, let's see what happens when a `Door` is added in Scilab.

    --> house.addWindow(newDoor);
    !--error 999
    Method invocation: An error occurred: Exception when calling Java method : No method addWindow in the class com.foo.House or bad arguments type.

The same as using Java Reflection, the JVM security measures prevent us from disobeying the Java polymorthism rules. The same goes for private methods and members.

    --> c.descr
    ans  =
    blue

    --> house.door
    !--error 999
    %_EObj_e: An error occurred: Exception when calling Java method : Invalid field door

    --> house.repaint();

    --> house
    house  =
    This is a house painted in red, has a white door, and 2 windows

    --> house.swapDoorHouseColor()
    !--error 999
    %_EObj_e: An error occurred: Exception when calling Java method : Invalid field swapDoorHouseColor

Concluding, the JIMS package does the job of hiding the Java JNI interface with Scilab, and make it very clear and transparent to use Java libraries under Scilab. All the normal JVM functionality is present and the Scilab syntax is clear and natural to use.

From this point you should understand how to interface Scilab and Java libraries, utilize the full power of Java under the Scilab scripting environment.

## History

5.5.0 Function introduced. Based on the 'JIMS' module. The main difference in the behavior compared to the JIMS module is that jautoUnwrap is enabled by default.