我正在寻找一种从独立的基于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服务器?有人有什么想法吗?
答案 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和登录凭据都将在不同的线程上运行,因此它们将拥有自己独立的执行堆栈,您不应遇到任何并发问题(两个线程访问同一对象)。 但是,您应该很好地理解并发性和线程,否则可能会遇到不同的异常,由于使用多个线程而难以调试。
汤姆。