2014-10-07 57 views
2

我正在尋找一種方法,可以從獨立的基於Swing的客戶端(JDK7-SE)同時連接到Glassfish 4+(JDK7-EE)的多個實例。我順利地通過以下方式連接到一個實例:如何同時遠程連接到多個Glassfish 4+實例?

這是初始上下文的建設:

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

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使用遠程接口完成我正在使用駐留在服務器上的自定義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服務器?有人有任何想法?

+0

您的問題說你想連接到多個服務器,但你的賞金聲明說你正在尋找連接到EJB:有區別。你真的在找什麼? – kolossus 2014-10-12 17:53:39

+0

我在不同的服務器上部署了不同的EJB。我想同時從獨立的Java SE客戶端連接到兩個服務器/ EJB。通過連接Glassfish,我的意思是通過JNDI查找在該服務器上訪問EJB。 – salocinx 2014-10-13 06:39:00

+0

EJB是安全的,所以我需要一個可以在服務器上進行身份驗證的地方(正在使用我的自定義JDBC領域)。但只要JVM正在運行,它就只能與一臺服務器一起工作,因爲屬性被設置爲JVM(System.setProperty(x,y))。 – salocinx 2014-10-13 06:41:56

回答

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

}

在主親ject我要與以下連接:

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

} 
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和登錄憑證將在不同的線程上運行,因此它們將擁有自己的獨立執行堆棧,並且不應該遇到任何併發問題(兩個線程訪問同一個對象)。 但是,你應該對併發和線程有一個很好的理解,否則你可能遇到不同的異常,由於使用多線程而難以調試。

湯姆。