/*
* Lilith - a log event viewer.
* Copyright (C) 2007-2016 Joern Huxhorn
*
* 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 de.huxhorn.lilith.engine.impl.sourceproducer;
import de.huxhorn.lilith.data.eventsource.EventWrapper;
import de.huxhorn.lilith.data.eventsource.SourceIdentifier;
import de.huxhorn.lilith.engine.EventProducer;
import de.huxhorn.lilith.engine.EventSourceProducer;
import de.huxhorn.lilith.engine.SourceManager;
import de.huxhorn.sulky.buffers.AppendOperation;
import de.huxhorn.sulky.io.IOUtilities;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.BindException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// TODO: ServerSocket
// TODO: postprocess
public abstract class AbstractServerSocketEventSourceProducer<T extends Serializable>
implements EventSourceProducer<T>, Runnable
{
final Logger logger = LoggerFactory.getLogger(AbstractServerSocketEventSourceProducer.class);
private static final DateTimeFormatter FORMAT = DateTimeFormatter
.ofPattern("yyyyMMdd'T'HHmmssSSS", Locale.US)
.withZone(ZoneId.systemDefault());
private ServerSocket serverSocket;
private AppendOperation<EventWrapper<T>> queue;
private SourceManager<T> sourceManager;
private int port;
public AbstractServerSocketEventSourceProducer(int port)
throws IOException
{
this.port = port;
try
{
serverSocket = new ServerSocket(port);
}
catch(BindException ex)
{
if(logger.isErrorEnabled()) logger.error("Couldn't start ServerSocket on port {}!", port);
throw ex;
}
}
public AppendOperation<EventWrapper<T>> getQueue()
{
return queue;
}
public void setQueue(AppendOperation<EventWrapper<T>> queue)
{
this.queue = queue;
}
public SourceManager<T> getSourceManager()
{
return sourceManager;
}
public void setSourceManager(SourceManager<T> sourceManager)
{
this.sourceManager = sourceManager;
}
public int getPort()
{
return port;
}
public void run()
{
for(;;)
{
Socket socket;
try
{
socket = serverSocket.accept();
}
catch(IOException e)
{
if(logger.isInfoEnabled()) logger.info("Closing serverSocket because of exception.", e);
try
{
if(serverSocket != null)
{
serverSocket.close();
}
}
catch(IOException e1)
{
if(logger.isInfoEnabled()) logger.info("Exception while closing serverSocket.");
}
break;
}
try
{
SourceIdentifier id = createSourceIdentifier(socket);
EventProducer<T> producer = createProducer(id, queue, socket.getInputStream());
producer.start();
sourceManager.addEventProducer(producer);
}
catch(Throwable e)
{
if(logger.isInfoEnabled()) logger.info("Exception while creating EventProducer.", e);
IOUtilities.interruptIfNecessary(e);
}
}
}
private SourceIdentifier createSourceIdentifier(Socket socket)
{
SocketAddress address = socket.getRemoteSocketAddress();
String primary;
if(address instanceof InetSocketAddress)
{
InetSocketAddress inetSocketAddress = (InetSocketAddress) address;
InetAddress inetAddress = inetSocketAddress.getAddress();
primary = inetAddress.getHostAddress();
}
else
{
primary = "" + address;
}
String secondary = FORMAT.format(Instant.now());
return new SourceIdentifier(primary, secondary);
}
protected abstract EventProducer<T> createProducer(SourceIdentifier id,
AppendOperation<EventWrapper<T>> eventQueue,
InputStream inputStream)
throws IOException;
}