Added ParameterizedSocket and LoggerOutputStream classes.
ParameterizedSocket ------------------- This is a wrapper around the basic java.net.Socket class that supports sending and receiving messages with parameters. It exposes two methods: `void sendMessage(String... message)` and `String[] receiveMessage()`. The line-level format of the message is: START_TOKEN param [SEPARATOR param ...] END_TOKEN Where `START_TOKEN` is the ASCII "Start heading" control code `0x01`, `SEPARATOR` is the ASCII "record separator" code `0x1E`, and `END_TOKEN` is the ASCII "end of transmission" code `0x03`. LoggerOutputStream ------------------ An OutputStream implementation that flushes to an org.slf4j.Logger instance. The log level is configurable. It is important to note that data written to the stream accumulates in an internal buffer until `flush()` is called. At this point the data is written out as one log message to the logger. It is expected that one would wrap this stream in an auto-flushing PrintStream or PrintWriter in actual use.
This commit is contained in:
parent
01c2f4930a
commit
21cdf6909c
BIN
lib/runtime/jar/logback-classic-0.9.26.jar
Normal file
BIN
lib/runtime/jar/logback-classic-0.9.26.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/logback-core-0.9.26.jar
Normal file
BIN
lib/runtime/jar/logback-core-0.9.26.jar
Normal file
Binary file not shown.
89
src/main/com/jdbernard/net/ParameterizedSocket.java
Normal file
89
src/main/com/jdbernard/net/ParameterizedSocket.java
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* ParameterizedSocket
|
||||||
|
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||||
|
*/
|
||||||
|
package com.jdbernard.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ParameterizedSocket {
|
||||||
|
|
||||||
|
public static final String START_TOKEN = "\u0001";
|
||||||
|
public static final String END_TOKEN = "\u0004";
|
||||||
|
public static final String RECORD_SEPARATOR = "\u001E";
|
||||||
|
|
||||||
|
public static final byte START_TOKEN_BYTE = 0x01;
|
||||||
|
public static final byte END_TOKEN_BYTE = 0x04;
|
||||||
|
public static final byte RECORD_SEPARATOR_BYTE = 0x1E;
|
||||||
|
|
||||||
|
private Socket socket;
|
||||||
|
private byte[] buffer;
|
||||||
|
private Charset charset;
|
||||||
|
|
||||||
|
public ParameterizedSocket(Socket socket, int bufferSize) {
|
||||||
|
this.socket = socket;
|
||||||
|
this.buffer = new byte[bufferSize];
|
||||||
|
this.charset = Charset.forName("US-ASCII"); }
|
||||||
|
|
||||||
|
public ParameterizedSocket(String ipAddress, int port, int bufferSize)
|
||||||
|
throws UnknownHostException, IOException {
|
||||||
|
this(new Socket(ipAddress, port), bufferSize); }
|
||||||
|
|
||||||
|
public ParameterizedSocket(Socket socket)
|
||||||
|
throws UnknownHostException, IOException {
|
||||||
|
this(socket, 2048); }
|
||||||
|
|
||||||
|
public ParameterizedSocket(String ipAddress, int port)
|
||||||
|
throws UnknownHostException, IOException {
|
||||||
|
this(ipAddress, port, 2048); }
|
||||||
|
|
||||||
|
public boolean getClosed() { return socket.isClosed(); }
|
||||||
|
public boolean getConnected() { return socket.isConnected(); }
|
||||||
|
|
||||||
|
public void close() throws IOException { socket.close(); }
|
||||||
|
|
||||||
|
public void writeMessage(String... message) throws IOException {
|
||||||
|
if (message == null || message.length == 0) return;
|
||||||
|
|
||||||
|
byte[] messageBytes = formatMessage(message);
|
||||||
|
socket.getOutputStream().write(messageBytes); }
|
||||||
|
|
||||||
|
public String[] readMessage() throws IOException {
|
||||||
|
List<String> messageList = new ArrayList<String>();
|
||||||
|
|
||||||
|
if (socket.getInputStream().read() != START_TOKEN_BYTE) {
|
||||||
|
byte[] errMsg = formatMessage("ERROR", "Invalid command (expected START_TOKEN).");
|
||||||
|
socket.getOutputStream().write(errMsg); }
|
||||||
|
|
||||||
|
int bufIdx= 0;
|
||||||
|
int nextByte = socket.getInputStream().read();
|
||||||
|
|
||||||
|
while (nextByte != END_TOKEN_BYTE) {
|
||||||
|
if (nextByte == -1) {
|
||||||
|
byte[] errMsg = formatMessage("ERROR", "Invalid command: stream ended before END_TOKEN was read.");
|
||||||
|
socket.getOutputStream().write(errMsg);
|
||||||
|
return null; }
|
||||||
|
|
||||||
|
else if (nextByte == RECORD_SEPARATOR_BYTE) {
|
||||||
|
messageList.add(new String(buffer, 0, bufIdx, charset));
|
||||||
|
bufIdx = 0; }
|
||||||
|
|
||||||
|
else { buffer[bufIdx++] = (byte) nextByte; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufIdx > 0) messageList.add(new String(buffer, 0, bufIdx, charset));
|
||||||
|
|
||||||
|
return (String[]) messageList.toArray(); }
|
||||||
|
|
||||||
|
protected byte[] formatMessage(String... message) {
|
||||||
|
String fullMessage = START_TOKEN + message[0];
|
||||||
|
for (int i = 1; i < message.length; i++) {
|
||||||
|
fullMessage += RECORD_SEPARATOR + message[i]; }
|
||||||
|
fullMessage += END_TOKEN;
|
||||||
|
return fullMessage.getBytes(charset); }
|
||||||
|
}
|
88
src/main/com/jdbernard/slf4j/LoggerOutputStream.java
Normal file
88
src/main/com/jdbernard/slf4j/LoggerOutputStream.java
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* LoggerOutputStream
|
||||||
|
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||||
|
*/
|
||||||
|
package com.jdbernard.slf4j;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
public class LoggerOutputStream {
|
||||||
|
|
||||||
|
public enum Level { TRACE, DEBUG, INFO, WARN, ERROR }
|
||||||
|
|
||||||
|
private Logger logger;
|
||||||
|
private Level level;
|
||||||
|
private boolean closed = false;
|
||||||
|
private byte[] buffer;
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
private static final int DEFAULT_BUFFER_LENGTH = 2048;
|
||||||
|
|
||||||
|
public LoggerOutputStream(Logger logger, Level level) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.level = level; }
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void write(final byte[] b, final int offset, final int length)
|
||||||
|
throws IOException {
|
||||||
|
if (closed)
|
||||||
|
throw new IOException("The output stream has been closed.");
|
||||||
|
|
||||||
|
// Grow the buffer if we will reach the limit.
|
||||||
|
if (count + length >= buffer.length) {
|
||||||
|
final int newLength =
|
||||||
|
Math.max(buffer.length + DEFAULT_BUFFER_LENGTH, count + length);
|
||||||
|
final byte[] newBuffer = new byte[newLength];
|
||||||
|
|
||||||
|
System.arraycopy(buffer, 0, newBuffer, 0, count);
|
||||||
|
buffer = newBuffer; }
|
||||||
|
|
||||||
|
System.arraycopy(buffer, count, b, offset, length);
|
||||||
|
count += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void write(final int b) throws IOException {
|
||||||
|
if (closed)
|
||||||
|
throw new IOException("The output stream has been closed.");
|
||||||
|
|
||||||
|
// Grow the buffer if we have reached the limit.
|
||||||
|
if (count == buffer.length) {
|
||||||
|
final int newLength = buffer.length + DEFAULT_BUFFER_LENGTH;
|
||||||
|
final byte[] newBuffer = new byte[newLength];
|
||||||
|
|
||||||
|
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
|
||||||
|
buffer = newBuffer; }
|
||||||
|
|
||||||
|
buffer[count++] = (byte) b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void flush() throws IOException {
|
||||||
|
if (closed)
|
||||||
|
throw new IOException("The output stream has been closed.");
|
||||||
|
|
||||||
|
final byte[] messageBytes = new byte[count];
|
||||||
|
System.arraycopy(buffer, 0, messageBytes, 0, count);
|
||||||
|
final String message = new String(messageBytes);
|
||||||
|
synchronized(logger) {
|
||||||
|
switch (level) {
|
||||||
|
default:
|
||||||
|
case TRACE: logger.trace(message); break;
|
||||||
|
case DEBUG: logger.debug(message); break;
|
||||||
|
case INFO: logger.info(message); break;
|
||||||
|
case WARN: logger.warn(message); break;
|
||||||
|
case ERROR: logger.error(message); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (closed) return;
|
||||||
|
flush();
|
||||||
|
closed = true; }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user