/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.communication.internal.connection;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.StringTokenizer;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.constants.TimingConstantsServer;
import org.eclipse.jubula.tools.internal.exception.JBVersionException;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.internal.utils.TimeUtil;
import org.eclipse.jubula.tools.internal.version.IVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Constants for the state of a connection
*
* @author BREDEX GmbH
* @created 20.09.2004
*/
public class ConnectionState {
/** Separator of messages*/
public static final String SEPARATOR = "/"; //$NON-NLS-1$
/** The index of the state */
public static final int STATE_INDEX = 0;
/** The index of the version number */
public static final int VERSION_INDEX = 1;
/** unconnected, e.g. server did not send a state */
public static final int UNKNOWN = -1;
/** server is ready */
public static final int SERVER_OK = 0;
/** server is busy */
public static final int SERVER_BUSY = 1;
/** Version of client and AutStarter are different */
public static final int VERSION_ERROR = 2;
/** the string used by servers to determine the type of a client */
public static final String CLIENT_TYPE_REQUEST = "ClientTypeRequest"; //$NON-NLS-1$
/** client type that requires exclusive access to the server */
public static final String CLIENT_TYPE_SINGLE = "ClientType.Exclusive"; //$NON-NLS-1$
/** client type that represents an AUT wishing to register with an AUT Agent */
public static final String CLIENT_TYPE_AUT = "ClientType.Aut"; //$NON-NLS-1$
/** client type that represents an instance of "autrun" */
public static final String CLIENT_TYPE_AUTRUN = "ClientType.autrun"; //$NON-NLS-1$
/** client type that represents an external request to shut down the server */
public static final String CLIENT_TYPE_COMMAND_SHUTDOWN = "ClientType.Command.ShutDown"; //$NON-NLS-1$
/** the logger */
private static final Logger LOG = LoggerFactory
.getLogger(ConnectionState.class);
/**
* Utility constructor
*/
private ConnectionState() {
// Utility constructor
}
/**
* Parses the state out of the given message
* @param message the message to parse
* @return the state or UNKNOWN-state if any error occurred
*/
public static int parseState(String message) {
StringTokenizer tok = new StringTokenizer(message, SEPARATOR);
try {
if (tok.hasMoreTokens()) {
String stateStr = tok.nextToken();
return Integer.parseInt(stateStr);
}
} catch (NumberFormatException e) {
return UNKNOWN;
}
return UNKNOWN;
}
/**
* Parses the version number out of the given message
* @param message the message to parse
* @return the version number or -1 if any error occurred
*/
public static int parseVersion(String message) {
StringTokenizer tok = new StringTokenizer(message, SEPARATOR);
final int index = VERSION_INDEX + 1;
if (tok.countTokens() < index) {
return -1;
}
String versionStr = StringConstants.EMPTY;
for (int i = 0; i < index; i++) {
if (tok.hasMoreTokens()) {
versionStr = tok.nextToken();
}
}
try {
return Integer.parseInt(versionStr);
} catch (NumberFormatException e) {
return -1;
}
}
/**
* Waits for a "client type" request from the server and responds to that
* request.
*
* @param waitForServer
* The maximum amount of time (in milliseconds) to wait for the
* request from the server.
* @param inputReader
* Reader for the input stream from which the request is
* expected.
* @param inputStream
* The input stream from which the request is expected.
* @param outputStream
* The printer to use for sending the response.
* @param response
* The response to send, if the expected request is received.
* @return <code>true</code> if the expected request is received in good.
* Otherwise <code>false</code>.
* @throws JBVersionException
* in case of a version error between client and server.
* @throws IOException
* in case of an I/O error.
*/
public static boolean respondToTypeRequest(long waitForServer,
BufferedReader inputReader, InputStream inputStream,
PrintStream outputStream, String response)
throws JBVersionException, IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("waiting for server's 'client type request' with timeout: " //$NON-NLS-1$
+ String.valueOf(waitForServer));
}
long waitTime = 0;
boolean success = false;
while (!success && (waitTime <= waitForServer)) {
if (inputStream.available() > 0) {
String clientVersionLine = inputReader.readLine();
success = true;
final int protocolVersion = Integer.parseInt(String.valueOf(
IVersion.JB_PROTOCOL_MAJOR_VERSION.intValue()));
int clientVersion = ConnectionState
.parseVersion(clientVersionLine);
if (clientVersion != protocolVersion) {
throw new JBVersionException(
"Version error between Client and Server! Client version: " //$NON-NLS-1$
+ clientVersion + " Server Version: " //$NON-NLS-1$
+ protocolVersion,
MessageIDs.E_VERSION_ERROR);
}
if (clientVersionLine != null) {
clientVersionLine = clientVersionLine.substring(0,
clientVersionLine
.indexOf(ConnectionState.SEPARATOR));
}
if (ConnectionState.CLIENT_TYPE_REQUEST
.equals(clientVersionLine)) {
LOG.debug("sending response: " + response); //$NON-NLS-1$
outputStream.println(response);
outputStream.flush();
} else {
if (LOG.isWarnEnabled()) {
StringBuffer errBuf = new StringBuffer();
errBuf.append("Received invalid request from server. Expected '") //$NON-NLS-1$
.append(ConnectionState.CLIENT_TYPE_REQUEST)
.append("' but received '").append(clientVersionLine) //$NON-NLS-1$
.append("'."); //$NON-NLS-1$
LOG.warn(errBuf.toString());
}
}
} else {
/*
* Do nothing in case of interrupted exception. We may end up
* waiting a bit longer for a response, but that shouldn't be a
* problem.
*/
waitTime += TimeUtil.delay(TimingConstantsServer
.POLLING_DELAY_AUT_REGISTER);
}
}
if (!success) {
LOG.error("Did not receive expected request from server."); //$NON-NLS-1$
}
return success;
}
}