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
|
||||
version=1.7
|
||||
version=1.8
|
||||
lib.local=true
|
||||
|
||||
build.number=16
|
||||
build.number=2
|
||||
|
@ -12,6 +12,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class ParameterizedSocket {
|
||||
|
||||
@ -50,6 +52,7 @@ public class ParameterizedSocket {
|
||||
private Socket socket;
|
||||
private byte[] buffer;
|
||||
private Charset charset;
|
||||
private Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public ParameterizedSocket(Socket socket, int bufferSize) {
|
||||
this.socket = socket;
|
||||
@ -58,7 +61,8 @@ public class ParameterizedSocket {
|
||||
|
||||
public ParameterizedSocket(String ipAddress, int port, int bufferSize)
|
||||
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)
|
||||
throws UnknownHostException, IOException {
|
||||
@ -76,6 +80,7 @@ public class ParameterizedSocket {
|
||||
public void writeMessage(Message message) throws IOException {
|
||||
if (message == null || message.parts.size() == 0) return;
|
||||
|
||||
log.debug("Writing a message: [{}].", message);
|
||||
byte[] messageBytes = formatMessage(message);
|
||||
socket.getOutputStream().write(messageBytes); }
|
||||
|
||||
@ -83,6 +88,8 @@ public class ParameterizedSocket {
|
||||
List<String> messageList = new ArrayList<String>();
|
||||
Map<String, String> namedParameters = new HashMap<String, String>();
|
||||
|
||||
log.trace("Reading a message.");
|
||||
|
||||
if (socket.getInputStream().read() != START_TOKEN_BYTE) {
|
||||
byte[] errMsg = formatMessage("ERROR", "Invalid command (expected START_TOKEN).");
|
||||
socket.getOutputStream().write(errMsg); }
|
||||
@ -135,7 +142,9 @@ public class ParameterizedSocket {
|
||||
else namedParameters.put(paramName,
|
||||
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) {
|
||||
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 " +
|
||||
"default argument.")
|
||||
|
||||
val = val.asType(defVal.class)
|
||||
val = val.asType(defVal?.class ?: String)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user