/*
* Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
*
* 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 org.traccar;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.DownstreamMessageEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.traccar.events.CommandResultEventHandler;
import org.traccar.events.FuelDropEventHandler;
import org.traccar.events.GeofenceEventHandler;
import org.traccar.events.IgnitionEventHandler;
import org.traccar.events.MaintenanceEventHandler;
import org.traccar.events.MotionEventHandler;
import org.traccar.events.OverspeedEventHandler;
import org.traccar.events.AlertEventHandler;
import org.traccar.helper.Log;
import org.traccar.processing.ComputedAttributesHandler;
import org.traccar.processing.CopyAttributesHandler;
import java.net.InetSocketAddress;
public abstract class BasePipelineFactory implements ChannelPipelineFactory {
private final TrackerServer server;
private int timeout;
private FilterHandler filterHandler;
private CoordinatesHandler coordinatesHandler;
private DistanceHandler distanceHandler;
private GeocoderHandler geocoderHandler;
private GeolocationHandler geolocationHandler;
private HemisphereHandler hemisphereHandler;
private CopyAttributesHandler copyAttributesHandler;
private ComputedAttributesHandler computedAttributesHandler;
private CommandResultEventHandler commandResultEventHandler;
private OverspeedEventHandler overspeedEventHandler;
private FuelDropEventHandler fuelDropEventHandler;
private MotionEventHandler motionEventHandler;
private GeofenceEventHandler geofenceEventHandler;
private AlertEventHandler alertEventHandler;
private IgnitionEventHandler ignitionEventHandler;
private MaintenanceEventHandler maintenanceEventHandler;
private static final class OpenChannelHandler extends SimpleChannelHandler {
private final TrackerServer server;
private OpenChannelHandler(TrackerServer server) {
this.server = server;
}
@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
server.getChannelGroup().add(e.getChannel());
}
}
private static class StandardLoggingHandler extends LoggingHandler {
@Override
public void log(ChannelEvent e) {
if (e instanceof MessageEvent) {
MessageEvent event = (MessageEvent) e;
StringBuilder msg = new StringBuilder();
msg.append("[").append(String.format("%08X", e.getChannel().getId())).append(": ");
msg.append(((InetSocketAddress) e.getChannel().getLocalAddress()).getPort());
if (e instanceof DownstreamMessageEvent) {
msg.append(" > ");
} else {
msg.append(" < ");
}
if (event.getRemoteAddress() != null) {
msg.append(((InetSocketAddress) event.getRemoteAddress()).getHostString());
} else {
msg.append("null");
}
msg.append("]");
if (event.getMessage() instanceof ChannelBuffer) {
msg.append(" HEX: ");
msg.append(ChannelBuffers.hexDump((ChannelBuffer) event.getMessage()));
}
Log.debug(msg.toString());
}
}
}
public BasePipelineFactory(TrackerServer server, String protocol) {
this.server = server;
timeout = Context.getConfig().getInteger(protocol + ".timeout");
if (timeout == 0) {
timeout = Context.getConfig().getInteger(protocol + ".resetDelay"); // temporary
if (timeout == 0) {
timeout = Context.getConfig().getInteger("server.timeout");
}
}
if (Context.getConfig().getBoolean("filter.enable")) {
filterHandler = new FilterHandler();
}
if (Context.getConfig().getBoolean("coordinates.filter")) {
coordinatesHandler = new CoordinatesHandler();
}
if (Context.getGeocoder() != null) {
geocoderHandler = new GeocoderHandler(
Context.getGeocoder(),
Context.getConfig().getBoolean("geocoder.processInvalidPositions"));
}
if (Context.getGeolocationProvider() != null) {
geolocationHandler = new GeolocationHandler(
Context.getGeolocationProvider(),
Context.getConfig().getBoolean("geolocation.processInvalidPositions"));
}
distanceHandler = new DistanceHandler();
if (Context.getConfig().hasKey("location.latitudeHemisphere")
|| Context.getConfig().hasKey("location.longitudeHemisphere")) {
hemisphereHandler = new HemisphereHandler();
}
if (Context.getConfig().getBoolean("processing.copyAttributes.enable")) {
copyAttributesHandler = new CopyAttributesHandler();
}
if (Context.getConfig().getBoolean("processing.computedAttributes.enable")) {
computedAttributesHandler = new ComputedAttributesHandler();
}
if (Context.getConfig().getBoolean("event.enable")) {
commandResultEventHandler = new CommandResultEventHandler();
overspeedEventHandler = new OverspeedEventHandler();
fuelDropEventHandler = new FuelDropEventHandler();
motionEventHandler = new MotionEventHandler();
geofenceEventHandler = new GeofenceEventHandler();
alertEventHandler = new AlertEventHandler();
ignitionEventHandler = new IgnitionEventHandler();
maintenanceEventHandler = new MaintenanceEventHandler();
}
}
protected abstract void addSpecificHandlers(ChannelPipeline pipeline);
@Override
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
if (timeout > 0 && !server.isConnectionless()) {
pipeline.addLast("idleHandler", new IdleStateHandler(GlobalTimer.getTimer(), timeout, 0, 0));
}
pipeline.addLast("openHandler", new OpenChannelHandler(server));
if (Context.isLoggerEnabled()) {
pipeline.addLast("logger", new StandardLoggingHandler());
}
addSpecificHandlers(pipeline);
if (geolocationHandler != null) {
pipeline.addLast("location", geolocationHandler);
}
if (hemisphereHandler != null) {
pipeline.addLast("hemisphere", hemisphereHandler);
}
if (geocoderHandler != null) {
pipeline.addLast("geocoder", geocoderHandler);
}
pipeline.addLast("remoteAddress", new RemoteAddressHandler());
addDynamicHandlers(pipeline);
if (filterHandler != null) {
pipeline.addLast("filter", filterHandler);
}
if (coordinatesHandler != null) {
pipeline.addLast("coordinatesHandler", coordinatesHandler);
}
if (distanceHandler != null) {
pipeline.addLast("distance", distanceHandler);
}
if (copyAttributesHandler != null) {
pipeline.addLast("copyAttributes", copyAttributesHandler);
}
if (computedAttributesHandler != null) {
pipeline.addLast("computedAttributes", computedAttributesHandler);
}
if (Context.getDataManager() != null) {
pipeline.addLast("dataHandler", new DefaultDataHandler());
}
if (Context.getConfig().getBoolean("forward.enable")) {
pipeline.addLast("webHandler", new WebDataHandler(Context.getConfig().getString("forward.url")));
}
if (commandResultEventHandler != null) {
pipeline.addLast("CommandResultEventHandler", commandResultEventHandler);
}
if (overspeedEventHandler != null) {
pipeline.addLast("OverspeedEventHandler", overspeedEventHandler);
}
if (fuelDropEventHandler != null) {
pipeline.addLast("FuelDropEventHandler", fuelDropEventHandler);
}
if (motionEventHandler != null) {
pipeline.addLast("MotionEventHandler", motionEventHandler);
}
if (geofenceEventHandler != null) {
pipeline.addLast("GeofenceEventHandler", geofenceEventHandler);
}
if (alertEventHandler != null) {
pipeline.addLast("AlertEventHandler", alertEventHandler);
}
if (ignitionEventHandler != null) {
pipeline.addLast("IgnitionEventHandler", ignitionEventHandler);
}
if (maintenanceEventHandler != null) {
pipeline.addLast("MaintenanceEventHandler", maintenanceEventHandler);
}
pipeline.addLast("mainHandler", new MainEventHandler());
return pipeline;
}
private void addDynamicHandlers(ChannelPipeline pipeline) {
if (Context.getConfig().hasKey("extra.handlers")) {
String[] handlers = Context.getConfig().getString("extra.handlers").split(",");
for (int i = 0; i < handlers.length; i++) {
try {
pipeline.addLast("extraHandler." + i, (ChannelHandler) Class.forName(handlers[i]).newInstance());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException error) {
Log.warning(error);
}
}
}
}
}