/*
* XCTrack - XContest Live Tracking client for J2ME devices
* Copyright (C) 2009 Petr Chromec <petr@xcontest.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.xcontest.live;
import java.util.Timer;
import java.util.Vector;
import org.xcontest.live.message.RequestOpen;
import org.xcontest.live.message.RequestOpenContinue;
import org.xcontest.live.message.RequestTrackPart;
import org.xcontest.live.message.ResponseOpenOk;
import org.xcontest.live.message.ResponseTrackPart;
class LiveSender extends Thread {
public LiveSender(LiveClient live, LiveConnection conn, RequestOpen open) {
super("LiveSender");
_conn = conn;
_live = live;
_trackMessages = new Vector();
_openRequest = open;
_timer = new Timer();
_weHaveSignal = false;
if (open instanceof RequestOpenContinue) {
_key = ((RequestOpenContinue)open).getKey();
}
}
public synchronized void stop() {
interrupt();
}
public void run() {
long tLastTry = 0;
_live.logInfo("LiveSender: Started");
try {
while (true) {
boolean msgSent = false;
boolean weHadSignal = false;
long now;
_conn.reconnect();
synchronized(this) {
weHadSignal = _weHaveSignal;
_weHaveSignal = false; // well we still have probably, but it means something like "SEND ALL"
}
now = System.currentTimeMillis();
if (weHadSignal) {
tLastTry = now;
msgSent = sendAllMessages();
}
else if (tLastTry+_conn.getResendInterval() <= now) {
tLastTry = now;
msgSent = sendFirstMessage();
}
if (msgSent) {
_live.messageSent();
}
synchronized(this) {
if (getPendingCounter() == 0) {
_weHaveSignal = true;
wait();
}
else {
long delay = tLastTry + _conn.getResendInterval() - System.currentTimeMillis();
if (delay > 0)
wait(delay);
}
}
}
}
catch (InterruptedException e) {}
catch (Throwable e) {
_live.logError("LiveSender: FATAL",e);
}
_live.logInfo("LiveSender: Stopped");
}
// [gps]
public synchronized void addTrackMessage(RequestTrackPart msg) {
_trackMessages.addElement(msg);
_pendingPoints += msg.getPointCount();
notify();
}
public synchronized int getPendingCounter() {
return _trackMessages.size() + (_openRequest != null ? 1 : 0);
}
public synchronized int getOKCounter() {
return _nOK;
}
public synchronized int getPendingPoints() {
return _pendingPoints;
}
public synchronized int getConfirmedPoints() {
return _confirmedPoints;
}
// [receiver]
public synchronized void receivedOpenResponseOk(ResponseOpenOk resp) {
_openRequest = null; // no longer try to send auth
if (resp.getKey() != null) // key is not set for ResponseOpenContinue
_key = resp.getKey();
_nOK ++;
_weHaveSignal = true; // we are on the signal now!
notify(); // which is a good reason to wake up!
}
// [receiver]
public synchronized void receivedTrackPartResponse(ResponseTrackPart resp) {
int i = 0;
while (i < _trackMessages.size()) {
RequestTrackPart msg = (RequestTrackPart)_trackMessages.elementAt(i);
if (resp.isConfirmed(msg.getSeq())) {
// server claims it has already received this message - no need to send it again
_trackMessages.removeElementAt(i);
int npts = msg.getPointCount();
_confirmedPoints += npts;
_pendingPoints -= npts;
_nOK ++;
}
else {
i ++;
}
}
_weHaveSignal = true; // we are on the signal now!
notify(); // which is a good reason to wake up!
}
private synchronized String getMessageString(int idx) {
if (_openRequest != null) {
if (idx == 0)
return _openRequest.toJSON().toString();
else
idx --;
}
if (_key != null && idx < _trackMessages.size()) {
RequestTrackPart msg = (RequestTrackPart)_trackMessages.elementAt(idx);
msg.setKey(_key);
return msg.toJSON().toString();
}
return null;
}
// [sender]
// returns true if message was sent
private boolean sendFirstMessage() {
String msg = null;
if (_conn.startSendingMessages()) {
msg = getMessageString(0);
if (msg != null) {
_live.logInfo("SEND: "+msg);
_conn.sendStringMessage(msg);
}
_conn.finishedSendingMessages();
}
return msg != null;
}
// [sender]
// returns true if message was sent
private boolean sendAllMessages() {
boolean isSent = false;
if (_conn.startSendingMessages()) {
for (int i = 0; i < getPendingCounter(); i ++) {
String msg = getMessageString(i);
_live.logInfo("SEND: "+msg);
_conn.sendStringMessage(msg);
isSent = true;
}
_conn.finishedSendingMessages();
}
return isSent;
}
int _nOK;
String _key;
boolean _weHaveSignal;
int _pendingPoints;
int _confirmedPoints;
// messages to send
RequestOpen _openRequest;
Vector _trackMessages;
LiveConnection _conn;
LiveClient _live;
Timer _timer;
}