Added LightOptionParser, NullOutputStream, bugfixes.
LightOptionParser ----------------- Lightweight, fairly featureful option parsing mechanism idiomatic to Groovy. Takes in a map of parameter definitions and returns a map of option values and arguments. NullOutputStream ---------------- Ignores all data sent its way. ParameterizedSocket ------------------- Added trace and debug logging to the message handling code. SmartConfig ----------- Fixed a bug where a property lookup on a non-existent property with no default given caused a null pointer exception trying to resolve the class of the default value.
This commit is contained in:
parent
a186d6a09d
commit
c887a49f8c
@ -1,6 +1,6 @@
|
|||||||
#Thu, 22 Nov 2012 14:39:26 -0600
|
#Tue, 27 Nov 2012 08:38:33 -0600
|
||||||
name=jdb-util
|
name=jdb-util
|
||||||
version=1.7
|
version=1.8
|
||||||
lib.local=true
|
lib.local=true
|
||||||
|
|
||||||
build.number=16
|
build.number=2
|
||||||
|
@ -12,6 +12,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
public class ParameterizedSocket {
|
public class ParameterizedSocket {
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ public class ParameterizedSocket {
|
|||||||
private Socket socket;
|
private Socket socket;
|
||||||
private byte[] buffer;
|
private byte[] buffer;
|
||||||
private Charset charset;
|
private Charset charset;
|
||||||
|
private Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
public ParameterizedSocket(Socket socket, int bufferSize) {
|
public ParameterizedSocket(Socket socket, int bufferSize) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
@ -58,7 +61,8 @@ public class ParameterizedSocket {
|
|||||||
|
|
||||||
public ParameterizedSocket(String ipAddress, int port, int bufferSize)
|
public ParameterizedSocket(String ipAddress, int port, int bufferSize)
|
||||||
throws UnknownHostException, IOException {
|
throws UnknownHostException, IOException {
|
||||||
this(new Socket(ipAddress, port), bufferSize); }
|
this(new Socket(ipAddress, port), bufferSize);
|
||||||
|
log.trace("Opened a socket to {}:{}", ipAddress, port); }
|
||||||
|
|
||||||
public ParameterizedSocket(Socket socket)
|
public ParameterizedSocket(Socket socket)
|
||||||
throws UnknownHostException, IOException {
|
throws UnknownHostException, IOException {
|
||||||
@ -76,6 +80,7 @@ public class ParameterizedSocket {
|
|||||||
public void writeMessage(Message message) throws IOException {
|
public void writeMessage(Message message) throws IOException {
|
||||||
if (message == null || message.parts.size() == 0) return;
|
if (message == null || message.parts.size() == 0) return;
|
||||||
|
|
||||||
|
log.debug("Writing a message: [{}].", message);
|
||||||
byte[] messageBytes = formatMessage(message);
|
byte[] messageBytes = formatMessage(message);
|
||||||
socket.getOutputStream().write(messageBytes); }
|
socket.getOutputStream().write(messageBytes); }
|
||||||
|
|
||||||
@ -83,6 +88,8 @@ public class ParameterizedSocket {
|
|||||||
List<String> messageList = new ArrayList<String>();
|
List<String> messageList = new ArrayList<String>();
|
||||||
Map<String, String> namedParameters = new HashMap<String, String>();
|
Map<String, String> namedParameters = new HashMap<String, String>();
|
||||||
|
|
||||||
|
log.trace("Reading a message.");
|
||||||
|
|
||||||
if (socket.getInputStream().read() != START_TOKEN_BYTE) {
|
if (socket.getInputStream().read() != START_TOKEN_BYTE) {
|
||||||
byte[] errMsg = formatMessage("ERROR", "Invalid command (expected START_TOKEN).");
|
byte[] errMsg = formatMessage("ERROR", "Invalid command (expected START_TOKEN).");
|
||||||
socket.getOutputStream().write(errMsg); }
|
socket.getOutputStream().write(errMsg); }
|
||||||
@ -135,7 +142,9 @@ public class ParameterizedSocket {
|
|||||||
else namedParameters.put(paramName,
|
else namedParameters.put(paramName,
|
||||||
new String(buffer, 0, bufIdx, charset)); }
|
new String(buffer, 0, bufIdx, charset)); }
|
||||||
|
|
||||||
return new Message(messageList, namedParameters); }
|
Message message = new Message(messageList, namedParameters);
|
||||||
|
log.debug("Message read: [{}].", message);
|
||||||
|
return message; }
|
||||||
|
|
||||||
protected byte[] formatMessage(String... parts) {
|
protected byte[] formatMessage(String... parts) {
|
||||||
return formatMessage(new Message(parts)); }
|
return formatMessage(new Message(parts)); }
|
||||||
|
86
src/main/com/jdbernard/util/LightOptionParser.groovy
Normal file
86
src/main/com/jdbernard/util/LightOptionParser.groovy
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* # Light Option Parser
|
||||||
|
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||||
|
*
|
||||||
|
* LightOptionParser parses command-line style options.
|
||||||
|
* TODO: complete docs.
|
||||||
|
*/
|
||||||
|
package com.jdbernard.util
|
||||||
|
|
||||||
|
public class LightOptionParser {
|
||||||
|
|
||||||
|
public static def parseOptions(def optionDefinitions, List args) {
|
||||||
|
|
||||||
|
def returnOpts = [:]
|
||||||
|
def foundOpts = [:]
|
||||||
|
def optionArgIndices = []
|
||||||
|
|
||||||
|
/// Find all the options.
|
||||||
|
args.eachWithIndex { arg, idx ->
|
||||||
|
if (arg.startsWith('--')) foundOpts[arg.substring(2)] = [idx: idx]
|
||||||
|
else if (arg.startsWith('-')) foundOpts[arg.substring(1)] = [idx: idx] }
|
||||||
|
|
||||||
|
/// Look for option arguments.
|
||||||
|
foundOpts.each { foundName, optInfo ->
|
||||||
|
|
||||||
|
def retVal
|
||||||
|
|
||||||
|
/// Find the definition for this option.
|
||||||
|
def optDef = optionDefinitions.find {
|
||||||
|
it.key == foundName || it.value.longName == foundName }
|
||||||
|
def optName = optDef.key
|
||||||
|
optDef = optDef.value
|
||||||
|
|
||||||
|
if (!optDef) throw new IllegalArgumentException(
|
||||||
|
"Unrecognized option: '${args[optInfo.idx]}.")
|
||||||
|
|
||||||
|
/// Remember the option index for later.
|
||||||
|
optionArgIndices << optInfo.idx
|
||||||
|
|
||||||
|
/// If there are no arguments, this is a flag.
|
||||||
|
if ((optDef.arguments ?: 0) == 0) retVal = true
|
||||||
|
|
||||||
|
/// Otherwise, read in the arguments
|
||||||
|
if (optDef.arguments && optDef.arguments > 0) {
|
||||||
|
|
||||||
|
/// Not enough arguments left
|
||||||
|
if ((optInfo.idx + optDef.arguments) >= args.size()) {
|
||||||
|
throw new Exception("Option '${args[optInfo.idx]}' " +
|
||||||
|
"expects ${optDef.arguments} arguments.") }
|
||||||
|
|
||||||
|
int firstArgIdx = optInfo.idx + 1
|
||||||
|
|
||||||
|
/// Case of only one argument
|
||||||
|
if (optDef.arguments == 1)
|
||||||
|
retVal = args[firstArgIdx]
|
||||||
|
/// Case of multiple arguments
|
||||||
|
else retVal = args[firstArgIdx..<(firstArgIdx + optDef.arguments)]
|
||||||
|
|
||||||
|
/// Remember all the option argument indices for later.
|
||||||
|
(firstArgIdx..<(firstArgIdx + optDef.arguments)).each {
|
||||||
|
optionArgIndices << it }}
|
||||||
|
|
||||||
|
/// Store the value in the returnOpts map
|
||||||
|
returnOpts[optName] = retVal
|
||||||
|
if (optDef.longName) returnOpts[optDef.longName] = retVal }
|
||||||
|
|
||||||
|
/// Check that all required options have been found.
|
||||||
|
optionDefinitions.each { optName, optDef ->
|
||||||
|
/// If this is a required field
|
||||||
|
if (optDef.required &&
|
||||||
|
/// and it has not been found, by either it's short or long name.
|
||||||
|
!(returnOpts[optName] ||
|
||||||
|
(optDef.longName && returnOpts[longName])))
|
||||||
|
|
||||||
|
throw new Exception("Missing required option: '-${optName}'.") }
|
||||||
|
|
||||||
|
/// Remove all the option arguments from the args list and return just
|
||||||
|
/// the non-option arguments.
|
||||||
|
optionArgIndices.sort().reverse().each { args.remove(it) }
|
||||||
|
|
||||||
|
//optionArgIndices = optionArgIndices.collect { args[it] }
|
||||||
|
//args.removeAll(optionArgIndices)
|
||||||
|
|
||||||
|
returnOpts.args = args
|
||||||
|
return returnOpts }
|
||||||
|
}
|
13
src/main/com/jdbernard/util/NullOutputStream.java
Normal file
13
src/main/com/jdbernard/util/NullOutputStream.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.jdbernard.util;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class NullOutputStream extends OutputStream {
|
||||||
|
|
||||||
|
public NullOutputStream() {}
|
||||||
|
public void close() { }
|
||||||
|
public void flush() { }
|
||||||
|
public void write(int b) { }
|
||||||
|
public void write(byte[] b) { }
|
||||||
|
public void write(byte[] b, int offset, int length) { }
|
||||||
|
}
|
@ -71,7 +71,7 @@ public class SmartConfig {
|
|||||||
log.trace("No known interpretation, casting to type of " +
|
log.trace("No known interpretation, casting to type of " +
|
||||||
"default argument.")
|
"default argument.")
|
||||||
|
|
||||||
val = val.asType(defVal.class)
|
val = val.asType(defVal?.class ?: String)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user