/*
* Copyright 2011 Uwe Krueger.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mandelsoft.mand.srv.tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import com.mandelsoft.mand.srv.CalcRequest;
import com.mandelsoft.mand.srv.RequestProcessor;
/**
*
* @author Uwe Krüger
*/
public class Client implements Constants, Runnable {
private int MAX=30*60;
private InetAddress host;
private int port=PORT;
private Socket socket;
private DataInputStream is;
private DataOutputStream os;
private RequestProcessor proc;
private long cnt=0;
private int version;
private int servertimeout;
private boolean log=false;
private boolean verb=true;
public Client(String[] args) throws IOException
{
int c=0;
int n=1;
while (args.length>c&&args[c].charAt(0)=='-') {
String arg=args[c++];
for (int i=1; i<arg.length(); i++) {
char opt;
switch (opt=arg.charAt(i)) {
case 'h': // host
if (args.length>c) {
try {
host=InetAddress.getByName(args[c++]);
}
catch (UnknownHostException ex) {
throw new IllegalArgumentException("unknown host");
}
}
else throw new IllegalArgumentException("host missing");
break;
case 'p': // port
if (args.length>c) {
try {
port=Integer.parseInt(args[c++]);
}
catch (Exception ex) {
throw new IllegalArgumentException("port number expected");
}
}
else throw new IllegalArgumentException("port missing");
break;
case 'n': // processors
if (args.length>c) {
try {
n=Integer.parseInt(args[c++]);
}
catch (Exception ex) {
throw new IllegalArgumentException("number for processors expected");
}
}
else throw new IllegalArgumentException("number of processors missing");
break;
default:
throw new IllegalArgumentException("illegal option '"+opt+"'");
}
}
}
setup(n);
}
public Client(InetAddress host, int port, int n)
{
this.host=host;
this.port=port;
setup(n);
}
private void setup(int n)
{
proc=new RequestProcessor(n);
}
private void log(String m)
{
if (log) System.out.println(m);
}
private void verb(String m)
{
if (verb) System.out.println(m);
}
public void run()
{ int sleep;
do {
CalcRequest req;
try {
log("next action");
req=proc.getNextAction();
log(req==null?"-> get next":"-> send answer");
}
catch (InterruptedException ex) {
return;
}
sleep=10;
do {
if (connect()) {
if (req==null) {
req=getRequest();
if (req!=null) {
sleep=0;
proc.sendRequest(req);
}
else {
sleep=servertimeout;
}
}
else {
if (sendAnswer(req)) sleep=0;
else sleep=servertimeout;
}
}
if (sleep>0) {
if (req!=null || (req=proc.testAndGetAnswer())==null) {
try {
verb("sleep "+sleep);
Thread.sleep(sleep*1000);
sleep=sleep*2;
if (sleep>MAX) sleep=MAX;
}
catch (InterruptedException ex) {
}
}
if (req!=null) verb("continue with "+req.getReqId());
}
}
while (sleep>0);
}
while (true);
}
private CalcRequest getRequest()
{ String stat;
try {
os.writeInt(REQ_GET);
stat=is.readUTF();
log("get "+stat);
if (stat.equals(Constants.FOUND)) {
CalcRequest req=new CalcRequest();
req.read(is,false);
verb("got "+req.getReqId());
cnt++;
// if (cnt%1000==0) {
// verb("request lost "+req.getReqId());
// return null;
// }
return req;
}
else {
if (stat.equals(Constants.EMPTY)) {
servertimeout=is.readInt();
}
}
}
catch (IOException io) {
System.out.println("get failed: "+io);
close();
}
return null;
}
private boolean sendAnswer(CalcRequest req)
{ String stat;
try {
verb("send answer "+req.getReqId());
os.writeInt(REQ_ANS);
req.write(os,false);
stat=is.readUTF();
return true;
}
catch (IOException io) {
System.out.println("put failed: "+io);
close();
return false;
}
}
private boolean connect()
{
if (socket!=null) {
if (socket.isInputShutdown() || socket.isOutputShutdown()) {
close("shutdown");
}
if (socket!=null && !socket.isConnected()) close("not connected");
if (socket!=null && socket.isClosed()) close("closed");
}
if (socket==null) {
try {
if (host==null) host=InetAddress.getLocalHost();
verb("connecting "+host+" ...");
socket=new Socket(host, port);
try {
is=new DataInputStream(socket.getInputStream());
os=new DataOutputStream(socket.getOutputStream());
os.writeUTF(PROTOCOL);
os.writeInt(VERSION);
String stat=is.readUTF();
if (!stat.equals(OK)) {
System.out.println(stat);
System.exit(1);
}
version=is.readInt();
log("protocol version is "+version);
}
catch (IOException ex) {
if (is!=null) is.close();
is=null;
os=null;
return false;
}
}
catch (IOException io) {
System.err.println("connect failed: "+io);
is=null;
os=null;
return false;
}
}
return true;
}
private void close()
{
close("");
}
private void close(String msg)
{
verb("close "+msg);
if (is!=null) try {
is.close();
}
catch (IOException ex) {
}
if (os!=null) try {
os.close();
}
catch (IOException ex) {
}
is=null;
os=null;
socket=null;
}
static public void main(String[] args)
{
try {
new Client(args).run();
}
catch (Exception ex) {
System.err.println("Fail: "+ex);
}
}
}