I wrote an QuickFix program and created a config file.. Now, when I'm running my application, nothing happens.. So I ask me, how I can recognize if the connection (my program is of type initiator) is established or not.
I've added to the methods that I implement from the Application interface
void fromAdmin(Message message, SessionID sessionId)
void fromApp(Message message, SessionID sessionId)
void onCreate(SessionID sessionId)
void onLogon(SessionID sessionId)
void onLogout(SessionID sessionId)
void toAdmin(Message message, SessionID sessionId)
void toApp(Message message, SessionID sessionId)
a System.out and a logger.info, but nothing of them fires something.
If a connection established, the methods onCreate and onLogon are invoked, or?! So the System.outs in these methods should write something..
But are there any other opportunitys to check wheter the connection established, respectively the config file is valid.
P.S.: I use the SessionSettings to read the config File in.. But I can't find a method in the SessionSettings like validateConfigFile() or something like that.
Has your config file got FileLogPath=log?
Then to debug you look at the FIX messages log, usually in the bin/debug/log directory, which is where it would be for the above config file. If it's not a security risk then paste your config file here please. Also, yes add the System.Out to your Application interface. Here's mine:
public void FromApp(Message msg, SessionID s)
{
Console.WriteLine("IN: " + msg.ToString());
You can download Banzai application which is an accpetor/iniciator with grafic interface. You can iniciate a session, and send/receive messages from your app.
Main class you need in your Iniciator
public class Banzai {
private static final CountDownLatch shutdownLatch = new CountDownLatch(1);
/** enable logging for this class */
private static Logger log = LoggerFactory.getLogger(Banzai.class);
private static Banzai banzai;
private boolean initiatorStarted = false;
private Initiator initiator = null;
private JFrame frame = null;
public Banzai(String[] args) throws Exception {
InputStream inputStream = null;
if (args.length == 0) {
inputStream = new BufferedInputStream(new FileInputStream(new File("config/banzai.cfg")));
} else if (args.length == 1) {
inputStream = new FileInputStream(args[0]);
}
if (inputStream == null) {
System.out.println("usage: " + Banzai.class.getName() + " [configFile].");
return;
}
SessionSettings settings = new SessionSettings(inputStream);
inputStream.close();
boolean logHeartbeats = Boolean.valueOf(System.getProperty("logHeartbeats", "true")).booleanValue();
OrderTableModel orderTableModel = new OrderTableModel();
ExecutionTableModel executionTableModel = new ExecutionTableModel();
BanzaiApplication application = new BanzaiApplication(orderTableModel, executionTableModel);
MessageStoreFactory messageStoreFactory = new FileStoreFactory(settings);
LogFactory logFactory = new ScreenLogFactory(true, true, true, logHeartbeats);
MessageFactory messageFactory = new DefaultMessageFactory();
initiator = new SocketInitiator(application, messageStoreFactory, settings, logFactory, messageFactory);
frame = new BanzaiFrame(orderTableModel, executionTableModel, application);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public synchronized void logon() {
if (!initiatorStarted) {
try {
initiator.start();
initiatorStarted = true;
} catch (Exception e) {
log.error("Logon failed", e);
}
} else {
Iterator<SessionID> sessionIds = initiator.getSessions().iterator();
while (sessionIds.hasNext()) {
SessionID sessionId = (SessionID) sessionIds.next();
Session.lookupSession(sessionId).logon();
}
}
}
public void logout() {
Iterator<SessionID> sessionIds = initiator.getSessions().iterator();
while (sessionIds.hasNext()) {
SessionID sessionId = (SessionID) sessionIds.next();
Session.lookupSession(sessionId).logout("user requested");
}
}
public void stop() {
shutdownLatch.countDown();
}
public JFrame getFrame() {
return frame;
}
public static Banzai get() {
return banzai;
}
public static void main(String args[]) throws Exception {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
log.info(e.getMessage(), e);
}
banzai = new Banzai(args);
if (!System.getProperties().containsKey("openfix")) {
banzai.logon();
}
shutdownLatch.await();
}
}
NOTE: The information in your .settings has to match with the information you have in your code.
After you start both codes you will start to receive logon, and heartbeat messages.
Related
Context
I made a Java application, and need to run two instances of that application, synchronizing some of their attributes via socket each time there's some change. To communicate those changes, Serializable objects are sent through a socket using ObjectStreams (input and output) using read/writeUTF() for an identifier, and read/writeObject() and flush(). The app is the exact same .jar, run twice with some changes like having different ports and ip (if necessary).
Problem
I noticed that objects of some of my classes (e.g. Notification) were sent and received without any troubles, but objects from another class (RegisteredUsers) weren't sent (or received) properly. So I ran some tests to send objects between the two apps and found that the object is being sent and isn't null, it's attribute (a HashMap<String,User>) is also being sent and isn't null, but is always empty.
So I decided to scale it down to what the problem was exactly: I'm trying to write an object through a Stream, and read it in a different process of the same .jar, and with most classes it seems to work, but it doesn't with one.
There seems to be something I'm missing or don't understand about this serialization process, if the object is written and read during the execution of the same process it works, but not if this object is read on another instance of the same app. I even added a HashMap to Notification with the same creation process, but it still works, I really don't get it, what am I missing?
Code
I have taken some code from the bigger app and trimmed it down to the basic problem if anyone wants to test it. To reproduce the errors, run Main1, which will create the two files with an object persisted in each one (one with a Notification object and the other with a RegisteredUsers object) and shows their information, then Main2, which reads them from the files and shows their information, and the problem should be printed. That being that reg3's HashMap is empty and thus neither of the Users are registered.
Main1
public class Main1 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg1 = new RegisteredUsers();
RegisteredUsers reg2 = new RegisteredUsers();
reg1.register("Name1", "127.0.0.1");
reg1.register("Name2", "127.0.0.1");
try {
pers.writeReg(reg1, regFile);
} catch (IOException e) {
System.out.println("Error writing registry.");
}
try {
reg2 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
System.out.println("Original registry: ");
System.out.println(reg1.isRegistered("Name1") + " " + reg1.isRegistered("Name2"));
System.out.println("Registry read from file: ");
System.out.println(reg2.isRegistered("Name1") + " " + reg2.isRegistered("Name2"));
Notification noti1 = new Notification("Name", "127.0.0.1");
Notification noti2 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
pers.writeNotif(noti1, notificationFile);
} catch (IOException e) {
System.out.println("Error writing notification.");
}
try {
noti2 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Original notification: ");
System.out.println(noti1.getAttributes().get(0) + " " + noti1.getAttributes().get(1));
System.out.println(noti1.getMap());
System.out.println("Notification read from file: ");
System.out.println(noti2.getAttributes().get(0) + " " + noti2.getAttributes().get(1));
System.out.println(noti2.getMap());
}
}
Main2
public class Main2 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg3 = new RegisteredUsers();
try {
reg3 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
if (reg3 == null) {
System.out.println("reg3 is null");
}
if (reg3.getMap() == null)
System.out.println("reg3 has a null map");
if (reg3.getMap().isEmpty())
System.out.println("reg3 has an empty map");
System.out.println("Registry read from file on another process: ");
System.out.println(reg3.isRegistered("Name1") + " " + reg3.isRegistered("Name2"));
Notification noti3 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
noti3 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Notification read from file on another process: ");
System.out.println(noti3.getAttributes().get(0) + " " + noti3.getAttributes().get(1));
System.out.println(noti3.getMap());
}
}
A Class to persist the objects in the files:
public class Persistence {
public void writeReg(RegisteredUsers regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public RegisteredUsers readReg(String file) throws IOException {
RegisteredUsers regus = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
regus = (RegisteredUsers) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return regus;
}
public void writeNotif(Notification regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public Notification readNotif(String file) throws IOException {
Notification notif = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
notif = (Notification) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return notif;
}
}
RegisteredUsers
public class RegisteredUsers implements Serializable {
private static HashMap<String, User> users;
public RegisteredUsers() {
users = new HashMap<String, User>();
}
public HashMap<String, User> getMap() {
return users;
}
public boolean isRegistered(String name) {
User us = users.get(name);
return us != null;
}
public void register(String name, String ip) {
users.put(name, new User(name, ip, false));
}
}
Notification
public class Notification implements Serializable {
private ArrayList<String> attributes;
private HashMap<String, User> map = new HashMap<>();
public Notification() {
}
public Notification(String name, String ip) {
attributes = new ArrayList<String>();
attributes.add(0, name);
attributes.add(1, ip);
map.put(ip, new User(name, ip, false));
}
public ArrayList<String> getAttributes() {
return attributes;
}
public HashMap<String, User> getMap() {
return map;
}
}
User
public class User implements Serializable {
private String name;
private String ip;
private boolean connection_state;
public User(String name, String ip, boolean connection_state) {
this.name = name;
this.ip = ip;
this.connection_state = connection_state;
}
}
In java static fields are implicitly transient, and transient fields are not serialized.
If you modify the RegisterdUsers to
public class RegisteredUsers implements Serializable {
private HashMap<String, User> users; // static modifier is removed
...
}
The serialization will work.
My scheme: ajax long polling to Tomcat. Tomcat executes selenium "operations".
Im trying to execute selenium scenario from tomcat.
Its working ok but i need to get logs back to js client.
Javascript client partially receives messages from server when selenium working.
Inside some selenium operations im using Thread.sleep(). Maybe mistakes because of this ?
Please tell me why messages partially received (i think) by client
Here is ServerInfoLogger. BaseLogger outputs messages to console and file
public class ServerInfoLogger extends BaseLogger {
public ServerSession clientServerSession;
protected void logToClient(String message) {
super.log(message);
sendMessage(message);
}
// Server.serverSession and Server.clientServerSession not null but messages partially not received by client
private void sendMessage(String message) {
// send message to client
if (Server.serverSession!=null && Server.clientServerSession!=null) {
Server.clientServerSession.deliver(Server.serverSession, "/message", message);
} else {
System.err.println("Server error. Server.serverSession=" + Server.serverSession + " clientServerSession=" + clientServerSession);
}
}
}
Here is selenium scenario
public class Task extends ServerInfoLogger {
public static boolean datesAvailable = false;
private TaskParser parser = new TaskParser();
protected ArrayList<Step> steps = new ArrayList<>();
private WebDriver webDriver;
protected int currentStepIndex = 0;
protected Step currentStep;
private WebDriverFactory webDriverFactory = new WebDriverFactory();
private int currentTryout = 1;
private int maxTryouts = 40;
public Task(ServerSession clientServerSession, String taskData) {
this.clientServerSession = clientServerSession;
logToClient("new task"); // client always receives this message
steps = parser.parse(taskData);
logToClient("steps parsed. total: "+steps.size()); // client always receives this message
start();
}
protected void start() {
createWebDriver();
startStep();
}
protected void startStep() {
currentStep = steps.get(currentStepIndex);
currentStep.setWebDriver(webDriver);
currentStep.clientServerSession = clientServerSession;
boolean stepComplete = false;
try {
stepComplete = currentStep.start();
} catch (StepException e) {
logToClient(e.getMessage()+" step id: "+e.getStepId());
e.printStackTrace();
}
log("step complete = "+stepComplete);
if (stepComplete) {
onStepComplete();
} else {
onStepError();
}
}
private void onStepError() {
currentTryout++;
if (currentTryout > maxTryouts) {
destroyWebDriver();
logToClient("Max tryouts reached"); // client never receives this message
} else {
logToClient("Step not complete. Restarting task. currentTryout=" + currentTryout); // client partially receives this message
restart();
}
}
private void onStepComplete() {
currentStepIndex++;
if (currentStepIndex < steps.size()) {
startStep();
} else {
destroyWebDriver();
taskComplete();
}
}
private void destroyWebDriver() {
webDriver.quit();
webDriver = null;
}
private void taskComplete() {
logToClient("Task complete !!!"); // client **never** receives this message
TaskEvent taskEvent = new TaskEvent(TaskEvent.TASK_COMPLETE);
EventDispatcher.getInstance().dispatchEvent(taskEvent);
}
public void restart() {
logToClient("Task restart");
try {
setTimeout(Application.baseOperationWaitSecondsUntil);
new SwitchToDefaultContentOperation().execute();
} catch(OperationException exception) {
logToClient("Cannot get default content"); // client partially receives this message
}
currentStepIndex = 0;
startStep();
}
private void setTimeout(int seconds) {
webDriver.manage().timeouts().implicitlyWait(seconds, TimeUnit.SECONDS);
}
private void createWebDriver() {
webDriver = webDriverFactory.getDriver(BrowserType.CHROME).getDriver();
}
public int getCurrentStepIndex() {
return currentStepIndex;
}
}
Here is creation of logger
private void createLogger() {
Date currentDate = new Date();
String logFilePostfix = currentDate.getMonth()+"_"+currentDate.getDate()+"-"+currentDate.getHours()+"_"+currentDate.getMinutes()+"_"+currentDate.getSeconds();
logger = Logger.getLogger(appName);
logger.setUseParentHandlers(false);
FileHandler fh;
SimplestFormatter formatter = new SimplestFormatter();
try {
fh = new FileHandler("C:\\consultant\\logs\\log_"+logFilePostfix+".txt");
logger.addHandler(fh);
fh.setFormatter(formatter);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Selenium operation with Thread.sleep()
public class SwitchToMainFrameOperation extends BaseOperation {
private WebElement mainIframe;
private WebDriverWait wait;
#Override
public boolean execute() throws OperationException {
switchToRoot();
sleepThread();
log("switchToMainIFrame by xPath "+Page.getMainIframeXPath()); // log to console and file
wait = new WebDriverWait(webDriver, Application.baseOperationWaitSecondsUntil);
try {
mainIframe = wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(Page.getMainIframeXPath())));
webDriver.switchTo().frame(mainIframe);
log("main frame switch OK"); // log to console and file
} catch(StaleElementReferenceException exception) {
log("main frame switch error. StaleElementReferenceException - trying again"); // log to console and file
wait = null;
sleepThread();
execute();
}
return true;
}
private void switchToRoot() {
log("switch to root");
webDriver.switchTo().defaultContent();
}
private void sleepThread() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I am trying to implement a JMXclient to monitor remote JVM. I obtain the mbeanserver connection from a main method and pass it to a thread which search for memory usage. Problem is when I do this i get an error saying "The client has been closed". But if I run the program without threads it works perfectly.
public class ESBMonitor {
private static TreeSet<ObjectName> mbeansNames = null;
public static void main(String[] args) throws IOException {
RemoteConnector.defaultConnector();
MBeanServerConnection remote = RemoteConnector.getRemote();
//MemoryExtractor.getMemoryInfo();
MemoryExtractor memoryExtractor = new MemoryExtractor();
memoryExtractor.start();
RemoteConnector.closeConnection();
}
}
public class RemoteConnector {
private static MBeanServerConnection remote = null;
private static JMXConnector connector = null;
private static final Logger logger= LogManager.getLogger(RemoteConnector.class);
public static void defaultConnector() {
try {
JMXServiceURL target = new JMXServiceURL
("service:jmx:rmi://localhost:11111/jndi/rmi://localhost:9999/jmxrmi");
//for passing credentials for password
Map<String, String[]> env = new HashMap<String, String[]>();
String[] credentials = {"admin", "admin"};
env.put(JMXConnector.CREDENTIALS, credentials);
connector = JMXConnectorFactory.connect(target, env);
remote = connector.getMBeanServerConnection();
logger.info("MbeanServer connection obtained");
} catch (MalformedURLException e) {
logger.error(e.getStackTrace());
} catch (IOException e) {
logger.error(e.getStackTrace());
}
}
public static MBeanServerConnection getRemote() {
return remote;
}
public static synchronized Object getMbeanAttribute(ObjectName bean, String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException {
return remote.getAttribute(bean,attribute);
}
}
public class MemoryExtractor extends Thread{
final static Logger logger = Logger.getLogger(MemoryExtractor.class);
private static MBeanInfo memoryInfo;
private static ObjectName bean = null;
private static double MEMORY = 0.05;
private static long TIMEOUT = 3000;
public static void getMemoryInfo() {
try {
bean = new ObjectName("java.lang:type=Memory");
checkWarningUsage();
} catch (MalformedObjectNameException e) {
logger.error("MemoryExtractor.java:25 " + e.getMessage());
}
}
public static boolean checkWarningUsage() {
try {
logger.info("MemoryExtractor.java:46 Acessing memory details");
CompositeData memoryUsage = (CompositeData) RemoteConnector.getMbeanAttribute(bean,"HeapMemoryUsage");
} catch (Exception e) {
logger.error("MemoryExtractor.java:58 " + e.getMessage());
}
return false;
}
public void run(){
while (true){
getMemoryInfo();
}
}
}
No matter I synchronize or not problem will still be there.
Stack trace
java.io.IOException: The client has been closed.
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.restart(ClientCommunicatorAdmin.java:94)
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.gotIOException(ClientCommunicatorAdmin.java:54)
at javax.management.remote.rmi.RMIConnector$RMIClientCommunicatorAdmin.gotIOException(RMIConnector.java:1474)
at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.getAttribute(RMIConnector.java:910)
at org.wso2.connector.RemoteConnector.getMbeanAttribute(RemoteConnector.java:55)
at org.wso2.jvmDetails.MemoryExtractor.checkWarningUsage(MemoryExtractor.java:47)
at org.wso2.jvmDetails.MemoryExtractor.run(MemoryExtractor.java:79)
You are caching the reference to the JMXConnector as a static in your RemoteConnector class, so there's only ever one connection. As soon as the first thread closes that singleton connection, the next time any other thread attempts to call something it will fail because you've already closed the connection at that point.
If you want to have multiple threads, then either you should close the connection when all threads have finished, or have one connection per thread.
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);
}
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.
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 ?
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.");
}
}
}
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.
I am trying to create a continuous thread where a server recieves/sends messages from a client however when I try to check for a next element it gets stuck:
public void run()
{
try
{
try
{
ArrayList<Socket> connections = parent.getConnections();
in = new Scanner(socket.getInputStream());
while(true)
{
if(in.hasNextLine()) // Gets stuck here
{
String message = in.nextLine();
System.out.println("Client said " + message);
}
}
}
finally
{
socket.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
How do I make the loop not get stuck at the specified point
Assuming you want to be able to deal with 'lines', I'd probably start with something like this:
public class SocketReader implements Runnable {
private final InputStream stream;
private final Queue<String> destination;
private volatile boolean active = true;
private SocketReader(InputStream stream, Queue<String> destination) {
this.stream = stream;
this.destination = destination;
}
public static SocketReader getReader(Socket toRead, Queue<String> destination) throws IOException {
return new SocketReader(toRead.getInputStream(), destination);
}
public void shutdown() {
active = false;
}
public void run() {
while(active) {
if (stream.hasNextLine() && active) {
final String line = stream.nextLine;
destination.add(line);
}
}
try {
stream.close();
} catch (IOException e) {
// Log somewhere
}
}
}
Drop this into its own thread (or as part of a thread or executor pool, really), and you've made the rest of your application non-blocking with regards to this code. EXPECT this to block while waiting for updates from stream.hasNextLine(). You can even supply a BlockingQueue if you don't wish to actively poll a queue, but are handling updates in some other fashion.
You can then do something like this for output:
public class QueuedPrinter implements Runnable {
private final Queue<String> input;
private final PrintStream destination;
private volatile boolean active;
public QueuedPrinter(Queue<String> input, PrintStream destination) {
this.input = input;
this.destination = destination;
}
public void shutdown() {
active = false;
}
public void run() {
while(active) {
final String line = input.poll();
if (line != null && active) {
destination.println(line);
}
}
}
}
Please note that I haven't tested this, and you may have to adjust things slightly for other Checked exceptions. You probably need to put in additional error-checking code (null-handling comes to mind). Also, this isn't completely threadsafe, but is likely to be 'good enough' for most uses.