[Japi-cvs] SF.net SVN: japi: [238] libs/argparser/trunk/src
Status: Beta
Brought to you by:
christianhujer
From: <chr...@us...> - 2006-11-29 21:17:06
|
Revision: 238 http://svn.sourceforge.net/japi/?rev=238&view=rev Author: christianhujer Date: 2006-11-29 13:17:00 -0800 (Wed, 29 Nov 2006) Log Message: ----------- Improved converter feature. Integrated converter with ArgParser. Changed option names to value so it's default annotation argument. Modified Paths: -------------- libs/argparser/trunk/src/doc/examples/Head.java libs/argparser/trunk/src/doc/examples/Tail.java libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java libs/argparser/trunk/src/net/sf/japi/io/args/BasicCommand.java libs/argparser/trunk/src/net/sf/japi/io/args/Command.java libs/argparser/trunk/src/net/sf/japi/io/args/Option.java libs/argparser/trunk/src/net/sf/japi/io/args/converter/BooleanConverter.java libs/argparser/trunk/src/net/sf/japi/io/args/converter/Converter.java libs/argparser/trunk/src/net/sf/japi/io/args/converter/ConverterRegistry.java libs/argparser/trunk/src/net/sf/japi/io/args/converter/InputStreamConverter.java libs/argparser/trunk/src/net/sf/japi/io/args/converter/StringConverter.java libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java Added Paths: ----------- libs/argparser/trunk/src/META-INF/ libs/argparser/trunk/src/META-INF/services/ libs/argparser/trunk/src/META-INF/services/net.sf.japi.io.args.converter.Converter libs/argparser/trunk/src/doc/examples/Uniq.java libs/argparser/trunk/src/net/sf/japi/io/args/converter/AbstractConverter.java libs/argparser/trunk/src/net/sf/japi/io/args/converter/IntegerConverter.java Added: libs/argparser/trunk/src/META-INF/services/net.sf.japi.io.args.converter.Converter =================================================================== --- libs/argparser/trunk/src/META-INF/services/net.sf.japi.io.args.converter.Converter (rev 0) +++ libs/argparser/trunk/src/META-INF/services/net.sf.japi.io.args.converter.Converter 2006-11-29 21:17:00 UTC (rev 238) @@ -0,0 +1,4 @@ +net.sf.japi.io.args.converter.BooleanConverter +net.sf.japi.io.args.converter.InputStreamConverter +net.sf.japi.io.args.converter.IntegerConverter +net.sf.japi.io.args.converter.StringConverter Property changes on: libs/argparser/trunk/src/META-INF/services/net.sf.japi.io.args.converter.Converter ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + LF Modified: libs/argparser/trunk/src/doc/examples/Head.java =================================================================== --- libs/argparser/trunk/src/doc/examples/Head.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/doc/examples/Head.java 2006-11-29 21:17:00 UTC (rev 238) @@ -43,9 +43,9 @@ * Sets the number of lines to print. * @param lines number of lines to print */ - @Option(names = {"n", "lines"}) - public void setLines(final String lines) { - numItems = Integer.parseInt(lines); + @Option({"n", "lines"}) + public void setLines(final Integer lines) { + numItems = lines; printBytes = false; } @@ -53,16 +53,16 @@ * Sets the number of bytes to print. * @param bytes number of bytes to print. */ - @Option(names = {"c", "bytes"}) - public void setBytes(final String bytes) { - numItems = Integer.parseInt(bytes); + @Option({"c", "bytes"}) + public void setBytes(final Integer bytes) { + numItems = bytes; printBytes = true; } /** * Sets the command to be quiet. */ - @Option(names = {"q", "quiet", "silent"}) + @Option({"q", "quiet", "silent"}) public void setQuiet() { verbose = 0; } @@ -70,7 +70,7 @@ /** * Sets the command to be verbose. */ - @Option(names = {"v", "verbose"}) + @Option({"v", "verbose"}) public void setVerbose() { verbose = 2; } Modified: libs/argparser/trunk/src/doc/examples/Tail.java =================================================================== --- libs/argparser/trunk/src/doc/examples/Tail.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/doc/examples/Tail.java 2006-11-29 21:17:00 UTC (rev 238) @@ -40,9 +40,9 @@ * Sets the number of lines to print. * @param lines number of lines to print */ - @Option(names = {"n", "lines"}) - public void setLines(final String lines) { - numItems = Integer.parseInt(lines); + @Option({"n", "lines"}) + public void setLines(final Integer lines) { + numItems = lines; printBytes = false; } @@ -50,16 +50,16 @@ * Sets the number of bytes to print. * @param bytes number of bytes to print. */ - @Option(names = {"c", "bytes"}) - public void setBytes(final String bytes) { - numItems = Integer.parseInt(bytes); + @Option({"c", "bytes"}) + public void setBytes(final Integer bytes) { + numItems = bytes; printBytes = true; } /** * Sets the command to be quiet. */ - @Option(names = {"q", "quiet", "silent"}) + @Option({"q", "quiet", "silent"}) public void setQuiet() { verbose = 0; } @@ -67,7 +67,7 @@ /** * Sets the command to be verbose. */ - @Option(names = {"v", "verbose"}) + @Option({"v", "verbose"}) public void setVerbose() { verbose = 2; } Added: libs/argparser/trunk/src/doc/examples/Uniq.java =================================================================== --- libs/argparser/trunk/src/doc/examples/Uniq.java (rev 0) +++ libs/argparser/trunk/src/doc/examples/Uniq.java 2006-11-29 21:17:00 UTC (rev 238) @@ -0,0 +1,110 @@ +package examples; + +import net.sf.japi.io.args.BasicCommand; +import net.sf.japi.io.args.Option; +import org.jetbrains.annotations.NotNull; +import java.util.List; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.BufferedReader; + +/** + * Java implementation of the UNIX command <q>uniq</q> to demonstrate how to use the argparser library. + * @author <a href="mailto:ch...@ri...">Christian Hujer</a> + */ +public class Uniq extends BasicCommand { + + /** Whether to prefix lines with the count of their occurrence. */ + private boolean count; + + /** Whether to only print lines that occurred more than once. */ + private boolean repeated; + + /** Whether to ignore case. */ + private boolean ignoreCase; + + /** + * Sets that lines should prefixed with the count of their occurrence. + */ + @Option({"c", "count"}) + public void setCount() { + count = true; + } + + /** + * Sets that only lines that occurred more than once will be printed. + */ + @Option({"d", "repeated"}) + public void setRepeated() { + repeated = true; + } + + /** + * Sets that the case should be ignored. + */ + @Option({"i", "ignore-case"}) + public void setIgnoreCase() { + ignoreCase = true; + } + + /** {@inheritDoc} */ + @SuppressWarnings({"InstanceMethodNamingConvention"}) + public int run(final @NotNull List<String> args) throws Exception { + int returnCode = 0; + for (final String arg : args) { + try { + final InputStream in = new BufferedInputStream(new FileInputStream(arg)); + try { + uniq(in); + } finally { + in.close(); + } + } catch (final IOException e) { + returnCode = 1; + System.err.println(e); + } + } + return returnCode; + } + + /** + * Prints unique lines from the specified InputStream. + * @param in InputStream to print unique lines from. + * @throws IOException In case of I/O problems. + */ + private void uniq(@NotNull final InputStream in) throws IOException { + uniq(new InputStreamReader(in)); + } + + /** + * Prints unique lines from the specified Reader. + * @param in Reader to print unique lines from. + * @throws IOException In case of I/O problems. + */ + private void uniq(@NotNull final Reader in) throws IOException { + final BufferedReader bin = in instanceof BufferedReader ? (BufferedReader) in : new BufferedReader(in); + String previousLine = bin.readLine(); + if (previousLine != null) { + String line; + int lineCount = 1; + do { + line = bin.readLine(); + if (!(ignoreCase ? previousLine.equalsIgnoreCase(line) : previousLine.equals(line)) && (!repeated || lineCount > 1)) { + if (count) { + System.out.format("%7d %s%n", lineCount, previousLine); + } else { + System.out.println(previousLine); + } + lineCount = 0; + } + previousLine = line; + lineCount++; + } while (line != null); + } + } + +} // class Uniq Property changes on: libs/argparser/trunk/src/doc/examples/Uniq.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + LF Modified: libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java 2006-11-29 21:17:00 UTC (rev 238) @@ -25,6 +25,7 @@ import java.lang.reflect.Method; import java.util.*; import java.io.Closeable; +import net.sf.japi.io.args.converter.ConverterRegistry; /** * Parser for command line arguments. @@ -97,7 +98,7 @@ for (final Method requiredMethod : requiredMethods) { final Option option = requiredMethod.getAnnotation(Option.class); assert option != null; - missingOptions.add(option.names()[0]); + missingOptions.add(option.value()[0]); } throw new RequiredOptionsMissingException(missingOptions.toArray(new String[missingOptions.size()])); } @@ -112,7 +113,7 @@ for (final Method method : getOptionMethods(commandClass)) { final Option option = method.getAnnotation(Option.class); assert option != null; - for (final String optionName : option.names()) { + for (final String optionName : option.value()) { if (argumentMethods.containsKey(optionName)) { throw new IllegalArgumentException(commandClass.getName() + " declared option " + optionName + " twice."); } @@ -207,8 +208,8 @@ final int parameterCount = parameterTypes.length; if (parameterCount == 1) { final String arg = argIterator.next(); - method.invoke(command, arg); argIterator.remove(); + method.invoke(command, ConverterRegistry.convert(parameterTypes[0], arg)); } else if (parameterCount == 0) { method.invoke(command); } else { @@ -222,6 +223,8 @@ throw (TerminalException) cause; } System.err.println(e.getCause()); + } catch (final Exception e) { + e.printStackTrace(); } if (method.getAnnotation(Option.class).type() == OptionType.TERMINAL) { throw new TerminalException(); Modified: libs/argparser/trunk/src/net/sf/japi/io/args/BasicCommand.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/BasicCommand.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/BasicCommand.java 2006-11-29 21:17:00 UTC (rev 238) @@ -8,6 +8,7 @@ import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; +import org.jetbrains.annotations.NotNull; /** * BasicCommand is a base class for commands that provides the options --help, --exit and --noexit. @@ -34,24 +35,18 @@ } /** Exit Option. */ - @Option(names = {"exit"}) - public void setExiting() { - exiting = true; + @Option(value = {"exit"}) + public void setExiting(@NotNull final Boolean exiting) { + this.exiting = exiting; } - /** No Exit Option. */ - @Option(names = {"noexit"}) - public void setNotExiting() { - exiting = false; - } - /** {@inheritDoc} */ - public boolean isExiting() { + public Boolean isExiting() { return exiting; } /** Help Option. */ - @Option(type = OptionType.TERMINAL, names = {"h", "help"}) + @Option(type = OptionType.TERMINAL, value = {"h", "help"}) public void help() { final Set<Method> optionMethods = ArgParser.getOptionMethods(this); final Set<Class<?>> parameterTypes = new HashSet<Class<?>>(); @@ -59,7 +54,7 @@ int maxShort = 0; for (final Method optionMethod : optionMethods) { final Option option = optionMethod.getAnnotation(Option.class); - final String[] names = option.names(); + final String[] names = option.value(); int currentLong = 0; int currentShort = 0; for (final String name : names) { @@ -80,7 +75,7 @@ for (final Method optionMethod : optionMethods) { final Option option = optionMethod.getAnnotation(Option.class); final OptionType optionType = option.type(); - final String[] names = option.names(); + final String[] names = option.value(); final List<String> shortNames = new ArrayList<String>(); final List<String> longNames = new ArrayList<String>(); for (final String name : names) { Modified: libs/argparser/trunk/src/net/sf/japi/io/args/Command.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/Command.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/Command.java 2006-11-29 21:17:00 UTC (rev 238) @@ -45,6 +45,6 @@ * Return whether after running this Command, {@link System#exit(int)} should be invoked. * @return <code>true</code> if {@link ArgParser} should invoke {@link System#exit(int)} after this command, otherwise <code>false</code>. */ - boolean isExiting(); + Boolean isExiting(); } // interface Command Modified: libs/argparser/trunk/src/net/sf/japi/io/args/Option.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/Option.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/Option.java 2006-11-29 21:17:00 UTC (rev 238) @@ -48,7 +48,7 @@ * @note the supplied string values MUST consist of ASCII-letters only (match regex <code>[a-zA-Z]+</code>). * @return option names */ - String[] names(); + String[] value(); /** * The option key, used for i18n/l10n. Added: libs/argparser/trunk/src/net/sf/japi/io/args/converter/AbstractConverter.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/converter/AbstractConverter.java (rev 0) +++ libs/argparser/trunk/src/net/sf/japi/io/args/converter/AbstractConverter.java 2006-11-29 21:17:00 UTC (rev 238) @@ -0,0 +1,38 @@ +package net.sf.japi.io.args.converter; + +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * Base class for the default converters. + * @author <a href="mailto:ch...@ri...">Christian Hujer</a> + */ +abstract class AbstractConverter<T> implements Converter<T> { + + /** The target class. */ + private final Class<T> targetClass; + + /** + * Create an AbstractConverter. + * @param targetClass TargetClass + */ + AbstractConverter(final Class<T> targetClass) { + this.targetClass = targetClass; + } + + /** {@inheritDoc} */ + public final Class<T> getTargetClass() { + return targetClass; + } + + /** {@inheritDoc} */ + public final String getDisplayName() { + return ResourceBundle.getBundle("net.sf.japi.io.args.converter.names").getString(targetClass.getName()); + } + + /** {@inheritDoc} */ + public final String getDisplayName(final Locale locale) { + return ResourceBundle.getBundle("net.sf.japi.io.args.converter.names", locale).getString(targetClass.getName()); + } + +} // class AbstractConverter Property changes on: libs/argparser/trunk/src/net/sf/japi/io/args/converter/AbstractConverter.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + LF Modified: libs/argparser/trunk/src/net/sf/japi/io/args/converter/BooleanConverter.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/converter/BooleanConverter.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/converter/BooleanConverter.java 2006-11-29 21:17:00 UTC (rev 238) @@ -4,8 +4,15 @@ * Converter which converts a String into a Boolean. * @author <a href="mailto:ch...@ri...">Christian Hujer</a> */ -public class BooleanConverter implements Converter<Boolean> { +public class BooleanConverter extends AbstractConverter<Boolean> { + /** + * Create a BooleanConverter. + */ + public BooleanConverter() { + super(Boolean.class); + } + /** {@inheritDoc} */ public Boolean convert(final String arg) throws Exception { return Boolean.valueOf(arg); Modified: libs/argparser/trunk/src/net/sf/japi/io/args/converter/Converter.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/converter/Converter.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/converter/Converter.java 2006-11-29 21:17:00 UTC (rev 238) @@ -1,5 +1,7 @@ package net.sf.japi.io.args.converter; +import java.util.Locale; + /** * The Converter interface is used for converters that convert Strings into other types. * @author <a href="mailto:ch...@ri...">Christian Hujer</a> @@ -14,4 +16,23 @@ */ T convert(final String arg) throws Exception; + /** + * Returns the Class this Converter is for. + * @return The Class this Converter is for. + */ + Class<T> getTargetClass(); + + /** + * Returns a display name for the type of this Converter. + * @return A display name for the type of this Converter. + */ + String getDisplayName(); + + /** + * Returns a display name for the type of this Converter. + * @param locale Locale to get display name for. + * @return A display name for the type of this Converter in the specified locale. + */ + String getDisplayName(final Locale locale); + } // interface Convert Modified: libs/argparser/trunk/src/net/sf/japi/io/args/converter/ConverterRegistry.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/converter/ConverterRegistry.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/converter/ConverterRegistry.java 2006-11-29 21:17:00 UTC (rev 238) @@ -1,10 +1,9 @@ package net.sf.japi.io.args.converter; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; -import java.util.HashMap; -import java.util.Enumeration; -import java.net.URL; -import java.io.IOException; +import sun.misc.Service; /** * Registry for Converters. @@ -32,14 +31,8 @@ */ private static ConverterRegistry createSingletonInstance() { final ConverterRegistry instance = new ConverterRegistry(); - try { - for (final Enumeration<URL> urls = ConverterRegistry.class.getClassLoader().getResources("META-INF/services/net.sf.japi.io.args.ConverterRegistry"); urls.hasMoreElements() ; ) { - final URL url = urls.nextElement(); - // TODO - } - } catch (final IOException e) { - // TODO - e.printStackTrace(); + for (final Iterator<Converter<?>> converters = Service.providers(Converter.class); converters.hasNext();) { + instance.register(converters.next()); } return instance; } @@ -63,21 +56,31 @@ /** * Register a Converter for a specific class. - * @param clazz Class Class to register converter for * @param converter Converter to register */ - public <T> void register(final Class<T> clazz, final Converter<T> converter) { - converters.put(clazz, converter); - for (Class<?> superClass = clazz; (superClass = superClass.getSuperclass()) != null;) { + public <T> void register(final Converter<T> converter) { + converters.put(converter.getTargetClass(), converter); + for (Class<?> superClass = converter.getTargetClass(); (superClass = superClass.getSuperclass()) != null;) { if (!converters.containsKey(superClass)) { converters.put(superClass, converter); } } - for (final Class<?> interf : clazz.getInterfaces()) { + for (final Class<?> interf : converter.getTargetClass().getInterfaces()) { if (!converters.containsKey(interf)) { converters.put(interf, converter); } } } + /** + * Convenience method to convert a String to the desired target type using the default ConverterRegistry. + * @param targetType target type to convert to. + * @param s String to convert + * @return Converted String in the desired target type. + * @throws Exception in case the conversion failed. + */ + public static <T> T convert(final Class<T> targetType, final String s) throws Exception { + return getInstance().getConverter(targetType).convert(s); + } + } // class ConverterRegistry Modified: libs/argparser/trunk/src/net/sf/japi/io/args/converter/InputStreamConverter.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/converter/InputStreamConverter.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/converter/InputStreamConverter.java 2006-11-29 21:17:00 UTC (rev 238) @@ -10,8 +10,15 @@ * Converter that converts a String into an InputStream. * @author <a href="mailto:ch...@ri...">Christian Hujer</a> */ -public class InputStreamConverter implements Converter<InputStream> { +public class InputStreamConverter extends AbstractConverter<InputStream> { + /** + * Create an InputStreamConverter. + */ + public InputStreamConverter() { + super(InputStream.class); + } + /** {@inheritDoc} */ public InputStream convert(final String arg) throws FileNotFoundException { try { Added: libs/argparser/trunk/src/net/sf/japi/io/args/converter/IntegerConverter.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/converter/IntegerConverter.java (rev 0) +++ libs/argparser/trunk/src/net/sf/japi/io/args/converter/IntegerConverter.java 2006-11-29 21:17:00 UTC (rev 238) @@ -0,0 +1,21 @@ +package net.sf.japi.io.args.converter; + +/** + * Converter which converts a String into a an Integer. + * @author <a href="mailto:ch...@ri...">Christian Hujer</a> + */ +public class IntegerConverter extends AbstractConverter<Integer> { + + /** + * Create an IntegerConverter. + */ + public IntegerConverter() { + super(Integer.class); + } + + /** {@inheritDoc} */ + public Integer convert(final String arg) throws Exception { + return Integer.valueOf(arg); + } + +} // class IntegerConverter Property changes on: libs/argparser/trunk/src/net/sf/japi/io/args/converter/IntegerConverter.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + LF Modified: libs/argparser/trunk/src/net/sf/japi/io/args/converter/StringConverter.java =================================================================== --- libs/argparser/trunk/src/net/sf/japi/io/args/converter/StringConverter.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/net/sf/japi/io/args/converter/StringConverter.java 2006-11-29 21:17:00 UTC (rev 238) @@ -4,8 +4,15 @@ * Dummy Converter which "converts" a String into a String by simply returning it. * @author <a href="mailto:ch...@ri...">Christian Hujer</a> */ -public class StringConverter implements Converter<String> { +public class StringConverter extends AbstractConverter<String> { + /** + * Create a StringConverter. + */ + public StringConverter() { + super(String.class); + } + /** {@inheritDoc} */ public String convert(final String arg) throws Exception { return arg; Modified: libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java =================================================================== --- libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java 2006-11-26 23:47:21 UTC (rev 237) +++ libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java 2006-11-29 21:17:00 UTC (rev 238) @@ -53,7 +53,7 @@ * Set the value of the input option. * @param input Value of the input option. */ - @Option(type = OptionType.REQUIRED, names = {"i", "input"}) + @Option(type = OptionType.REQUIRED, value = {"i", "input"}) public void setInput(final String input) { this.input = input; } @@ -62,7 +62,7 @@ * Set the value of the foo option. * @param foo Value of the foo option. */ - @Option(names = {"f", "b", "foo", "bar", "buzz"}) + @Option(value = {"f", "b", "foo", "bar", "buzz"}) public void setFoo(final String foo) { // ignored } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |