Comparing version 0.4.7 to 0.5.1
@@ -5,3 +5,6 @@ 'use strict'; | ||
var _ = require('lodash'); | ||
var async = require('async'); | ||
var path = require('path'); | ||
var fs = require('fs'); | ||
var binaryPath = path.resolve(path.join(__dirname, "../build/Release/nodejavabridge_bindings.node")); | ||
@@ -13,2 +16,7 @@ var bindings = require(binaryPath); | ||
java.classpath.push(path.resolve(__dirname, __dirname, "../src-java")); | ||
java.classpath.pushDir = function(dir) { | ||
fs.readdirSync(dir).forEach(function(file) { | ||
java.classpath.push(path.resolve(dir, file)); | ||
}); | ||
}; | ||
java.nativeBindingLocation = binaryPath; | ||
@@ -29,2 +37,121 @@ | ||
java.isJvmCreated = function() { | ||
return typeof java.onJvmCreated !== 'function'; | ||
} | ||
var clients = []; | ||
// We provide two methods for 'clients' of node-java to 'register' their use of java. | ||
// By registering, a client gets the opportunity to be called asynchronously just before the JVM is created, | ||
// and just after the JVM is created. The before hook function will typically be used to add to java.classpath. | ||
// The function may peform asynchronous operations, such as async [glob](https://github.com/isaacs/node-glob) | ||
// resolutions of wild-carded file system paths, and then notify when it has finished via either calling | ||
// a node-style callback function, or by resolving a promise. | ||
// A client can register function hooks to be called before and after the JVM is created. | ||
// If the client doesn't need to be called back for either function, it can pass null or undefined. | ||
// Both before and after here are assumed to be functions that accept one argument that is a node-callback function. | ||
java.registerClient = function(before, after) { | ||
if (java.isJvmCreated()) { | ||
throw new Error('java.registerClient() called after JVM already created.'); | ||
} | ||
clients.push({before: before, after: after}); | ||
} | ||
// A client can register function hooks to be called before and after the JVM is created. | ||
// If the client doesn't need to be called back for either function, it can pass null or undefined. | ||
// Both before and after here are assumed to be functions that return Promises/A+ `thenable` objects. | ||
java.registerClientP = function(beforeP, afterP) { | ||
if (java.isJvmCreated()) { | ||
throw new Error('java.registerClient() called after JVM already created.'); | ||
} | ||
clients.push({beforeP: beforeP, afterP: afterP}); | ||
} | ||
function runBeforeHooks(done) { | ||
function iterator(client, cb) { | ||
try { | ||
if (client.before) { | ||
client.before(cb); | ||
} | ||
else if (client.beforeP) { | ||
client.beforeP().then(function(ignored) { cb(); }, function(err) { cb(err); }); | ||
} | ||
else { | ||
cb(); | ||
} | ||
} | ||
catch (err) { | ||
cb(err); | ||
} | ||
} | ||
async.each(clients, iterator, done); | ||
} | ||
function createJVMAsync(callback) { | ||
var ignore = java.newLong(0); // called just for the side effect that it will create the JVM | ||
callback(); | ||
} | ||
function runAfterHooks(done) { | ||
function iterator(client, cb) { | ||
try { | ||
if (client.after) { | ||
client.after(cb); | ||
} | ||
else if (client.afterP) { | ||
client.afterP().then(function(ignored) { cb(); }, function(err) { cb(err); }); | ||
} | ||
else { | ||
cb(); | ||
} | ||
} | ||
catch (err) { | ||
cb(err); | ||
} | ||
} | ||
async.each(clients, iterator, done); | ||
} | ||
function initializeAll(done) { | ||
async.series([runBeforeHooks, createJVMAsync, runAfterHooks], done); | ||
} | ||
// This function ensures that the JVM has been launched, asynchronously. The application can be notified | ||
// when the JVM is fully created via either a node callback function, or via a promise. | ||
// If the parameter `callback` is provided, it is assume be a node callback function. | ||
// If the parameter is not provided, and java.asyncOptions.promisify has been specified, | ||
// then this function will return a promise, by promisifying itself and then calling that | ||
// promisified function. | ||
// This function may be called multiple times -- the 2nd and subsequent calls are no-ops. | ||
// However, once this method has been called (or the JVM is launched as a side effect of calling other java | ||
// methods), then clients can no longer use the registerClient API. | ||
java.ensureJvm = function(callback) { | ||
// First see if the promise-style API should be used. | ||
// This must be done first in order to ensure the proper API is used. | ||
if (_.isUndefined(callback) && java.asyncOptions && _.isFunction(java.asyncOptions.promisify)) { | ||
// Create a promisified version of this function. | ||
var launchJvmPromise = java.asyncOptions.promisify(java.ensureJvm.bind(java)); | ||
// Call the promisified function, returning its result, which should be a promise. | ||
return launchJvmPromise(); | ||
} | ||
// If we get here, callback must be a node-style callback function. If not, throw an error. | ||
else if (!_.isFunction(callback)) { | ||
throw new Error('java.launchJvm(cb) requires its one argument to be a callback function.'); | ||
} | ||
// Now check if the JVM has already been created. If so, we assume that the jvm was already successfully | ||
// launched, and we can just implement idempotent behavior, i.e. silently notify that the JVM has been created. | ||
else if (java.isJvmCreated()) { | ||
return setImmediate(callback); | ||
} | ||
// Finally, queue the initializeAll function. | ||
else { | ||
return setImmediate(initializeAll, callback); | ||
} | ||
} | ||
java.onJvmCreated = function() { | ||
@@ -31,0 +158,0 @@ if (java.asyncOptions) { |
@@ -10,3 +10,3 @@ { | ||
], | ||
"version": "0.4.7", | ||
"version": "0.5.1", | ||
"engines": { | ||
@@ -30,12 +30,12 @@ "node": ">=0.10.0" | ||
"dependencies": { | ||
"async": "0.9.0", | ||
"find-java-home": "0.1.2", | ||
"glob": "~3.2.9", | ||
"nan": "1.4.1" | ||
"glob": "5.0.5", | ||
"nan": "1.7.0" | ||
}, | ||
"devDependencies": { | ||
"async": "0.9.0", | ||
"chalk": "^1.0.0", | ||
"lodash": "^3.5.0", | ||
"nodeunit": "0.9.0", | ||
"when": "3.6.4" | ||
"chalk": "1.0.0", | ||
"lodash": "3.7.0", | ||
"nodeunit": "0.9.1", | ||
"when": "3.7.2" | ||
}, | ||
@@ -42,0 +42,0 @@ "scripts": { |
@@ -182,3 +182,3 @@ [![Build Status](https://travis-ci.org/joeferner/node-java.png)](https://travis-ci.org/joeferner/node-java) | ||
* We've tested promises with five Promises/A+ implementations. See `testHelpers.js` for more information. | ||
* NOTE: Due to specifics of initialization order, the methods `java.newInstancePromise`, `java.callMethodPromise`, and `java.callStaticMethodPromise` are not available until some other java method is called. You may need to call some other java method such as `java.import()` to finalize java initialization. | ||
* NOTE: Due to specifics of initialization order, the methods `java.newInstancePromise`, `java.callMethodPromise`, and `java.callStaticMethodPromise` are not available until the JVM has been created. You may need to call some other java method such as `java.import()` to finalize java initialization, or even better, the function `java.ensureJVM()`. | ||
@@ -189,4 +189,28 @@ ##### Special note about the exported module functions `newInstance`, `callMethod`, and `callStaticMethod`. | ||
## Varargs support | ||
With v0.5.0 node-java now supports methods with variadic arguments (varargs). Prior to v0.5.0, | ||
a javascript call to a Java varargs method had to construct an array of the variadic arguments using `java.newArray()`. With v0.5.0 javascript applications can simply use the variadic style. | ||
In most cases it is still acceptable to use `java.newArray()`. But it is now possible to pass a plain javascript array, or use the variadic style. For example, consider these snippets from the unit test file `test/varargs-test.js`: | ||
``` | ||
test.equal(Test.staticVarargsSync(5, 'a', 'b', 'c'), '5abc'); | ||
test.equal(Test.staticVarargsSync(5, ['a', 'b', 'c']), '5abc'); | ||
test.equal(Test.staticVarargsSync(5, java.newArray('java.lang.String', ['a', 'b', 'c'])), '5abc'); | ||
``` | ||
Note that when passing a Javascript array (e.g. `['a', 'b', 'c']`) for a varargs parameter, node-java must infer the Java type of the array. If all of the elements are of the same javascript primitive type (`string` in this example) then node-java will create a Java array of the corresponding type (e.g. `java.lang.String`). The Java types that node-java can infer are: `java.lang.String`, `java.lang.Boolean`, `java.lang.Integer`, `java.lang.Long`, and `java.lang.Double`. If an array has a mix of `Integer`, `Long`, and `Double`, then the inferred type will be `java.lang.Number`. Any other mix will result in an inferred type of `java.lang.Object`. | ||
## JVM Creation | ||
With v0.5.1 a new API is available to make it easier for a complex application to have full control over JVM creation. In particular, it is now easier to compose an application from several modules, each of which must add to the Java classpath and possibly do other operations just before or just after the JVM has been created. See the methods [ensureJvm](#javaEnsureJvm) and [registerClient](#javaRegisterClient). See also several of the tests in the testAsyncOptions directory. | ||
# Release Notes | ||
### v0.5.0 | ||
* Support for varargs. This change is not 100% backwards compatible, but the fix is generally easy and results in more natural code. | ||
### v0.2.0 | ||
@@ -218,2 +242,6 @@ | ||
* [newProxy](#javaNewProxy) | ||
* [isJvmCreated](#javaIsJvmCreated) | ||
* [registerClient](#javaRegisterClient) | ||
* [registerClientP](#javaRegisterClientP) | ||
* [ensureJvm](#javaEnsureJvm) | ||
@@ -239,2 +267,3 @@ ## java objects | ||
java.classpath.push('commons.io.jar'); | ||
java.classpath.pathDir('lib'); | ||
@@ -506,3 +535,25 @@ <a name="javaOptions" /> | ||
thread.start(); | ||
<a name="javaisJvmCreated" /> | ||
**java.isJvmCreated()** | ||
Returns true if the JVM has been created. The JVM can only be created once. | ||
<a name="javaRegisterClient" /> | ||
**java.registerClient(before, after)** | ||
Register that a client wants to be called back immediately before and/or immediately after the JVM is created. If used, this function must be called before the JVM has been created. The before function is typically used to add to the classpath. The function may execute asynchronous operations (such as a async glob function). The after function is sometimes useful for doing one-time initialization that requires the JVM to first be initialized. If either function is unnecessary, use `null` or `undefined`. See also `registerClientP` and `ensureJvm`. See the unit tests in `testAsyncOptions` for examples. | ||
<a name="javaRegisterClientP" /> | ||
**java.registerClientP(before, after)** | ||
Like java.registerClient, but before and after are assumed to be functions returning promises. | ||
<a name="javaEnsureJvm" /> | ||
**java.ensureJvm(callback)** | ||
If the JVM has not yet been created, execute the full JVM initialization process, then call callback function when initialization is complete. If the JVM has been created, just call the callback. Note that the full initialization process includes: 1) executing all registered client *before* hooks, 2) creating the JVM, then 3) executing all registered client *after* hooks. | ||
<a name="javaObject"/> | ||
@@ -509,0 +560,0 @@ ## java object |
@@ -270,4 +270,16 @@ var java = require("../testHelpers").java; | ||
test.done(); | ||
}, | ||
"Call static method with varargs": function(test) { | ||
var Test = java.import("Test"); | ||
var str = Test.staticVarargsSync(5, java.newArray('java.lang.String', ['a', 'b', 'c'])); | ||
test.equal(str, "5abc"); | ||
str = Test.staticVarargsSync(5, 'a', 'b', 'c'); | ||
test.equal(str, "5abc"); | ||
test.done(); | ||
} | ||
}); |
@@ -59,3 +59,3 @@ | ||
"newInstance bad arg types": function(test) { | ||
java.newInstance("Test", "z", function(err, result) { | ||
java.newInstance("Test", 'a', function(err, result) { | ||
test.ok(err); | ||
@@ -69,3 +69,3 @@ test.ok(!result); | ||
test.throws(function() { | ||
java.newInstanceSync("Test", "z"); | ||
java.newInstanceSync("Test", 'a'); | ||
}); | ||
@@ -76,3 +76,3 @@ test.done(); | ||
"newInstance bad number of args": function(test) { | ||
java.newInstance("Test", 42, "z", function(err, result) { | ||
java.newInstance("Test", 42, 15, function(err, result) { | ||
test.ok(err); | ||
@@ -86,3 +86,3 @@ test.ok(!result); | ||
test.throws(function() { | ||
java.newInstanceSync("Test", 42, "z"); | ||
java.newInstanceSync("Test", 42, 15); | ||
}); | ||
@@ -112,2 +112,15 @@ test.done(); | ||
}, | ||
"newInstanceSync with varargs": function(test) { | ||
var result = java.newInstanceSync("Test", 42, java.newArray('java.lang.String', ["a", "b"])); | ||
test.ok(result); | ||
result = java.newInstanceSync("Test", 42, "a"); | ||
test.ok(result); | ||
result = java.newInstanceSync("Test", 42, "a", "b", "c"); | ||
test.ok(result); | ||
test.done(); | ||
} | ||
}); |
@@ -70,3 +70,3 @@ // testAllThreeSuffix.js | ||
var String = java.import("java.lang.String"); | ||
test.strictEqual(String.formatSync('%s--%s', java.newArray("java.lang.String", ["hello", "world"])), "hello--world"); | ||
test.strictEqual(String.formatSync('%s--%s', "hello", "world"), "hello--world"); | ||
test.done(); | ||
@@ -73,0 +73,0 @@ }, |
@@ -67,3 +67,3 @@ // testAsyncSuffixSyncDefault.js | ||
var String = java.import("java.lang.String"); | ||
test.strictEqual(String.format('%s--%s', java.newArray("java.lang.String", ["hello", "world"])), "hello--world"); | ||
test.strictEqual(String.format('%s--%s', "hello", "world"), "hello--world"); | ||
test.done(); | ||
@@ -70,0 +70,0 @@ }, |
@@ -9,8 +9,41 @@ // testDefacto.js | ||
java.asyncOptions = { | ||
syncSuffix: "Sync", | ||
asyncSuffix: "" | ||
}; | ||
module.exports = { | ||
module.exports = { | ||
launch: function(test) { | ||
test.expect(9); | ||
var api = _.functions(java); | ||
test.ok(_.includes(api, 'isJvmCreated'), 'Expected `isJvmCreated` to be present, but it is NOT.'); | ||
test.ok(!java.isJvmCreated()); | ||
java.asyncOptions = { | ||
syncSuffix: "Sync", | ||
asyncSuffix: "" | ||
}; | ||
function before(callback) { | ||
test.ok(!java.isJvmCreated()); | ||
callback(); | ||
} | ||
function after(callback) { | ||
test.ok(java.isJvmCreated()); | ||
callback(); | ||
} | ||
java.registerClient(before, after); | ||
java.registerClient(undefined, after); | ||
java.registerClient(before, undefined); | ||
java.ensureJvm(function(err) { | ||
test.ifError(err); | ||
test.ok(java.isJvmCreated()); | ||
// Verify that ensureJvm is idempotent | ||
java.ensureJvm(function(err) { | ||
test.ifError(err); | ||
test.done(); | ||
}); | ||
}); | ||
}, | ||
testAPI: function(test) { | ||
@@ -68,3 +101,3 @@ test.expect(5); | ||
var String = java.import("java.lang.String"); | ||
test.strictEqual(String.formatSync('%s--%s', java.newArray("java.lang.String", ["hello", "world"])), "hello--world"); | ||
test.strictEqual(String.formatSync('%s--%s', "hello", "world"), "hello--world"); | ||
test.done(); | ||
@@ -71,0 +104,0 @@ }, |
@@ -7,12 +7,38 @@ // testDefactoPlusPromise.js | ||
var assert = require("assert"); | ||
var _ = require('lodash'); | ||
var _ = require("lodash"); | ||
java.asyncOptions = { | ||
syncSuffix: "Sync", | ||
asyncSuffix: "", | ||
promiseSuffix: 'Promise', | ||
promisify: require('when/node').lift // https://github.com/cujojs/when | ||
}; | ||
module.exports = { | ||
launch: function(test) { | ||
test.expect(7); | ||
var api = _.functions(java); | ||
test.ok(_.includes(api, 'isJvmCreated'), 'Expected `isJvmCreated` to be present, but it is NOT.'); | ||
test.ok(!java.isJvmCreated()); | ||
module.exports = { | ||
java.asyncOptions = { | ||
syncSuffix: "Sync", | ||
asyncSuffix: "", | ||
promiseSuffix: 'Promise', | ||
promisify: require('when/node').lift // https://github.com/cujojs/when | ||
}; | ||
function before(callback) { | ||
test.ok(!java.isJvmCreated()); | ||
callback(); | ||
} | ||
function after(callback) { | ||
test.ok(java.isJvmCreated()); | ||
callback(); | ||
} | ||
java.registerClient(before, after); | ||
java.registerClient(null, after); | ||
java.registerClient(before); | ||
java.ensureJvm().done(function() { | ||
test.ok(java.isJvmCreated()); | ||
test.done(); | ||
}); | ||
}, | ||
testAPI: function(test) { | ||
@@ -70,3 +96,3 @@ test.expect(5); | ||
var String = java.import("java.lang.String"); | ||
test.strictEqual(String.formatSync('%s--%s', java.newArray("java.lang.String", ["hello", "world"])), "hello--world"); | ||
test.strictEqual(String.formatSync('%s--%s', "hello", "world"), "hello--world"); | ||
test.done(); | ||
@@ -73,0 +99,0 @@ }, |
@@ -65,3 +65,3 @@ // testDefault.js | ||
var String = java.import("java.lang.String"); | ||
test.strictEqual(String.formatSync('%s--%s', java.newArray("java.lang.String", ["hello", "world"])), "hello--world"); | ||
test.strictEqual(String.formatSync('%s--%s', "hello", "world"), "hello--world"); | ||
test.done(); | ||
@@ -68,0 +68,0 @@ }, |
@@ -8,10 +8,43 @@ // testNoAsync.js | ||
var _ = require('lodash'); | ||
var when = require('when'); | ||
java.asyncOptions = { | ||
syncSuffix: "Sync", | ||
promiseSuffix: 'Promise', | ||
promisify: require('when/node').lift // https://github.com/cujojs/when | ||
}; | ||
module.exports = { | ||
launch: function(test) { | ||
test.expect(7); | ||
var api = _.functions(java); | ||
test.ok(_.includes(api, 'isJvmCreated'), 'Expected `isJvmCreated` to be present, but it is NOT.'); | ||
test.ok(!java.isJvmCreated()); | ||
module.exports = { | ||
java.asyncOptions = { | ||
syncSuffix: "Sync", | ||
promiseSuffix: 'Promise', | ||
promisify: require('when/node').lift | ||
}; | ||
function before() { | ||
var promise = when.promise(function(resolve, reject) { | ||
test.ok(!java.isJvmCreated()); | ||
resolve(); | ||
}); | ||
return promise; | ||
} | ||
function after() { | ||
var promise = when.promise(function(resolve, reject) { | ||
test.ok(java.isJvmCreated()); | ||
resolve(); | ||
}); | ||
return promise; | ||
} | ||
java.registerClientP(before, after); | ||
java.registerClientP(null, after); | ||
java.registerClientP(before); | ||
java.ensureJvm().done(function() { | ||
test.ok(java.isJvmCreated()); | ||
test.done(); | ||
}); | ||
}, | ||
testAPI: function(test) { | ||
@@ -70,3 +103,3 @@ test.expect(6); | ||
var String = java.import("java.lang.String"); | ||
test.strictEqual(String.formatSync('%s--%s', java.newArray("java.lang.String", ["hello", "world"])), "hello--world"); | ||
test.strictEqual(String.formatSync('%s--%s', "hello", "world"), "hello--world"); | ||
test.done(); | ||
@@ -73,0 +106,0 @@ }, |
@@ -71,3 +71,3 @@ // testSyncDefaultPlusPromise.js | ||
var String = java.import("java.lang.String"); | ||
test.strictEqual(String.format('%s--%s', java.newArray("java.lang.String", ["hello", "world"])), "hello--world"); | ||
test.strictEqual(String.format('%s--%s', "hello", "world"), "hello--world"); | ||
test.done(); | ||
@@ -74,0 +74,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2623310
4
94
2559
687
4
4
+ Addedasync@0.9.0
+ Addedasync@0.9.0(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedglob@5.0.5(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedminimatch@2.0.10(transitive)
+ Addednan@1.7.0(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedwrappy@1.0.2(transitive)
- Removedglob@3.2.11(transitive)
- Removedlru-cache@2.7.3(transitive)
- Removedminimatch@0.3.0(transitive)
- Removednan@1.4.1(transitive)
- Removedsigmund@1.0.1(transitive)
Updatedglob@5.0.5
Updatednan@1.7.0