如何同时远程连接多个Glassfish 4+实例?

时间:2014-10-07 10:41:12

标签: java java-ee authentication glassfish glassfish-4

我正在寻找一种从独立的基于Swing的客户端(JDK7-SE)同时连接到Glassfish 4+(JDK7-EE)的多个实例的方法。我通过以下方式成功连接到单个实例:

这是初始背景的构建:

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();
}

JNDI使用远程接口完成查找:

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

我正在使用驻留在服务器上的自定义JDBC域并且工作正常。在客户端,我将以下login.conf传递给初始上下文(参见上面的代码):

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

身份验证目前由ProgrammaticLogin完成:

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

所有这一切都很好!但是在独立客户端启动期间,我希望同时连接到位于不同服务器上的另一个EJB。

由于ProgrammaticLogin与初始上下文没有直接关系,我不确定如何使用不同的凭据(例如用户名/密码)同时登录两个不同的Glassfish服务器?有人有什么想法吗?

2 个答案:

答案 0 :(得分:1)

对该问题的进一步研究发现,初始上下文只能在每个JVM的基础上设置一次。因此,只要使用System.setProperty(String,String)设置ORB并实例化初始上下文对象,SerialInitContextFactory的设计就让您不再更改所选端点。

因此,我决定在不同的JVM中连接到不同的Glassfish服务器。最后,我最终得到了一个单独的项目,用于管理与应用程序服务器的连接,并通过RMI与主项目进行通信。

目前我的项目包括两个我想要同时连接的不同EE项目,即“LawSuiteEE”和“MgmtCenterEE”。这是处理连接的新项目:

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);
    }

接口ILawSuiteEE用于此项目与主项目之间的RMI(第二个接口IMgmtCenterEE完全相同):

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;

}

适当的实施:

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);
}

}

在主项目中,我将连接以下内容:

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.");
        }
    }

}

答案 1 :(得分:0)

如何使用多个线程,每个服务器一个? 您可以为所需的每个连接创建一个新线程,在每个线程上设置InitialContext并使用不同的凭据连接ProgrammaticLogin。

您可以通过实现Runnable接口创建自己的“自定义”线程,并为其创建接收凭证和/或InitialContext对象的构造函数。 简单的例子:

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
         }
      }

然后调用它:

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();

当然这是一个非常简单的例子,它可能不适合您的确切需求,但我认为这是您需要的良好开端。由于每个Context和登录凭据都将在不同的线程上运行,因此它们将拥有自己独立的执行堆栈,您不应遇到任何并发问题(两个线程访问同一对象)。 但是,您应该很好地理解并发性和线程,否则可能会遇到不同的异常,由于使用多个线程而难以调试。

汤姆。