Commit 771ef01c authored by yannick legoc's avatar yannick legoc
Browse files

Reimplemented ServerConnection with Cameo by removing the state pattern.

Reimplemented corba ReadyIndicator.
parent d51c4b75
......@@ -249,11 +249,6 @@
<arg line="${idlFlags} ${idlCommonDir}/Sequences.idl" />
</exec>
<echo message="Generating ReadyIndicator.java" />
<exec executable="idl">
<arg line="${idlFlags} ${idlCommonDir}/ReadyIndicator.idl" />
</exec>
<!-- proto files -->
<echo message="Generating ServantConfiguration.java" />
<exec executable="protoc">
......
......@@ -101,14 +101,6 @@ public class LoginManager {
return makeConnection("real");
}
public boolean checkConnection(String serverId) {
return ServerConnection.getInstance(serverId).checkConnection();
}
public boolean checkConnection() {
return checkConnection("real");
}
public void logout(String serverId) {
ServerSessionManager.getInstance(serverId).logoutAll(false);
}
......
/*
* Nomad Instrument Control Software
*
* Copyright 2011 Institut Laue-Langevin
*
* Licensed under the EUPL, Version 1.1 only (the "License");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://joinup.ec.europa.eu/software/page/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package fr.ill.ics.nscclient.serverconnection;
import fr.ill.ics.nomadserver.common.ReadyIndicator;
import fr.ill.ics.nomadserver.common.ReadyIndicatorHelper;
import fr.ill.ics.nomadserver.common.ReadyIndicatorPackage.State;
import fr.ill.ics.nscclient.corbabase.CorbaNamingService;
import fr.ill.ics.nscclient.corbabase.CorbaNamingService.CORBAResolveFailureException;
/**
*
* @author caunt
*
* This class represents the state where the server is up and running and
* communicating with the client. If communication problems occur then we move
* back to the ServerConnecting state to try to reastablish communications.
*/
public class ServerConnectedAndReady extends ServerConnectionState {
private ReadyIndicator readyIndicator;
/**
* Constructor. When a ServerConnectedAndReadyState is created we need to refresh
* all the corba objects in the server (we arrive at this state either when
* we are connecting for the first time or the server has been restarted).
* @param sessionManager corba object in the server
*/
public ServerConnectedAndReady(String serverId) {
super(serverId);
//System.out.println("ServerConnectedAndReady " + serverId);
//if (!ServerDisconnected.nRestarts.containsKey(serverId)) {
ServerDisconnected.nRestarts.put(serverId, new Integer(0));
//}
}
private void retrieveReadyIndicator() {
try {
String contextName = NOMAD_SERVER_CONTEXT_NAME;
if (!serverId.equals("real")) {
contextName += serverId;
}
// test connection
org.omg.CORBA.Object readyIndicatorObject = CorbaNamingService.getInstance().resolveObject(contextName, CORE_CONTEXT_NAME, READY_INDICATOR_OBJECT_NAME);
readyIndicator = ReadyIndicatorHelper.narrow(readyIndicatorObject);
} catch (CORBAResolveFailureException e) {
// unaccessible object
} catch (org.omg.CORBA.SystemException e) {
// unaccessible object
}
}
/**
* Tests the connection with the server to ensure that it is still ok. If
* we receive a corba exception (communication problems) then we try to
* re-establish a connection by creating the ServerConnectingState.
*/
public boolean makeConnection(ServerConnection connection) {
//System.out.println("ServerConnectedAndReady " + serverId + " make connection");
retrieveReadyIndicator();
if (readyIndicator != null) {
State newState = readyIndicator.getState();
if (newState == State.STARTED) {
return true;
}
}
// Change state to try to establish another connection
connection.setState(new ServerConnecting(serverId));
return false;
}
/**
* Returns a property key associated with a message for the current state
*/
public String getStatusMessage() {
return "serverConnectedMessage";
}
public boolean checkConnection(ServerConnection connection) {
if (readyIndicator == null) {
retrieveReadyIndicator();
}
try {
State newState = readyIndicator.getState();
if (newState == State.STARTED) {
return true;
}
} catch (org.omg.CORBA.SystemException e) {
// unaccessible object
} catch (Exception e) {
// unknown error
}
return false;
}
}
\ No newline at end of file
/*
* Nomad Instrument Control Software
*
* Copyright 2011 Institut Laue-Langevin
*
* Licensed under the EUPL, Version 1.1 only (the "License");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://joinup.ec.europa.eu/software/page/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package fr.ill.ics.nscclient.serverconnection;
import fr.ill.ics.nomadserver.common.ReadyIndicator;
import fr.ill.ics.nomadserver.common.ReadyIndicatorHelper;
import fr.ill.ics.nomadserver.common.ReadyIndicatorPackage.State;
import fr.ill.ics.nscclient.corbabase.CorbaNamingService;
import fr.ill.ics.nscclient.corbabase.CorbaNamingService.CORBAResolveFailureException;
public class ServerConnecting extends ServerConnectionState {
private int retry = 0;
private static int MAX_RETRY_1 = 1;
private static int MAX_RETRY_2 = 1000;
private static int WAITING_TIME_MS = 300;
public ServerConnecting(String serverId) {
super(serverId);
//System.out.println("ServerConnecting " + serverId);
}
/**
* Try to obtain the reference to the session manager in the naming service. If this
* succeeds then make a dummy call on it to check that the reference refers to a
* true object in the server. If that is ok then move to the next state. If problems occur
* successively then try to relaunch the server.
*/
public boolean makeConnection(ServerConnection connection) {
//System.out.println("ServerConnecting " + serverId + " make connection");
try {
String contextName = NOMAD_SERVER_CONTEXT_NAME;
if (!serverId.equals("real")) {
contextName += serverId;
}
org.omg.CORBA.Object readyIndicatorObject = CorbaNamingService.getInstance().resolveObject(contextName, CORE_CONTEXT_NAME, READY_INDICATOR_OBJECT_NAME);
ReadyIndicator readyIndicator = ReadyIndicatorHelper.narrow(readyIndicatorObject);
State newState = readyIndicator.getState();
if (newState == State.STARTED) {
connection.setState(new ServerConnectedAndReady(serverId));
return false;
}
} catch (CORBAResolveFailureException e) {
} catch (org.omg.CORBA.SystemException e) {
}
try {
Thread.sleep(WAITING_TIME_MS);
} catch (InterruptedException e) {
}
retry++;
int maxRetry = 0;
if (!ServerDisconnected.nRestarts.containsKey(serverId)) {
ServerDisconnected.nRestarts.put(serverId, new Integer(0));
}
// first retry has 1 max retry because the server can be not started
if (ServerDisconnected.nRestarts.get(serverId) == 0) {
maxRetry = MAX_RETRY_1;
} else {
maxRetry = MAX_RETRY_2;
}
// Relaunch the server if communication problems persist
if (retry >= maxRetry) {
// reinitialising retry
retry = 0;
System.out.println("Server did not respond in the expected time (" + maxRetry * WAITING_TIME_MS / 1000 + "s)");
connection.setState(new ServerDisconnected(serverId));
}
return false;
}
/**
* Returns a property key associated with a message for the current state
*/
public String getStatusMessage() {
return "serverConnectingMessage";
}
public boolean checkConnection(ServerConnection connection) {
return false;
}
}
\ No newline at end of file
......@@ -21,6 +21,8 @@ package fr.ill.ics.nscclient.serverconnection;
import java.util.HashMap;
import java.util.Map;
import fr.ill.ics.cameo.Application;
/**
* @author caunt
* Singleton class used to maintain a connection with the server. Implements a state pattern
......@@ -29,7 +31,7 @@ import java.util.Map;
public class ServerConnection {
private String serverId;
private ServerConnectionState connectionState = null;
private String statusMessage;
private static Map<String, ServerConnection> instances = new HashMap<String, ServerConnection>();
......@@ -38,7 +40,9 @@ public class ServerConnection {
* a connection is established or a new server launched.
*/
private ServerConnection(String serverId) {
connectionState = new ServerConnecting(serverId);
this.serverId = serverId;
statusMessage = "serverConnectionInitMessage";
}
public static ServerConnection getInstance(String serverId) {
......@@ -57,26 +61,40 @@ public class ServerConnection {
* @param serverId
*/
public boolean makeConnection() {
return connectionState.makeConnection(this);
}
/**
* Set the current state of connection
* @param connectionState
*/
public void setState(ServerConnectionState connectionState) {
this.connectionState = connectionState;
Application.Instance serverInstance = ServerInstance.getInstance().getApplicationInstance(serverId);
if (serverInstance == null || !serverInstance.exists()) {
System.out.println("The server does not exist");
serverInstance = ServerInstance.getInstance().startApplication(serverId);
if (serverInstance == null || !serverInstance.exists()) {
return false;
}
}
statusMessage = "serverConnectingMessage";
// Manage state in case the server exists but is shutting down or processing error.
System.out.println("Waiting for the state RUNNING of " + serverInstance);
serverInstance.waitFor(Application.State.RUNNING);
statusMessage = "serverConnectedMessage";
System.out.println("Server is running");
return true;
}
/**
* Returns a string message for the current state
*/
public String getStatusMessage() {
return connectionState.getStatusMessage();
}
public boolean checkConnection() {
return connectionState.checkConnection(this);
return statusMessage;
}
}
\ No newline at end of file
/*
* Nomad Instrument Control Software
*
* Copyright 2011 Institut Laue-Langevin
*
* Licensed under the EUPL, Version 1.1 only (the "License");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://joinup.ec.europa.eu/software/page/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package fr.ill.ics.nscclient.serverconnection;
/**
*
* @author caunt
* Abstract class representing the state of the connection with the server. Sub classes
* implement the various stages of connection.
*/
public abstract class ServerConnectionState {
public static String NOMAD_SERVER_CONTEXT_NAME = "NomadServer";
public static String CORE_CONTEXT_NAME = "Core";
public static String READY_INDICATOR_OBJECT_NAME = "readyIndicator";
protected String serverId;
public ServerConnectionState(String serverId) {
this.serverId = serverId;
}
/**
* Perform necessary actions to maintain a connection with the server. This depends
* on the particular state implemented.
* @param connection
* @return boolean indicating whether connection is ok
*/
public abstract boolean makeConnection(ServerConnection connection);
/**
* Returns a string message for the current state
*/
public abstract String getStatusMessage();
/**
* Returns true if the connection is ok.
*/
public abstract boolean checkConnection(ServerConnection connection);
}
\ No newline at end of file
/*
* Nomad Instrument Control Software
*
* Copyright 2011 Institut Laue-Langevin
*
* Licensed under the EUPL, Version 1.1 only (the "License");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://joinup.ec.europa.eu/software/page/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package fr.ill.ics.nscclient.serverconnection;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import fr.ill.ics.cameo.Application;
import fr.ill.ics.cameo.ConnectionTimeout;
import fr.ill.ics.cameo.Server;
import fr.ill.ics.util.ConfigManager;
/**
*
* @author caunt
*
* This class represents the state where the server is disconnected. A
* new server is launched (executes a script in the users's working
* directory) then waits for 5 seconds to give the server time to start.
* It then moves to the next state to test the connection.
*/
public class ServerDisconnected extends ServerConnectionState {
private long launchTime;
public static Map<String, Integer> nRestarts = new HashMap<String, Integer>();
static class StreamThread extends Thread {
private InputStream in;
public StreamThread(InputStream in) {
this.in = in;
}
public void run() {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String s;
try {
while ((s = br.readLine()) != null) {
//System.out.println("read = " + s);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Constructor. Launch script to start the server - this is
* different depending on the platform.
*/
public ServerDisconnected(String serverId) {
super(serverId);
//System.out.println("ServerDisconnected " + serverId);
if (!nRestarts.containsKey(serverId)) {
nRestarts.put(serverId, new Integer(0));
}
if (nRestarts.get(serverId) >= 1) {
System.out.println("Unable to restart the server " + serverId);
if (serverId.equals("real")) {
System.exit(0);
} else {
return;
}
}
System.out.println("Starting nomad server with Cameo");
// Get the server endpoint.
String nomadServerEndpoint = ConfigManager.getInstance().getNomadServerEndpoint();
// connect to the server
Server server = new Server(nomadServerEndpoint);
// start nomad server
try {
Application.Instance nomad = server.start("ns");
if (nomad.exists()) {
System.out.println("Started " + nomad);
}
} catch (ConnectionTimeout e) {
System.err.println("Timeout while starting nomad server");
}
server.terminate();
Integer value = nRestarts.get(serverId);
value++;
nRestarts.put(serverId, value);
}
/**
* Determines whether the script was launched more than 5 seconds ago. This
* gives the server time to start and create corba objects in the naming
* service.
*/
public boolean makeConnection(ServerConnection connection) {
//System.out.println("ServerDisconnected " + serverId + " make connection");
// Wait for 2 seconds after starting server
if (System.currentTimeMillis() - launchTime > 2000) {
// Move to next state to connect to server
connection.setState(new ServerConnecting(serverId));
}
return false;
}
/**
* Returns a property key associated with a message for the current state
*/
public String getStatusMessage() {
return "serverConnectionInitMessage";
}
public boolean checkConnection(ServerConnection connection) {
return false;
}
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import java.util.List;
import fr.ill.ics.bridge.command.CommandZoneWrapper;
import fr.ill.ics.cameo.Application;
import fr.ill.ics.cameo.Application.Instance;
import fr.ill.ics.cameo.ConnectionTimeout;
import fr.ill.ics.cameo.Server;
import fr.ill.ics.util.ConfigManager;
......@@ -38,6 +39,8 @@ public class ServerInstance {
// Connect nomad server.
Application.Instance nomad = null;
System.out.println("server id " + serverId);
// Do not connect to the same application if it is simulated.
if (!serverId.equals(CommandZoneWrapper.SERVER_ID)) {
......@@ -73,4 +76,21 @@ public class ServerInstance {
return nomad;
}
public Instance startApplication(String serverId) {
try {
// Do not start the same application if it is simulated.
if (!serverId.equals(CommandZoneWrapper.SERVER_ID)) {
return server.start("nssim");
}
return server.start("ns");
} catch (ConnectionTimeout e) {
System.err.println("Timeout while starting nomad server");
}
return null;
}
}