/* Copyright (c) 2011 Danish Maritime Authority.
*
* 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 dk.dma.ais.transform;
import java.util.Date;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
import dk.dma.ais.packet.AisPacket;
/**
* Special kind of transformer that imposes a delay to replay an AIS stream given speedup, and the timing in the stream.
*/
@ThreadSafe
public class ReplayTransformer implements IAisPacketTransformer {
@GuardedBy("this")
private double speedup = 1;
@GuardedBy("this")
private Long epochStream;
@GuardedBy("this")
private Long epochReplay;
public ReplayTransformer() {
}
public ReplayTransformer(double speedup) {
this.speedup = speedup;
}
@Override
public AisPacket transform(AisPacket packet) {
long diff;
long sleepTime;
synchronized (this) {
// Get timestamp from stream
Date timestamp = packet.getTimestamp();
if (timestamp == null) {
return packet;
}
long now = System.currentTimeMillis();
// Set epochs if not already set
if (epochReplay == null) {
epochReplay = now;
}
if (epochStream == null) {
epochStream = timestamp.getTime();
}
// How long has elapsed in the stream and in replay
long elapsedStream = timestamp.getTime() - epochStream;
long elapsedReplay = (long) ((now - epochReplay) * speedup);
diff = elapsedStream - elapsedReplay;
sleepTime = (long) (diff / speedup);
}
// Sleep if diff is becoming too large
if (diff > 200) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
return packet;
}
/**
* Method to reset the replay values. Can be used
* if the stream of packets are being repeated.
*/
public synchronized void reset() {
epochReplay = null;
epochStream = null;
}
/**
* Fractional speedup to use
*
* @param speedup
*/
public synchronized void setSpeedup(double speedup) {
this.speedup = speedup;
}
}