/* license-start
*
* Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>.
*
* 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 version 3.
*
* 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, at <http://www.gnu.org/licenses/>.
*
* Contributors:
* Crispico - Initial API and implementation
*
* license-end
*/
package org.flowerplatform.blazeds.heartbeat;
import static org.flowerplatform.blazeds.heartbeat.HeartbeatStatefulService.logger;
import static org.flowerplatform.blazeds.heartbeat.HeartbeatProperties.CLIENT_NO_ACTIVITY_PERIOD;
import static org.flowerplatform.blazeds.heartbeat.HeartbeatProperties.SERVER_HEARTBEAT_PERIOD;
import static org.flowerplatform.blazeds.heartbeat.HeartbeatProperties.WARN_ABOUT_NO_ACTIVITY_INTERVAL;
import static java.lang.Integer.valueOf;
import java.text.DecimalFormat;
import java.util.concurrent.Future;
import org.flowerplatform.blazeds.channel.BlazedsCommunicationChannel;
import org.flowerplatform.common.CommonPlugin;
import flex.messaging.util.TimeoutAbstractObject;
/**
* Channel Observer task that can run logic on a locked channel.
* Usefull for not disposing while processing a new object.
* @author Sorin
*
*/
public abstract class HeartbeatTask extends TimeoutAbstractObject {
// Easier to access this way.
protected static long noHeartbeatFromClientInterval;
protected static long warnAboutNoActivityInterval;
protected static long noActivityOnClientInterval;
static {
noHeartbeatFromClientInterval = valueOf(CommonPlugin.getInstance().getFlowerProperties()
.getProperty(SERVER_HEARTBEAT_PERIOD));
warnAboutNoActivityInterval = valueOf(CommonPlugin.getInstance().getFlowerProperties()
.getProperty(WARN_ABOUT_NO_ACTIVITY_INTERVAL));
noActivityOnClientInterval = valueOf(CommonPlugin.getInstance().getFlowerProperties()
.getProperty(CLIENT_NO_ACTIVITY_PERIOD));
}
private boolean taskExecuted = false;
private String name;
protected BlazedsCommunicationChannel channel;
public HeartbeatTask(String name, BlazedsCommunicationChannel channel, long timeoutPeriod) {
this.name = name;
this.channel = channel;
setTimeoutPeriod(timeoutPeriod);
updateLastUse();
}
@Override
final public void timeout() {
if (taskExecuted)
return;
try {
// All disposing operations must be done by blocking the channel because otherwise
// an object may be processed while disposing a channel.
synchronized (channel.lock) {
if (channel.isDisposed())
return;
runWithChannelLocked();
}
taskExecuted = true;
} catch (Exception e) {
logger.error("Problem kicking (warning) out client.", e);
}
}
protected abstract void runWithChannelLocked();
@SuppressWarnings("rawtypes")
@Override
public void setTimeoutFuture(Future timeoutFuture) {
super.setTimeoutFuture(timeoutFuture);
taskExecuted = false;
}
/**
* Because a blazeDS task doesn't know if it was executed or not, we keep this flag.
* It is needed to reschedule after {@link WarnAboutNoActivityTask} has executed and the client
* sent a signal of activity.
* @return
*/
public boolean isTaskExecuted() {
return taskExecuted;
}
@Override
public String toString() {
DecimalFormat df = new DecimalFormat("#.### s");
double timeoutPeriod = getTimeoutPeriod() / 1000.0;
double untilTimeout = (getLastUse() + getTimeoutPeriod() - System.currentTimeMillis()) / 1000.0;
return "Task '" + name + "' : timeout period = " + df.format(timeoutPeriod) + ", until timeout = " + df.format(untilTimeout);
}
}