/* 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.bus;
import java.util.concurrent.CopyOnWriteArrayList;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
import dk.dma.ais.bus.status.AisBusComponentStatus;
import dk.dma.ais.filter.PacketFilterCollection;
import dk.dma.ais.packet.AisPacket;
import dk.dma.ais.transform.IAisPacketTransformer;
/**
* Base class for all AisBus components receiving and handing of AIS packets. All components are able to filter, transform and tag
* all received data.
*/
@ThreadSafe
public abstract class AisBusComponent {
/**
* Maximum time to wait for threads to stop after having been cancelled
*/
public static final long THREAD_STOP_WAIT_MAX = 10000;
/**
* The status of the component
*/
protected final AisBusComponentStatus status;
/**
* Thread for this component
*/
@GuardedBy("this")
private Thread thread;
/**
* Filters to apply to received packets
*/
protected final PacketFilterCollection filters = new PacketFilterCollection();
/**
* Transformers to apply
*/
protected final CopyOnWriteArrayList<IAisPacketTransformer> packetTransformers = new CopyOnWriteArrayList<>();
public AisBusComponent() {
this.status = new AisBusComponentStatus();
}
/**
* Initialize the component after configuration. Must be called be starting the component.
*/
public void init() {
status.setInitialized();
}
/**
* Start the component. Must be called after init().
*/
public void start() {
status.setStarted();
}
public void setConnected() {
status.setConnected();
}
public void setNotConnected() {
status.setNotConnected();
}
public void setStopped() {
status.setStopped();
}
/**
* Get component status
* @return
*/
public AisBusComponentStatus getStatus() {
return status;
}
/**
* Set component thread
*
* @param thread
*/
protected synchronized void setThread(Thread thread) {
this.thread = thread;
}
/**
* Get component thread
*
* @return
*/
public synchronized Thread getThread() {
return thread;
}
/**
* All components must implement a way to stop
*/
public abstract void cancel();
/**
* Method to handle incoming packet for all AisBus components. Will do filtering, transformation and tagging.
*
* @param element
* @return
*/
protected AisPacket handleReceived(AisPacket packet) {
status.receive();
// Filter message
if (filters.rejectedByFilter(packet)) {
// Update statistics
status.filtered();
return null;
}
// Transform packet
for (IAisPacketTransformer transformer : packetTransformers) {
packet = transformer.transform(packet);
}
// Update statistics
if (packet == null) {
status.filtered();
}
return packet;
}
/**
* Get filters collection
*
* @return
*/
public PacketFilterCollection getFilters() {
return filters;
}
/**
* Get packet transformers list
*
* @return
*/
public CopyOnWriteArrayList<IAisPacketTransformer> getPacketTransformers() {
return packetTransformers;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("AisBusComponent [class=");
builder.append(this.getClass());
builder.append(", status=");
builder.append(status);
builder.append("]");
return builder.toString();
}
public String rateReport() {
return String.format("[received/filtered/overflow] %4.2f / %4.2f / %4.2f (packets/sec)", status.getInRate(), status.getFilteredRate(), status.getOverflowRate());
}
}