49723

How to remotely connect to multiple Glassfish 4+ instances simultaneously?

I am looking for a way to connect to multiple instances of Glassfish 4+ (JDK7-EE) simultaneously from a stand-alone Swing-based client (JDK7-SE). I successfully connect to a single instance by the following way:

That's the construction of the initial context:

private void connect(String address, String port) { System.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory"); System.setProperty("com.sun.corba.ee.transport.ORBTCPTimeouts", "500:30000:20:"+Integer.MAX_VALUE); System.setProperty("com.sun.corba.ee.transport.ORBTCPConnectTimeouts", "250:90000:100:"+Integer.MAX_VALUE); System.setProperty("com.sun.corba.ee.transport.ORBWaitForResponseTimeout", "300000"); System.setProperty("java.security.auth.login.config", new File("login.conf").getAbsolutePath()); System.setProperty("org.omg.CORBA.ORBInitialHost", address); System.setProperty("org.omg.CORBA.ORBInitialPort", port); InitialContext context = new InitialContext(); }

Look-ups are done by JNDI using a remote interface:

context.lookup("java:global/LawSuiteEE/LawSuiteEE-ejb/GlobalsFacade!ch.lawsuite.control.GlobalsFacadeRemote");

I am using a custom JDBC realm that resides on the server and works fine. On the client side I pass the following login.conf to the initial context (see code above):

default { com.sun.enterprise.security.auth.login.ClientPasswordLoginModule required debug=true; };

Authentication is currently done by ProgrammaticLogin:

private void login(String username, char[] password) { ProgrammaticLogin plogin = new ProgrammaticLogin(); plogin.login(username, password); }

<strong>All of this is working fine! But during startup of the stand-alone client, I want to simultaneously connect to another EJB located on a different server.</strong>

Since ProgrammaticLogin has no direct relation to the initial context, I am not sure how to login to two different Glassfish servers simulteneously with different credentials (e.g. username/password) ? Someone any ideas ?

Answer1:

Further examination of the issue has uncovered, that the initial context can only be set once on a per JVM basis. So as soon as the ORB is set up by using System.setProperty(String, String) and the inital context object is instantiated, the design of the SerialInitContextFactory let's you no more change the selected endpoint(s).

Therefore I decide to connect within different JVMs to the different Glassfish servers. So finally I ended up with a separate project that manages the connections to the application server and communicates by RMI with the main project.

Currently my project consists of two different EE projects to which I want connect simultaneously, namely "LawSuiteEE" and "MgmtCenterEE". Here's the new project that handles the connections:

public static void main(String args[]) { try { if(args.length==2) { if(args[1].equals("LawSuiteEE")) { ILawSuiteEE stub = (ILawSuiteEE) UnicastRemoteObject.exportObject(new LawSuiteEE(), 0); Registry registry = LocateRegistry.createRegistry(Integer.parseInt(args[0])); registry.bind("LawSuiteEE", stub); } else if(args[1].equals("MgmtCenterEE")) { ILawSuiteEE stub = (ILawSuiteEE) UnicastRemoteObject.exportObject(new MgmtCenterEE(), 0); Registry registry = LocateRegistry.createRegistry(Integer.parseInt(args[0])); registry.bind("MgmtCenterEE", stub); } else { throw new NumberFormatException(); } Logger.getLogger(RemoteContext.class.getName()).log(Level.INFO, "Remote context service is listening on port "+args[0]+" for incoming requests delegating to "+args[1]+"."); System.out.println("SIGNAL[READY]"); } else { throw new NumberFormatException(); } } catch (RemoteException ex) { System.exit(1); } catch (AlreadyBoundException ex) { System.exit(2); } catch(NumberFormatException ex) { System.exit(3); }

The interface ILawSuiteEE is used for RMI between this and the main project (the second interface IMgmtCenterEE is quite the same):

public interface ILawSuiteEE extends IConcurrentDatastore { void connect(String address, String port) throws RemoteException; void disconnect() throws RemoteException; boolean login(String username, char[] password) throws RemoteException; }

The appropriate implementation:

public class LawSuiteEE implements ILawSuiteEE { private InitialContext context; private ProgrammaticLogin login; @Override public void connect(String address, String port) throws RemoteException { if(context==null) { try { System.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory"); System.setProperty("com.sun.corba.ee.transport.ORBTCPTimeouts", "500:30000:20:"+Integer.MAX_VALUE); System.setProperty("com.sun.corba.ee.transport.ORBTCPConnectTimeouts", "250:90000:100:"+Integer.MAX_VALUE); System.setProperty("com.sun.corba.ee.transport.ORBWaitForResponseTimeout", "300000"); System.setProperty("java.security.auth.login.config", new File("login.conf").getAbsolutePath()); System.setProperty("org.omg.CORBA.ORBInitialHost", address); System.setProperty("org.omg.CORBA.ORBInitialPort", Integer.toString(port)); Logger.getLogger(RemoteDatastore.class.getName()).log(Level.INFO, "Try to connect to application server at "+System.getProperty("org.omg.CORBA.ORBInitialHost")+":"+System.getProperty("org.omg.CORBA.ORBInitialPort")+" ..."); context = new InitialContext(); } catch (NamingException ex) { throw new RemoteException(ex.getMessage()); } } } @Override public void disconnect() throws RemoteException { if(context!=null) { try { context.close(); Logger.getLogger(LawSuiteEE.class.getName()).log(Level.INFO, "Server context successfully closed."); } catch (NamingException ex) { Logger.getLogger(LawSuiteEE.class.getName()).log(Level.SEVERE, "Couldn't close server context."); } finally { this.facades.clear(); this.services.clear(); this.context=null; } } } @Override public boolean login(String username, char[] password) throws RemoteException { login = new ProgrammaticLogin(); return login.login(username, password); }

}

In the main project I'm going to connect with the following:

public class LawSuiteDatastore extends Thread implements ILawSuiteEE { private int port; private int trials; private boolean ready; private Process process; private ILawSuiteEE stub; public LawSuiteDatastore() { this.setName("K+: Remote-Datastore-Connection"); this.port = RemoteDatastoreService.cport++; } @Override public void run() { try { Tools.log(RemoteDatastoreService.class, Level.INFO, "Starting RMI registry on port "+port+" for connecting to LawSuiteEE server instance."); this.process = Runtime.getRuntime().exec(new String[] {"java", "-jar", Context.getWorkingDirectory()+"/lib/LawSuiteSX.jar", Integer.toString(port), "LawSuiteEE"}); //<editor-fold defaultstate="collapsed" desc="Redirect Error Stream"> new Thread(new Runnable() { @Override public void run() { try{ try(DataInputStream in = new DataInputStream(process.getErrorStream())) { BufferedReader br = new BufferedReader(new InputStreamReader(in)); String line; while((line=br.readLine())!=null) { Tools.log(RemoteDatastoreService.class, Level.SEVERE, line); } } } catch(Exception ex){ Tools.log(MgmtCenterDatastore.class, Level.SEVERE, ex.getMessage()); } } }).start(); //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Redirect Output Stream"> new Thread(new Runnable() { @Override public void run() { try{ try(DataInputStream in = new DataInputStream(process.getInputStream())) { BufferedReader br = new BufferedReader(new InputStreamReader(in)); String line; while((line=br.readLine())!=null) { if(line.contains("SIGNAL[READY]")) { ready=true; } Tools.log(RemoteDatastoreService.class, Level.INFO, line); } } } catch(Exception ex){ Tools.log(MgmtCenterDatastore.class, Level.SEVERE, ex.getMessage()); } } }).start(); //</editor-fold> // keep thread alive as long process is alive if(process.waitFor()>0) { // port was already bound if(process.exitValue()==2) { // try it with a different port and start over again if(trials<3) { process = null; port = ++RemoteDatastoreService.cport; trials++; if(trials<3) { start(); } } } } } catch (IOException ex) { Tools.log(RemoteDatastoreService.class, Level.SEVERE, ex.getMessage()); } catch (InterruptedException ex) { Tools.log(RemoteDatastoreService.class, Level.SEVERE, ex.getMessage()); } } public boolean isReady() { return ready; } public int getTrials() { return trials; } @Override public void connect(RemoteDatastore datastore) throws RemoteException { try { Tools.log(RemoteDatastoreService.class, Level.INFO, "Locating RMI registry on port "+port+" for connecting to LawSuiteEE server instance."); Registry registry = LocateRegistry.getRegistry(port); stub = (ILawSuiteEE)registry.lookup("LawSuiteEE"); stub.connect(datastore); } catch (NotBoundException ex) { Logger.getLogger(RemoteDatastoreService.class.getName()).log(Level.SEVERE, null, ex); } } @Override public void disconnect() throws RemoteException { if(process!=null && stub!=null) { stub.disconnect(); process.destroy(); } else { throw new RemoteException("Remote RMI server is not ready."); } } @Override public boolean login(String username, char[] password) throws RemoteException { if(process!=null && stub!=null) { return stub.login(username, password); } else { throw new RemoteException("Remote RMI server is not ready."); } } }

Answer2:

How about using multiple threads, one for each server? You can create a new thread for each connection you need, set up the InitialContext on each thread and connect with the ProgrammaticLogin with different credentials.

You can create your own "custom" thread by implementing the Runnable interface, and create a constructor for it that receives the credentials and/or InitialContext object. Simple example:

public class MyThread implements Runnable { private ProgrammaticLogin plogin; private string user; private char[] pass; public MyThread(String username, char[] password,InitialContext context) { this.user = username; this.pass = password; this.plogin = new ProgrammaticLogin(); //add more code here if needed } public void run() { //insert code here when thread will run } }

and invoke it thus:

Runnable thread1 = new MyThread("my user1","my pass1",ContextObject1); Runnable thread2 = new MyThread("my user2","my pass2",ContextObject2); new Thread(thread1).start(); new Thread(thread2).start();

Of course this is a very simple example and it might not be suitable for your exact needs, but i think it is a good start for what you need. Since each Context and login credentials will run on a different thread they will have their own separate execution stack and you should not experience any concurrency issues (two threads accessing the same object). However, you should have a good understanding of concurrency and threads otherwise you might run into different exceptions, that are a bit harder to debug due to using multiple threads.

Tom.

Recommend

  • Setting the cameras focus in ios7 xcode. opencv
  • Workaround for TextField bug in FP 10.3.183.5 and 10.3.183.7
  • Xcode 10: Compilation stopped by errors in other files
  • nservicebus deleting subscription record after inserting it?
  • Multiple lines automatically-resizeable UITextView
  • Should C++ programmers use std::flush frequently? [duplicate]
  • Looking for a number with specific conditions in python
  • Is there any reason to declare optional parameters in an interface?
  • Class not found using namespace
  • Set null to property in mvvm WPF when nothing is filled in textbox
  • Arduino Uno + ESP8266 reading server's response
  • Best way to handle .NET json [1,2,“three”]
  • arduino python interface with multiple variables
  • Using stanford parser to parse Chinese
  • phpseclib asn1 encoding structure
  • How to implement laravel function Crypt::encrypt() in Objective C?
  • Python 3 non-blocking read with pySerial (Cannot get pySerial's “in_waiting” property to work)
  • Good tutorial + reference for Emacs search and replace? [closed]
  • Adding to or updating an entity in a foreach loop takes too long time before calling SaveChanges()?
  • R's coreNLP::initCoreNLP() throws java.lang.OutOfMemoryError
  • Serialize HashMap as root element with Simple
  • Create an multidimensional array from a database table
  • Serial Communication between Arduino and Python, issue of using hexidecimal values
  • How do we set maximum_bad_records when loading a Bigquery table from dataflow?
  • Checking if the Faye server exists before running it for my Rails app
  • how to change api_token column in token guard
  • How can we prepend rows to a react native list-view?
  • Can I use AllJoyn Framework for Wifi Direct in iOS?
  • jQuery Orbit - How to make a Random Slideshow?
  • Silverlight DependencyProperty.SetCurrentValue Equivalent
  • What and where is mdimport
  • Does it make sense to call System.gc() and Thread.sleep() when working on Bitmaps?
  • Needing to do .toArray() to get output of mongodb .find() on key name not value
  • Different response to non-authenticated users and AJAX calls
  • Get object from AWS S3 as a stream
  • Arrow is showed instead of the material design version hamburger icon. Why doesn't syncState in
  • Invalid access key error using credentials redeemed from an amazon open id token
  • Data Validation Drop Down Box Arrow Disappearing
  • How to get Windows thread pool to call class member function?
  • sending mail using smtp is too slow