Using a NodeJS Library from Java using Rhino and Rhinodo - javascript

I'm trying to use the Javascript library multilang-extract-comments from within a Java application, so I decided to use Rhino as the Javascript engine and Rhinodo to interface between Rhino and NodeJS. However, I cannot figure out how to actually use Rhinodo. I've looked at the code for the projects that use Rhinodo (maven plugins for brunch, jshint, and recess), but I find the code to be pretty arcane. I've tried implementing code like the following (with some editing for my application):
rhinodoBuilder
.destDir(rhinodoDestDir)
.moduleFactory(nodeModuleProvider)
.consoleFactory(wrappingConsoleFactory)
.env(env)
.build(new BaseFunction() {
#Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
Scriptable brunch = (Scriptable) ScriptableObject.callMethod(cx, scope, "require",
new Object[]{Context.javaToJS("brunch", scope)});
Scriptable options = cx.newObject(scope);
ScriptableObject.putProperty(options, "minify", minify);
System.setProperty("user.dir", userDir.getAbsolutePath());
ScriptRuntime.doTopCall(ScriptableObject.getTypedProperty(brunch, "build", Function.class),
cx, scope, thisObj, new Object[]{
options,
new BaseFunction() {
#Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
return Undefined.instance;
}
}
});
return Undefined.instance;
}
});
(from the brunch maven plugin)
However, this code doesn't work for me. I either get an error in trying to find my Javascript library or, when I use a library it should be able to find (I used fs as an example), I get a NullPointerException. Could someone please tell me what I'm missing here?
Note: both Rhinodo and the maven plugins that use it can be found in MuleSoft's GitHub Repositories

I didn't find a way for this to work out. However, if anyone else is determined to use Rhinodo in this way, part of the problem was that I wasn't actually using a NodeModuleProvider. In order to try and load my required Node modules, I used code similar to the following:
// create a module provider for all the node modules in META-INF
String prefix = "META-INF/node_modules/";
String[] moduleNames = {"amodule","anothermodule","modulethethird"};
ArrayList<NodeModuleImpl> moduleList = new ArrayList<NodeModuleImpl>();
for (String module: moduleNames) {
moduleList.add(NodeModuleImplBuilder.fromFolder(prefix+module));
}
NodeModuleProviderImpl nmp = new NodeModuleProviderImpl(moduleList);
I then used the NodeModuleProvider in the RhinodoBuilder.moduleFactory() method (which you can see used in my code snippet in the question). However, be warned that you may have to solve the problem which I couldn't: using imported modules later from Rhino.
In the end I decided that it made much more sense to call my javascript as a command using exec, so I recommend that anyone else who undertakes something similar just use that solution.

Related

Minify JavaScript using the Google Closure Compiler and Gradle

I have a small Java web application being built with Gradle that includes some custom vanilla JavaScript. I'd like to minify the custom JS code using Google Closure Compiler.
All of the documentation for the Closure Compiler seems to be around using the CLI or the JSON API for minifying JS. I'd much prefer to call the Java API directly from Gradle in e.g. a Copy task.
I'd like to avoid
Node solutions
Calling out to the CLI and using java -jar
HTTP calls to the JSON API
This example is out-of-date and does not reflect the most recent Java API. This question is several years old, though most of the API calls seem similar to the current Java API.
Has anyone else minified JavaScript from Gradle using the Google Closure Compiler Java API directly?
I have a working solution:
task processWebapp(type: Copy) {
from('src/main/webapp') {
include "**/*"
}
eachFile {
if (it.sourceName.endsWith('.js') && !it.sourceName.endsWith('.min.js')) {
it.exclude()
Reader reader = it.file.newReader()
String source = ""
try {
source = reader.readLines().join("\r\n")
} finally {
reader.close()
}
com.google.javascript.jscomp.Compiler compiler = new com.google.javascript.jscomp.Compiler(System.err)
CompilerOptions options = new CompilerOptions()
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(
options)
SourceFile extern = SourceFile.fromCode("externs.js", "")
SourceFile input = SourceFile.fromCode(it.sourceName, source)
compiler.compile(extern, input, options)
String transpiled = compiler.toSource()
def directoryPath = it.relativePath - it.sourceName
File theDir = new File("build/resources/main/${directoryPath}")
if (!theDir.exists()) {
theDir.mkdirs()
}
PrintWriter writer = new PrintWriter("build/resources/main/${it.relativeSourcePath}", "UTF-8")
try {
writer.println(transpiled)
} finally {
writer.close()
}
}
}
destinationDir = file('build/resources/main')
}
This task copies everything from src/main/webapp to build/resources/main while transpiling (minifying) all files ending in .js (but not ending in .min.js) en-route. Gradle then packages and embeds those resources in the resulting jar.
Hope this helps someone else out there using Google Closure Compiler and Gradle.

cordova plugin x509store

I have to develop an app with cordova targeting mainly Windows platform.
In this app, I have to manipulate the certification store. Long story short answer, I have to do a cordova plugin (or maybe an activeX trick).
I made a windows runtime component in C#, as explained here, to use X509Store (as I need Windows).
I used visual studio 2015 to make a windows runtime component project (I tried universal windows and 8.1). It works, I can call C# methods in my .js.
But the problem is: a windows runtime component project doesn't have the namespace System.Security.Cryptography.X509Certificates. So I can't access to X509Store.
As a workaround, I made a Class library (.NetCore, .dll) which call X509Store and return strings, at least to show the certificate (json stringify). A classic class library can also access to x509store but it makes target error when I reference it in this windows runtime component project. (a portable/universal dll project doesn't have X509Store neither). My .netcore dll works, I tried it in a Console Application (.NetCore) project and it showed all my certificates. But when I call it from the cordova app (cordova app -> plugin -> runtime -> .netcore dll) it's empty (no certificate found, and the current user is undefined). I think it's because the execution context is not the same (webapp vs console app). And i don't think it's a good solution (which doesn't even work).
So, how can I access to the certification store (of the windows user) in a windows runtime component ? As I don't think it's possible with javascript.
Thanks
P.S: I can provide some source code if needed
EDIT:
I forgot that there is an assembly conflict in the runtime project with the .netcore dll which I solved by referencing the right dll in plugin.xml file (System.Runtime.dll etc ..) as I didn't manage to solve it in visual studio
//script inside cordova, called after device ready
signatureplugin.getAllCertNames(function(a) { }, function(a) { }, 0);
//signatureplugin.js
var exec = require('cordova/exec');
module.exports = {
getAllCertNames: function(successCallback, errorCallback, args) {
exec(successCallback, errorCallback, "SignaturePlugin", "getAllCertNames", [args]);
}
};
//signaturepluginProxy.js
module.exports = {
getAllCertNames: function(successCallback, errorCallback, args) {
var res = SignerVerifier.PluginRT.getAllCertNames();
for (var i = 0, len = res.length; i < len; i++) {
alert(res[i]);
}
}
};
require("cordova/exec/proxy").add("SignaturePlugin", module.exports);
//windows runtime component
using CertStore;
namespace SignerVerifier
{
public sealed class PluginRT
{
public static string[] getAllCertNames()
{
var certStore = new StoreManager();
var res = certStore.getAllCertificates();
return res;
}
}
}
//.NetCore dll
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using Newtonsoft.Json;
using System;
namespace CertStore
{
public class StoreManager
{
private X509Store store;
public StoreManager()
{
store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
}
public string[] getAllCertificates()
{
List<string> res = new List<string>();
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates;
foreach (var cert in certificates)
{
res.Add(JsonConvert.SerializeObject(cert));
}
store.Dispose();
return res.ToArray();
}
}
}
If i do a javascript blank app project + Windows Runtime Component project (projects from "universal", I don't have "Windows Store" and I use windows 10) then add the .netcore dll i got the conflict which lead to an exception:
System.IO.FileLoadException: Could not load file or assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
(in cordova I prevent this exception by referencing System.Runtime.dll, etc ..., from the nuget package NETStandard.Library.1.6.0 used in .netcore)
I must miss something. .NetCore dll doesn't seem compatible, but the windows runtime project target .NetCore
EDIT 2: (solved)
vcsjones's answer = workaround useless (and no problem from the previous edit).
BUT in anycase there is a security issue, and I have to check "Shared User Certificates" in Capabilities in the appxmanifest
WinRT does certificate management different from the Desktop and Core framework. For WinRT, you would use the Windows.Security namespace.
You can open and manage the certificate store using the Windows.Security.Cryptography.Certificates.CertificateStore class.

Writing commonjs module and load it using require (not using relative path)

What is best pratice for referencing a local commonjs module without using a relative path as below?
var custMod= require(‘customModule’);
custMod(true);
custMod.save(‘foo’);
Is there any reference for building a module like this?
If I wrote module like below, getting undefined when I call custMode.save(12);
module.exports = customModule;function customModule(mode) {
var mode = 1;
return {
save: function (value) {
console.log(mode, value)
},
get: function (id) {
console.log(mode, id)
}
}
You can add a path for require to check using
require.paths.push('/my/path');
or
require.main.paths.push('/my/path');
Depending on your node version.
Then if customModule.js exists at /my/path/customModule.js, you can just use
require('customModule');
Do note though, you'd need to do this on every module that you intend to use this method on.
I wish node made this easier to be honest. One possibility:
project_root
`--node_modules
|--npm-module-1
|--npm-module-2
|--... (etc)
`--lib
|--my-module.js
`--my-other-module.js
With the above you can then type require('lib/my-module') from anywhere in your project. (Just make sure and never install an npm module named lib :) Another possibility:
project_root
|--node_modules
| |--npm-module-1
| |--npm-module-2
| `--... (etc)
`--lib
`--node_modules
|--my-module.js
`--my-other-module.js
With the above you can then type require('my-module'), but only for any files under project_root/lib/.
An advantage of the former approach is that require('lib/my-module') makes it super easy at a glance to tell which modules are local to the project. However the latter is less typing.

Using Google Closure's "compiler.jar" in Google App Engine

I am trying to use Google Closure Compiler API from my Java code. Function compile() receives the original source code, and returns the compiled source code in a String.
This code will run in Google App Engine, but when I deploy and run it I get an "server error". Without calling function below, I don't get any errors. At time of compilation I get warning "compiler.jar will not be available on server's classpath". Compiler.jar is the library I downloaded from Closure Compiler project website.
Any ideas of how to go around this?
Thanks a million,
import com.google.javascript.jscomp.*;
public static String compile(String code)
{
com.google.javascript.jscomp.Compiler.setLoggingLevel(Level.INFO);
com.google.javascript.jscomp.Compiler compiler = new com.google.javascript.jscomp.Compiler();
CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
JSSourceFile js = JSSourceFile.fromCode("input.js", code);
WarningLevel.QUIET.setOptionsForWarningLevel(options);
compiler.compile(null, js, options);
return compiler.toSource();
}
try this:
import com.google.javascript.jscomp.*;
public static String compile(String code)
{
com.google.javascript.jscomp.Compiler.setLoggingLevel(Level.INFO);
com.google.javascript.jscomp.Compiler compiler = new
com.google.javascript.jscomp.Compiler();
CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
JSSourceFile js = JSSourceFile.fromCode("input.js", code);
List<SourceFile> list = new ArrayList<SourceFile>();
list.add(js);
WarningLevel.QUIET.setOptionsForWarningLevel(options);
compiler.compile(new ArrayList<SourceFile>(), list, options);
return compiler.toSource();
}
At time of compilation I get warning "compiler.jar will not be available on server's classpath".
You might have to move the compiler.jar to your WEB-INF/lib.
this is likely the cause for the 500: if you don't deploy the compiler.jar as part of your webapp, your servlet (or whatever) will fail with a NoClassDefFoundError.
If you haven't done so you need to disable threading in the compiler to run on app engine: see "disableThreads" in Compiler.java
http://code.google.com/p/closure-compiler/source/search?q=Compiler.java&origq=Compiler.java&btnG=Search+Trunk
Normally, the compiler spawns a new thread to be sure that it has a larger than standard stack.

NodeJS and Javascript (requirejs) dependency injection

I am currently using requirejs to manage module js/css dependencies.
I'd like to discover the possibilities of having node do this via a centralized config file.
So instead of manually doing something like
define([
'jquery'
'lib/somelib'
'views/someview']
within each module.
I'd have node inject the dependencies ie
require('moduleA').setDeps('jquery','lib/somelib','views/someview')
Anyway, I'm interested in any projects looking at dependency injection for node.
thanks
I've come up with a solution for dependency injection. It's called injectr, and it uses node's vm library and replaces the default functionality of require when including a file.
So in your tests, instead of require('libToTest'), use injectr('libToTest' { 'libToMock' : myMock });. I wanted to make the interface as straightforward as possible, with no need to alter the code being tested. I think it works quite well.
It's just worth noting that injectr files are relative to the working directory, unlike require which is relative to the current file, but that shouldn't matter because it's only used in tests.
I've previously toyed with the idea of providing an alternate require to make a form of dependency injection available in Node.js.
Module code
For example, suppose you have following statements in code.js:
fs = require('fs');
console.log(fs.readFileSync('text.txt', 'utf-8'));
If you run this code with node code.js, then it will print out the contents of text.txt.
Injector code
However, suppose you have a test module that wants to abstract away the file system.
Your test file test.js could then look like this:
var origRequire = global.require;
global.require = dependencyLookup;
require('./code.js');
function dependencyLookup (file) {
switch (file) {
case 'fs': return { readFileSync: function () { return "test contents"; } };
default: return origRequire(file);
}
}
If you now run node test.js, it will print out "test contents", even though it includes code.js.
I've also written a module to accomplish this, it's called rewire. Just use npm install rewire and then:
var rewire = require("rewire"),
myModule = rewire("./path/to/myModule.js"); // exactly like require()
// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123
// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
readFile: function (path, encoding, cb) {
cb(null, "Success!");
}
});
myModule.readSomethingFromFileSystem(function (err, data) {
console.log(data); // = Success!
});
I've been inspired by Nathan MacInnes's injectr but used a different approach. I don't use vm to eval the test-module, in fact I use node's own require. This way your module behaves exactly like using require() (except your modifications). Also debugging is fully supported.

Categories