Skip to content
Nedelcho Delchev edited this page Aug 24, 2017 · 6 revisions

API v3.x Guidelines

Since version 3.0 the Javascript API supports also V8 engine. This requires redesign of the API itself, because the Java objects from the JVM are not directly accessible and manageable from the Javascript engine as it is the case for the Rhino and Nashorn engines.

API developers have to follow the rules below when introducing new APIs, which require communication with the JVM underneath:

Static Facades

  1. From the Java side a "facade" has to be implemented with public static methods, which are supposed to be called by the Javascript engine.
  2. It is highly recommended the facade's methods to have input and output parameters only as primitives.

Sample Java Facade:

    ...

    public static final String getAttribute(String name) {
		HttpServletRequest request = getRequest();
		if (request == null) {
			throw new InvalidStateException(NO_VALID_REQUEST);
		}
		return request.getAttribute(name) != null ? request.getAttribute(name).toString() : null;
    }

    ...

Sample Javascript Call:

    ...

    exports.getAttribute = function(name) {
	var attr = java.call('org.eclipse.dirigible.api.v3.http.HttpRequestFacade', 'getAttribute', [name]);
	return attr;
    };

    ...
  1. In case of complex parameters needed, a serialization and deserialization to/from JSON have to be considered.

Sample Java Facade:

    ...

    public static final String getAttributeNames() {
		HttpServletRequest request = getRequest();
		if (request == null) {
			throw new InvalidStateException(NO_VALID_REQUEST);
		}
		List<String> list = Collections.list(request.getAttributeNames());
		return GsonHelper.GSON.toJson(list.toArray());
    }

    ...

Sample Javascript Call:

    ...

    exports.getAttributeNames = function() {
	var attrNamesJson = java.call('org.eclipse.dirigible.api.v3.http.HttpRequestFacade', 'getAttributeNames', []);
	var attrNames = JSON.parse(attrNamesJson);
	return attrNames;
    };

    ...
  1. It is highly recommended the the Java facade and Javascript API module to relate to each other as 1:1
  2. The Javascript modules must be placed in repositories in the GitHub's DirigibleLabs organization following the naming convention "api-v3-XXX" where the XXX is the particular name of the API group of modules e.g. core, http, utils, etc.

e.g. https://github.com/dirigiblelabs/api-v3-http

  1. The repository should have a root folder named in the same way as the API group part of the repository following the subfolder "v3". All the modules in this group should be placed under "v3" subfolder and below.
  2. A separate module in the main Eclipse Dirigible repository have to be created under the "content" subfolder containing all the "webjars" modules.

e.g. https://github.com/eclipse/dirigible/tree/master/api/api-javascript/api-http

  1. The API which is used in this case is call() of the built-in java module.
  2. The necessary test cases have to be introduced in the "dirigible-api-tests" module https://github.com/eclipse/dirigible/blob/master/api/api-facades/api-tests/src/main/java/org/eclipse/dirigible/api/v3/test/AbstractApiSuiteTest.java, to guarantee the compatibility between the Javascript engines.

e.g. https://github.com/eclipse/dirigible/tree/master/api/api-facades/api-tests/src/main/resources/http/v3

Object Instantiation

  1. In case it is required (e.g. for performance reasons) to instantiate an object from the Javascript engine side in the JVM side, it can be used the function instantiate() in the java module
    var dateInstance = java.instantiate('java.sql.Date', [123456]);

Object's Method Invocation

  1. To call a method of such an object can be used the invoke() function.
  2. To deallocate the resources in the JVM when the object is no more needed, can be used free() function.
    ...

    this.setDate = function(index, value) {
		if(value!==null && value!==undefined) {
			var dateInstance = java.instantiate('java.sql.Date', [value.getTime()]);
			try {
				java.invoke(this.uuid, 'setDate', [index, dateInstance.uuid]);
			} finally {
				java.free(dateInstance.uuid);
			}
		} else {
			this.setNull(index, this.SQLTypes.DATE);
		}
    };

    ...
  1. In case you expect the return type of the method call to be an Object instance, additional parameter deep have to be added. It is available in the call() as well as in the invoke() functions.
    ...

    exports.getConnection = function(databaseType, datasourceName) {
	var connectionInstance = java.call('org.eclipse.dirigible.api.v3.db.DatabaseFacade', 'getConnection', [databaseType, datasourceName], true);
	var connection = new Connection();
	connection.uuid = connectionInstance.uuid;
	return connection;
    };

    /**
     * Connection object
     */
    function Connection() {
	
	this.prepareStatement = function(sql) {
		var statementInstance = java.invoke(this.uuid, 'prepareStatement', [sql], true);
		var statement = new Statement();
		statement.uuid = statementInstance.uuid;
		return statement;
    };

    ...