Can any one help on embedding node-red in java process

I am new to Node.js/Node-RED. we have a requirement where we need to embed node-RED modules under java process.
From some blog i could understand that J2V8 make it possible to run Node.js and JVM in a single process. Similarly is it possible to Embed Node-RED modules in java process.

Is it possible to achieve this? if yes can some one please provide more information on this.

1 Like

Hi,

Can any one please provide any kind suggestion on this query

Hi,
https://nodered.org/docs/embedding
:white_check_mark:

Hi,

Thanks for the link, i have already gone through the above link but sorry i am not very clear with that.

I am new to node-red so please excuse me if I ask some thing which is not relevant.

To be more specific below are my queries/understanding

  1. We have Java web application and our own UI to create flows(using some built-in Java, Javascript and Python)services .

  2. new requirement says can we embed node-red core nodes(like Inject node, debug node etc) into our application. I dont want to create flows and allow node-red runtime api to call them.
    3 From documentation I could understand that node-red runs on node.js, and J2V8 make it possible to run Node.js and JVM in a single process.
    a. so is it possible to take only node-red nodes(like Inject node, debug node) and embed into our application?
    For example instead of writing to implement node-red inject node functionality can i copy 20-inject.js and 20-inject.html(Inject node files) files to my
    app directory and make use of it?

  3. With help of "Embedding into an existing app" topic i have tried some option. please find my code

    Main.java: 
    
    public static void main(String[] args) throws IOException {
     
     	final NodeJS nodeJS = NodeJS.createNodeJS();
     	nodeJS.exec(new File(".//src//myFirstModule.js"));
     	while(nodeJS.isRunning()) {
     		nodeJS.handleMessage();
     	}
     	nodeJS.release();
    
     }
    

    myFirstModule.js

    console.log('import MyFirstModule!');
    var http = require('http');
    console.log('imported http'+http);
    var express = require("express");
    var RED = require("node-red");

    var app = express();
    app.use("/",express.static("public"));
    var server = http.createServer(app);

    var settings = {
    httpAdminRoot:"/red",
    httpNodeRoot: "/api",
    userDir:"/home/nol/.nodered/",
    functionGlobalContext: { } // enables global context
    };

RED.init(settings);

// Serve the editor UI from /red
app.use(settings.httpAdminRoot,RED.httpAdmin);

// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot,RED.httpNode);

server.listen(8000);

// Start the runtime
RED.start();

console.log('RED node!'+RED);

I am getting exception module.js:341: Error: Cannot find module 'express' and Error: Cannot find module 'node-red'

locally I have done npm install of both node-red(npm install -g --unsafe-perm node-red) and express(npm install express)

I have explicitly given path of express.js(installed express module path) after that i could resolve "module.js:341: Error: Cannot find module 'express'

But still i am getting Error: Cannot find module 'node-red'

Well, first of all I have to tell you that I am not an expert.

I'm not sure I understand what you want to do ...

We are talking about "taking only" the functionality of some NR nodes and implementing them in an external FBP application that is capable of running node.js?

If you are interested in the logic of the node, so as not to rewrite code, you have hundreds of thousands of nodejs scripts in npm.org

If you are interested in the node logic plus the FBP (inputs-outputs) functionalities, you need the runtime.

Anyway, I understand that there may be a confusion with the term "embed in another application". It is understood that you are talking about "embedding in another application node.js" and always as a whole app and not loose nodes.

But I reiterate that I do not know if I have understood the problem well.
regards

I've just been trying to do a similar thing to the O/P.

@shwetha says they ran npm install but the error suggests that it's not installed where the J2V8 runtime is looking for them. I ran a (non-root) npm install from within the directory where I installed Node RED (.../node-red/), leaving me with a sub directory inside it called node_modules/ containing approx 700 modules.

My own code to launch it from J2V8 is pretty straight forward, the core is pretty similar to the O/P's (for context, I'm launching it in its own thread, from within a framework that invokes start() and stop() at appropriate times in its lifecycle), and I'm using the standard red.js script via a relative path (relative to the current working directory of my Java process):

  private static String SCRIPT_FILE = "../node-red/red.js";

  private ExecutorService nodeExecutorService;
  private NodeJS nodeJs;

  @Override
  public void start() {
    ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(
        "NodeJS Thread %s").build();
    nodeExecutorService = Executors.newFixedThreadPool(1, threadFactory);
    NodeExecutorThread nodeExecutorThread = new NodeExecutorThread();
    nodeExecutorService.execute(nodeExecutorThread);
    super.start();
  }

  class NodeExecutorThread implements Runnable {
    @Override
    public void run() {
      runNodeJs();
    }
      
    protected void runNodeJs() {
      NodeJS nodeJs = NodeJS.createNodeJS();
      try {
        V8 v8 = nodeJs.getRuntime();
        registerJsObject(v8); // add a Java object and methods callable from Javascript
        nodeJs.exec(new File(SCRIPT_FILE));
        while (nodeJs.isRunning()) {
          nodeJs.handleMessage();
        }
        nodeJs.release();
      } catch (Exception e) {
        logger.error("NodeExecutor encountered error", e);
      } finally {
        if (nodeJs != null) {
          nodeJs.release();
        }
      }
    }
  }

  @Override
  public void stop() {
    if (nodeJs != null) {
      nodeJs.release();
    }
    nodeJs = null;
    if (nodeExecutorService != null) {
      nodeExecutorService.shutdown();
      try {
        if (nodeExecutorService.awaitTermination(800,  TimeUnit.MILLISECONDS) ) {
          nodeExecutorService.shutdownNow();
        }
      } catch (InterruptedException e) {
        nodeExecutorService.shutdownNow();
      }
    }
    nodeExecutorService = null;
    super.stop();
  }

The first significant problem I encountered is that the JVM was crashing in a call from the native J2V8 code.

A bit of diagnosis lead to identifying that the 10-mqtt.js node causes something to break. You'll need to remove that from your Node-RED installation, for now.