/*
* Copyright 2014-2015 JKOOL, LLC.
*
* 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 com.jkoolcloud.tnt4j.sink.impl;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import com.jkoolcloud.tnt4j.core.Snapshot;
import com.jkoolcloud.tnt4j.sink.AbstractEventSink;
import com.jkoolcloud.tnt4j.sink.EventSink;
import com.jkoolcloud.tnt4j.source.Source;
import com.jkoolcloud.tnt4j.core.OpLevel;
import com.jkoolcloud.tnt4j.format.EventFormatter;
import com.jkoolcloud.tnt4j.tracker.TrackingActivity;
import com.jkoolcloud.tnt4j.tracker.TrackingEvent;
import com.jkoolcloud.tnt4j.utils.Utils;
/**
* <p>
* This class implements {@link EventSink} with socket as the underlying
* sink implementation.
* </p>
*
*
* @version $Revision: 14 $
*
* @see TrackingActivity
* @see TrackingEvent
* @see OpLevel
* @see EventSink
* @see EventFormatter
*/
public class SocketEventSink extends AbstractEventSink {
private Socket socketSink = null;
private DataOutputStream outStream = null;
private EventSink logSink = null;
private String hostName = "localhost";
private int portNo = 6400;
/**
* Create a socket event sink based on a given host, port and formatter.
* Another sink can be associated with this sink where all events are routed.
*
* @param name logical name assigned to this sink
* @param host name where all messages are sent
* @param port number where all messages are sent
* @param frm event formatter associated with this sink
* @param sink piped sink where all events are piped
*/
public SocketEventSink(String name, String host, int port, EventFormatter frm, EventSink sink) {
super(name, frm);
hostName = host;
portNo = port;
logSink = sink;
}
@Override
protected void _log(TrackingActivity activity) throws IOException {
if (logSink != null) {
logSink.log(activity);
}
writeLine(getEventFormatter().format(activity));
}
@Override
protected void _log(TrackingEvent event) throws IOException {
if (logSink != null) {
logSink.log(event);
}
writeLine(getEventFormatter().format(event));
}
@Override
protected void _log(Snapshot snapshot) throws IOException {
if (logSink != null) {
logSink.log(snapshot);
}
writeLine(getEventFormatter().format(snapshot));
}
@Override
protected void _log(long ttl, Source src, OpLevel sev, String msg, Object...args) throws IOException {
if (logSink != null) {
logSink.log(ttl, src, sev, msg, args);
}
writeLine(getEventFormatter().format(ttl, src, sev, msg, args));
}
@Override
protected void _write(Object msg, Object...args) throws IOException {
if (isOpen()) {
writeLine(getEventFormatter().format(msg, args));
}
}
@Override
public Object getSinkHandle() {
return socketSink;
}
@Override
public boolean isOpen() {
return socketSink != null && socketSink.isConnected();
}
@Override
public synchronized void open() throws IOException {
socketSink = new Socket(hostName, portNo);
outStream = new DataOutputStream(socketSink.getOutputStream());
if (logSink != null) {
logSink.open();
}
}
@Override
public void flush() throws IOException {
if (isOpen()) {
outStream.flush();
}
}
@Override
public synchronized void close() throws IOException {
try {
if (isOpen()) {
Utils.close(logSink);
outStream.close();
socketSink.close();
}
} finally {
outStream = null;
socketSink = null;
}
}
@Override
public String toString() {
return super.toString()
+ "{host: " + hostName
+ ", port: " + portNo
+ ", socket: " + socketSink
+ ", formatter: " + getEventFormatter()
+ ", piped.sink: " + logSink
+ "}";
}
private synchronized void writeLine(String msg) throws IOException {
String lineMsg = msg.endsWith("\n")? msg: msg + "\n";
byte [] bytes = lineMsg.getBytes();
outStream.write(bytes, 0, bytes.length);
outStream.flush();
}
@Override
public boolean isSet(OpLevel sev) {
return logSink != null? logSink.isSet(sev): true;
}
@Override
protected void _checkState() throws IllegalStateException {
if (!isOpen())
throw new IllegalStateException("Sink closed: " + hostName + ":" + this.portNo + ", socket=" + socketSink);
}
}