diff --git a/project.properties b/project.properties index a1bdcef..c6373ed 100644 --- a/project.properties +++ b/project.properties @@ -1,6 +1,6 @@ -#Wed, 21 Nov 2012 13:12:41 -0600 +#Thu, 22 Nov 2012 14:39:26 -0600 name=jdb-util version=1.7 lib.local=true -build.number=0 +build.number=16 diff --git a/src/main/com/jdbernard/net/ParameterizedSocket.java b/src/main/com/jdbernard/net/ParameterizedSocket.java index ebf4e26..9e0d514 100644 --- a/src/main/com/jdbernard/net/ParameterizedSocket.java +++ b/src/main/com/jdbernard/net/ParameterizedSocket.java @@ -9,18 +9,44 @@ import java.net.Socket; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class ParameterizedSocket { - public static final String START_TOKEN = "\u0001"; - public static final String END_TOKEN = "\u0004"; + public static final String START_TOKEN = "\u0001"; + public static final String END_TOKEN = "\u0004"; public static final String RECORD_SEPARATOR = "\u001E"; + public static final String FIELD_SEPARATOR = "\u001F"; - public static final byte START_TOKEN_BYTE = 0x01; - public static final byte END_TOKEN_BYTE = 0x04; - public static final byte RECORD_SEPARATOR_BYTE = 0x1E; + public static final byte START_TOKEN_BYTE = 0x01; + public static final byte END_TOKEN_BYTE = 0x04; + public static final byte RECORD_SEPARATOR_BYTE = 0x1E; + public static final byte FIELD_SEPARATOR_BYTE = 0x1F; + public static class Message { + List parts; + Map namedParameters; + + public Message(List parts, Map namedParameters) { + this.parts = parts; + this.namedParameters = namedParameters; } + + public Message(String... parts) { + this.parts = new ArrayList(); + this.namedParameters = new HashMap(); + + for (String part : parts) { this.parts.add(part); }} + + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String part: parts) { sb.append(part + "/"); } + for (Map.Entry param : namedParameters.entrySet()) { + sb.append(param.getKey() + "=" + param.getValue()); } + return sb.toString(); } + } + private Socket socket; private byte[] buffer; private Charset charset; @@ -47,14 +73,15 @@ public class ParameterizedSocket { public void close() throws IOException { socket.close(); } - public void writeMessage(String... message) throws IOException { - if (message == null || message.length == 0) return; + public void writeMessage(Message message) throws IOException { + if (message == null || message.parts.size() == 0) return; byte[] messageBytes = formatMessage(message); socket.getOutputStream().write(messageBytes); } - public String[] readMessage() throws IOException { + public Message readMessage() throws IOException { List messageList = new ArrayList(); + Map namedParameters = new HashMap(); if (socket.getInputStream().read() != START_TOKEN_BYTE) { byte[] errMsg = formatMessage("ERROR", "Invalid command (expected START_TOKEN)."); @@ -62,28 +89,69 @@ public class ParameterizedSocket { int bufIdx= 0; int nextByte = socket.getInputStream().read(); + String paramName = null; while (nextByte != END_TOKEN_BYTE) { + + // If we have reached end-of-stream, this is an error. 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)); + // Field separator means we have read a parameter name into the + // buffer. + else if (nextByte == FIELD_SEPARATOR_BYTE) { + paramName = new String(buffer, 0, bufIdx, charset); bufIdx = 0; } + // Record separator means we have finished reading the current + // message part (named or unnamed parameter). + else if (nextByte == RECORD_SEPARATOR_BYTE) { + + // No param name, must be an unnamed parameters. + if (paramName == null) { + messageList.add(new String(buffer, 0, bufIdx, charset)); + bufIdx = 0; } + + // If we read a param name we know this is a named parameters. + else { + namedParameters.put(paramName, + new String(buffer, 0, bufIdx, charset)); + bufIdx = 0; + paramName = null; } } + else { buffer[bufIdx++] = (byte) nextByte; } + + nextByte = socket.getInputStream().read(); } - if (bufIdx > 0) messageList.add(new String(buffer, 0, bufIdx, charset)); + // If we have data in the buffer then there is a remaining parameter + // (named or unnamed) to be read. + if (bufIdx > 0) { + if (paramName == null) + messageList.add(new String(buffer, 0, bufIdx, charset)); + // If we read a param name we know this is a named parameters. + else namedParameters.put(paramName, + new String(buffer, 0, bufIdx, charset)); } - return (String[]) messageList.toArray(); } + return new Message(messageList, namedParameters); } + + protected byte[] formatMessage(String... parts) { + return formatMessage(new Message(parts)); } + + protected byte[] formatMessage(Message message) { + String fullMessage = START_TOKEN + message.parts.get(0); + + // Add all unnamed parameters. + for (int i = 1; i < message.parts.size(); i++) { + fullMessage += RECORD_SEPARATOR + message.parts.get(i); } + + // Add all named parameters. + for (Map.Entry entry : message.namedParameters.entrySet()) { + fullMessage += RECORD_SEPARATOR + entry.getKey().toString() + + FIELD_SEPARATOR + entry.getValue().toString(); } - 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); } } diff --git a/src/main/com/jdbernard/slf4j/LoggerOutputStream.java b/src/main/com/jdbernard/slf4j/LoggerOutputStream.java index c1da96a..83e0750 100644 --- a/src/main/com/jdbernard/slf4j/LoggerOutputStream.java +++ b/src/main/com/jdbernard/slf4j/LoggerOutputStream.java @@ -8,7 +8,7 @@ import java.io.IOException; import java.io.OutputStream; import org.slf4j.Logger; -public class LoggerOutputStream { +public class LoggerOutputStream extends OutputStream { public enum Level { TRACE, DEBUG, INFO, WARN, ERROR } @@ -22,7 +22,8 @@ public class LoggerOutputStream { public LoggerOutputStream(Logger logger, Level level) { this.logger = logger; - this.level = level; } + this.level = level; + buffer = new byte[DEFAULT_BUFFER_LENGTH]; } /** {@inheritDoc} */ public void write(final byte[] b, final int offset, final int length) @@ -31,15 +32,16 @@ public class LoggerOutputStream { throw new IOException("The output stream has been closed."); // Grow the buffer if we will reach the limit. - if (count + length >= buffer.length) { + if ((count + length) >= buffer.length) { final int newLength = - Math.max(buffer.length + DEFAULT_BUFFER_LENGTH, count + length); + 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); + System.arraycopy(b, count, buffer, offset, length); count += length; }