http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/ArgumentInfo.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/ArgumentInfo.java b/commons/src/main/java/com/twitter/common/args/ArgumentInfo.java new file mode 100644 index 0000000..15daa11 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/ArgumentInfo.java @@ -0,0 +1,250 @@ +// ================================================================================================= +// Copyright 2012 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.List; + +import javax.annotation.Nullable; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.reflect.TypeToken; + +import com.twitter.common.args.constraints.NotNullVerifier; +import com.twitter.common.base.MorePreconditions; + +/** + * Description of a command line {@link Arg} instance. + */ +public abstract class ArgumentInfo<T> { + static final ImmutableSet<String> HELP_ARGS = ImmutableSet.of("h", "help"); + + /** + * Extracts the {@code Arg} from the given field. + * + * @param field The field containing the {@code Arg}. + * @param instance An optional object instance containing the field. + * @return The extracted {@code} Arg. + * @throws IllegalArgumentException If the field does not contain an arg. + */ + protected static Arg<?> getArgForField(Field field, Optional<?> instance) { + Preconditions.checkArgument(field.getType() == Arg.class, + "Field is annotated for argument parsing but is not of Arg type: " + field); + Preconditions.checkArgument(Modifier.isStatic(field.getModifiers()) || instance.isPresent(), + "Non-static argument fields are not supported, found " + field); + + field.setAccessible(true); + try { + return (Arg<?>) field.get(instance.orNull()); + } catch (IllegalAccessException e) { + throw new RuntimeException("Cannot get arg value for " + field); + } + } + + private final String canonicalName; + private final String name; + private final String help; + private final boolean argFile; + private final Arg<T> arg; + private final TypeToken<T> type; + private final List<Annotation> verifierAnnotations; + @Nullable private final Class<? extends Parser<? extends T>> parser; + + /** + * Creates a new {@code ArgsInfo}. + * + * @param canonicalName A fully qualified name for the argument. + * @param name The simple name for the argument. + * @param help Help string. + * @param argFile If argument file is allowed. + * @param arg Argument object. + * @param type Concrete argument type. + * @param verifierAnnotations {@link com.twitter.common.args.Verifier} annotations for this + * argument. + * @param parser Parser for the argument type. + */ + protected ArgumentInfo( + String canonicalName, + String name, + String help, + boolean argFile, + Arg<T> arg, + TypeToken<T> type, + List<Annotation> verifierAnnotations, + @Nullable Class<? extends Parser<? extends T>> parser) { + + this.canonicalName = MorePreconditions.checkNotBlank(canonicalName); + this.name = MorePreconditions.checkNotBlank(name); + this.help = MorePreconditions.checkNotBlank(help); + this.argFile = argFile; + this.arg = Preconditions.checkNotNull(arg); + this.type = Preconditions.checkNotNull(type); + this.verifierAnnotations = ImmutableList.copyOf(verifierAnnotations); + this.parser = parser; + } + + /** + * Return the name of the command line argument. In an optional argument, this is expressed on + * the command line by "-name=value"; whereas, for a positional argument, the name indicates + * the type/function. + */ + public final String getName() { + return name; + } + + /** + * Return the fully-qualified name of the command line argument. This is used as a command-line + * optional argument, as in: -prefix.name=value. Prefix is typically a java package and class like + * "com.twitter.myapp.MyClass". The difference between a canonical name and a regular name is that + * it is in some circumstances for two names to collide; the canonical name, then, disambiguates. + */ + public final String getCanonicalName() { + return canonicalName; + } + + /** + * Returns the instructions for this command-line argument. This is typically used when the + * executable is passed the -help flag. + */ + public String getHelp() { + return help; + } + + /** + * Returns whether an argument file is allowed for this argument. + */ + public boolean argFile() { + return argFile; + } + + /** + * Returns the Arg associated with this command-line argument. The Arg<?> is a mutable container + * cell that holds the value passed-in on the command line, after parsing and validation. + */ + public Arg<T> getArg() { + return arg; + } + + /** + * Sets the value of the {@link Arg} described by this {@code ArgumentInfo}. + * + * @param value The value to set. + */ + protected void setValue(@Nullable T value) { + arg.set(value); + } + + /** + * Returns the TypeToken that represents the type of this command-line argument. + */ + public TypeToken<T> getType() { + return type; + } + + @Override + public boolean equals(Object object) { + return (object instanceof ArgumentInfo) && arg.equals(((ArgumentInfo) object).arg); + } + + @Override + public int hashCode() { + return arg.hashCode(); + } + + /** + * Finds an appropriate parser for this args underlying value type. + * + * @param parserOracle The registry of known parsers. + * @return A parser that can parse strings into the underlying argument type. + * @throws IllegalArgumentException If no parser was found for the underlying argument type. + */ + protected Parser<? extends T> getParser(ParserOracle parserOracle) { + Preconditions.checkNotNull(parserOracle); + if (parser == null || NoParser.class.equals(parser)) { + return parserOracle.get(type); + } else { + try { + return parser.newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException("Failed to instantiate parser " + parser); + } catch (IllegalAccessException e) { + throw new RuntimeException("No access to instantiate parser " + parser); + } + } + } + + static class ValueVerifier<T> { + private final Verifier<? super T> verifier; + private final Annotation annotation; + + ValueVerifier(Verifier<? super T> verifier, Annotation annotation) { + this.verifier = verifier; + this.annotation = annotation; + } + + void verify(@Nullable T value) { + if (value != null || verifier instanceof NotNullVerifier) { + verifier.verify(value, annotation); + } + } + + String toString(Class<? extends T> rawType) { + return verifier.toString(rawType, annotation); + } + } + + private Iterable<ValueVerifier<T>> getVerifiers(final Verifiers verifierOracle) { + Function<Annotation, Optional<ValueVerifier<T>>> toVerifier = + new Function<Annotation, Optional<ValueVerifier<T>>>() { + @Override public Optional<ValueVerifier<T>> apply(Annotation annotation) { + @Nullable Verifier<? super T> verifier = verifierOracle.get(type, annotation); + if (verifier != null) { + return Optional.of(new ValueVerifier<T>(verifier, annotation)); + } else { + return Optional.absent(); + } + } + }; + return Optional.presentInstances(Iterables.transform(verifierAnnotations, toVerifier)); + } + + void verify(Verifiers verifierOracle) { + @Nullable T value = getArg().uncheckedGet(); + for (ValueVerifier<T> valueVerifier : getVerifiers(verifierOracle)) { + valueVerifier.verify(value); + } + } + + ImmutableList<String> collectConstraints(Verifiers verifierOracle) { + @SuppressWarnings("unchecked") // type.getType() is T + final Class<? extends T> rawType = (Class<? extends T>) type.getRawType(); + return FluentIterable.from(getVerifiers(verifierOracle)).transform( + new Function<ValueVerifier<T>, String>() { + @Override public String apply(ValueVerifier<T> verifier) { + return verifier.toString(rawType); + } + }).toList(); + } +}
http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/OptionInfo.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/OptionInfo.java b/commons/src/main/java/com/twitter/common/args/OptionInfo.java new file mode 100644 index 0000000..1f38195 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/OptionInfo.java @@ -0,0 +1,204 @@ +// ================================================================================================= +// Copyright 2012 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args; + +import java.io.File; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import com.google.common.base.Charsets; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; +import com.google.common.base.Strings; +import com.google.common.io.Files; +import com.google.common.reflect.TypeToken; + +import com.twitter.common.args.apt.Configuration; +import com.twitter.common.base.Function; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Description of a command line option/flag such as -foo=bar. + */ +public final class OptionInfo<T> extends ArgumentInfo<T> { + static final String ARG_NAME_RE = "[\\w\\-\\.]+"; + static final String ARG_FILE_HELP_TEMPLATE + = "%s This argument supports @argfile format. See details below."; + + private static final Pattern ARG_NAME_PATTERN = Pattern.compile(ARG_NAME_RE); + private static final String NEGATE_BOOLEAN = "no_"; + private static final String ARG_FILE_INDICATOR = "@"; + + /** + * Factory method to create a OptionInfo from a field. + * + * @param field The field must contain a {@link Arg}. + * @return an OptionInfo describing the field. + */ + static OptionInfo<?> createFromField(Field field) { + return createFromField(field, null); + } + + /** + * Factory method to create a OptionInfo from a field. + * + * @param field The field must contain a {@link Arg}. + * @param instance The object containing the non-static Arg instance or else null if the Arg + * field is static. + * @return an OptionInfo describing the field. + */ + static OptionInfo<?> createFromField(final Field field, @Nullable Object instance) { + CmdLine cmdLine = field.getAnnotation(CmdLine.class); + if (cmdLine == null) { + throw new Configuration.ConfigurationException( + "No @CmdLine Arg annotation for field " + field); + } + + String name = cmdLine.name(); + Preconditions.checkNotNull(name); + checkArgument(!HELP_ARGS.contains(name), + String.format("Argument name '%s' is reserved for builtin argument help", name)); + checkArgument(ARG_NAME_PATTERN.matcher(name).matches(), + String.format("Argument name '%s' does not match required pattern %s", + name, ARG_NAME_RE)); + + Function<String, String> canonicalizer = new Function<String, String>() { + @Override public String apply(String name) { + return field.getDeclaringClass().getCanonicalName() + "." + name; + } + }; + + @SuppressWarnings({"unchecked", "rawtypes"}) // we have no way to know the type here + OptionInfo<?> optionInfo = new OptionInfo( + canonicalizer, + name, + getCmdLineHelp(cmdLine), + cmdLine.argFile(), + ArgumentInfo.getArgForField(field, Optional.fromNullable(instance)), + TypeUtil.getTypeParamTypeToken(field), + Arrays.asList(field.getAnnotations()), + cmdLine.parser()); + + return optionInfo; + } + + private static String getCmdLineHelp(CmdLine cmdLine) { + String help = cmdLine.help(); + + if (cmdLine.argFile()) { + help = String.format(ARG_FILE_HELP_TEMPLATE, help, cmdLine.name(), cmdLine.name()); + } + + return help; + } + + private final Function<String, String> canonicalizer; + + private OptionInfo( + Function<String, String> canonicalizer, + String name, + String help, + boolean argFile, + Arg<T> arg, + TypeToken<T> type, + List<Annotation> verifierAnnotations, + @Nullable Class<? extends Parser<T>> parser) { + + super(canonicalizer.apply(name), name, help, argFile, arg, type, + verifierAnnotations, parser); + this.canonicalizer = canonicalizer; + } + + /** + * Parses the value and store result in the {@link Arg} contained in this {@code OptionInfo}. + */ + void load(ParserOracle parserOracle, String optionName, String value) { + Parser<? extends T> parser = getParser(parserOracle); + + String finalValue = value; + + // If "-arg=@file" is allowed and specified, then we read the value from the file + // and use it as the raw value to be parsed for the argument. + if (argFile() + && !Strings.isNullOrEmpty(value) + && value.startsWith(ARG_FILE_INDICATOR)) { + finalValue = getArgFileContent(optionName, value.substring(ARG_FILE_INDICATOR.length())); + } + + Object result = parser.parse(parserOracle, getType().getType(), finalValue); // [A] + + // If the arg type is boolean, check if the command line uses the negated boolean form. + if (isBoolean()) { + if (Predicates.in(Arrays.asList(getNegatedName(), getCanonicalNegatedName())) + .apply(optionName)) { + result = !(Boolean) result; // [B] + } + } + + // We know result is T at line [A] but throw this type information away to allow negation if T + // is Boolean at line [B] + @SuppressWarnings("unchecked") + T parsed = (T) result; + + setValue(parsed); + } + + boolean isBoolean() { + return getType().getRawType() == Boolean.class; + } + + /** + * Similar to the simple name, but with boolean arguments appends "no_", as in: + * {@code -no_fire=false} + */ + String getNegatedName() { + return NEGATE_BOOLEAN + getName(); + } + + /** + * Similar to the canonical name, but with boolean arguments appends "no_", as in: + * {@code -com.twitter.common.MyApp.no_fire=false} + */ + String getCanonicalNegatedName() { + return canonicalizer.apply(getNegatedName()); + } + + private String getArgFileContent(String optionName, String argFilePath) + throws IllegalArgumentException { + if (argFilePath.isEmpty()) { + throw new IllegalArgumentException( + String.format("Invalid null/empty value for argument '%s'.", optionName)); + } + + try { + return Files.toString(new File(argFilePath), Charsets.UTF_8); + } catch (IOException e) { + throw new IllegalArgumentException( + String.format("Unable to read argument '%s' value from file '%s'.", + optionName, argFilePath), + e); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/Parsers.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/Parsers.java b/commons/src/main/java/com/twitter/common/args/Parsers.java new file mode 100644 index 0000000..c879294 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/Parsers.java @@ -0,0 +1,117 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.common.reflect.TypeToken; + +import com.twitter.common.args.apt.Configuration; +import com.twitter.common.args.apt.Configuration.ParserInfo; + +import static com.google.common.base.Preconditions.checkArgument; + +import static com.twitter.common.args.apt.Configuration.ConfigurationException; + +/** + * A registry of Parsers for different supported argument types. + * + * @author William Farner + */ +public final class Parsers implements ParserOracle { + + public static final Splitter MULTI_VALUE_SPLITTER = + Splitter.on(",").trimResults().omitEmptyStrings(); + + private static final Function<ParserInfo, Class<?>> INFO_TO_PARSED_TYPE = + new Function<ParserInfo, Class<?>>() { + @Override public Class<?> apply(ParserInfo parserInfo) { + try { + return Class.forName(parserInfo.parsedType); + } catch (ClassNotFoundException e) { + throw new ConfigurationException(e); + } + } + }; + + @VisibleForTesting + static final Function<ParserInfo, Parser<?>> INFO_TO_PARSER = + new Function<ParserInfo, Parser<?>>() { + @Override public Parser<?> apply(ParserInfo parserInfo) { + try { + Class<?> parserClass = Class.forName(parserInfo.parserClass); + Constructor<?> constructor = parserClass.getDeclaredConstructor(); + constructor.setAccessible(true); + return (Parser<?>) constructor.newInstance(); + } catch (ClassNotFoundException e) { + throw new ConfigurationException(e); + } catch (InstantiationException e) { + throw new ConfigurationException(e); + } catch (IllegalAccessException e) { + throw new ConfigurationException(e); + } catch (NoSuchMethodException e) { + throw new ConfigurationException(e); + } catch (InvocationTargetException e) { + throw new ConfigurationException(e); + } + } + }; + + private final ImmutableMap<Class<?>, Parser<?>> registry; + + /** + * Creates a new parser registry over the specified {@code parsers}. + * + * @param parsers The parsers to register. + */ + public Parsers(Map<Class<?>, Parser<?>> parsers) { + Preconditions.checkNotNull(parsers); + registry = ImmutableMap.copyOf(parsers); + } + + @Override + public <T> Parser<T> get(TypeToken<T> type) throws IllegalArgumentException { + Parser<?> parser; + Class<?> explicitClass = type.getRawType(); + while (((parser = registry.get(explicitClass)) == null) && (explicitClass != null)) { + explicitClass = explicitClass.getSuperclass(); + } + checkArgument(parser != null, "No parser found for " + type); + + // We control loading of the registry which ensures a proper mapping of class -> parser + @SuppressWarnings("unchecked") + Parser<T> parserT = (Parser<T>) parser; + + return parserT; + } + + static Parsers fromConfiguration(Configuration configuration) { + Map<Class<?>, Parser<?>> parsers = + Maps.transformValues( + Maps.uniqueIndex(configuration.parserInfo(), INFO_TO_PARSED_TYPE), + INFO_TO_PARSER); + return new Parsers(parsers); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/PositionalInfo.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/PositionalInfo.java b/commons/src/main/java/com/twitter/common/args/PositionalInfo.java new file mode 100644 index 0000000..3a65cc4 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/PositionalInfo.java @@ -0,0 +1,119 @@ +// ================================================================================================= +// Copyright 2012 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nullable; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.reflect.TypeToken; + +import com.twitter.common.args.apt.Configuration; + +/** + * Description of a positional command line argument. + */ +public final class PositionalInfo<T> extends ArgumentInfo<List<T>> { + /** + * Factory method to create a PositionalInfo from a field. + * + * @param field The field must contain a {@link Arg Arg<List<?>>}. The List<?> + * represents zero or more positional arguments. + * @return a PositionalInfo describing the field. + */ + static PositionalInfo<?> createFromField(Field field) { + return createFromField(field, null); + } + + /** + * Factory method to create a PositionalInfo from a field. + * + * @param field The field must contain a {@link Arg Arg<List<?>>}. The List<?> + * represents zero or more positional arguments. + * @param instance The object containing the non-static Arg instance or else null if the Arg + * field is static. + * @return a PositionalInfo describing the field. + */ + static PositionalInfo<?> createFromField(Field field, @Nullable Object instance) { + Preconditions.checkNotNull(field); + Positional positional = field.getAnnotation(Positional.class); + if (positional == null) { + throw new Configuration.ConfigurationException( + "No @Positional Arg annotation for field " + field); + } + + Preconditions.checkArgument( + TypeUtil.getRawType(TypeUtil.getTypeParam(field)) == List.class, + "Field is annotated for positional parsing but is not of Arg<List<?>> type"); + Type nestedType = TypeUtil.extractTypeToken(TypeUtil.getTypeParam(field)); + + @SuppressWarnings({"unchecked", "rawtypes"}) // we have no way to know the type here + PositionalInfo<?> positionalInfo = new PositionalInfo( + field.getDeclaringClass().getCanonicalName() + "." + field.getName(), + "[positional args]", + positional.help(), + ArgumentInfo.getArgForField(field, Optional.fromNullable(instance)), + TypeUtil.getTypeParamTypeToken(field), + TypeToken.of(nestedType), + Arrays.asList(field.getAnnotations()), + positional.parser()); + + return positionalInfo; + } + + private final TypeToken<T> elementType; + + private PositionalInfo( + String canonicalName, + String name, + String help, + Arg<List<T>> arg, + TypeToken<List<T>> type, + TypeToken<T> elementType, + List<Annotation> verifierAnnotations, + @Nullable Class<? extends Parser<? extends List<T>>> parser) { + + // TODO: https://github.com/twitter/commons/issues/353, consider future support of + // argFile for Positional arguments. + super(canonicalName, name, help, false, arg, type, verifierAnnotations, parser); + this.elementType = elementType; + } + + /** + * Parses the positional args and stores the results in the {@link Arg} described by this + * {@code PositionalInfo}. + */ + void load(final ParserOracle parserOracle, List<String> positionalArgs) { + final Parser<? extends T> parser = parserOracle.get(elementType); + List<T> assignmentValue = Lists.newArrayList(Iterables.transform(positionalArgs, + new Function<String, T>() { + @Override public T apply(String argValue) { + return parser.parse(parserOracle, elementType.getType(), argValue); + } + })); + setValue(assignmentValue); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/TypeUtil.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/TypeUtil.java b/commons/src/main/java/com/twitter/common/args/TypeUtil.java new file mode 100644 index 0000000..a0e29ae --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/TypeUtil.java @@ -0,0 +1,123 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; +import java.util.Arrays; +import java.util.List; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import com.google.common.reflect.TypeToken; + +/** + * Utility class to extract generic type information. + * + * TODO(William Farner): Move this into a common library, integrate with EasyMockTest.Clazz. + * + * @author William Farner + */ +public final class TypeUtil { + + private static final Function<Type, Type> GET_TYPE = new Function<Type, Type>() { + @Override public Type apply(Type type) { + if (type instanceof WildcardType) { + return apply(((WildcardType) type).getUpperBounds()[0]); + } + return type; + } + }; + + private TypeUtil() { + // Utility. + } + + /** + * Gets the types that a type is type-parameterized with, in declaration order. + * + * @param type The type to extract type parameters from. + * @return The types that {@code type} is parameterized with. + */ + public static List<Type> getTypeParams(Type type) { + if (type instanceof WildcardType) { + return getTypeParams(GET_TYPE.apply(type)); + } + return Lists.transform(Arrays.asList( + ((ParameterizedType) type).getActualTypeArguments()), GET_TYPE); + } + + /** + * Finds the raw class of type. + * + * @param type The type to get the raw class of. + * @return The raw class of type. + */ + public static Class<?> getRawType(Type type) { + if (type instanceof ParameterizedType) { + return getRawType(((ParameterizedType) type).getRawType()); + } + if (type instanceof WildcardType) { + return getRawType(((WildcardType) type).getUpperBounds()[0]); + } + return (Class<?>) type; + } + + /** + * Convenience method to call {@link #getTypeParam(Field)}, with the requirement that there + * is exactly one type parameter on the field. + * + * @param field The field to extract type parameters from. + * @return The raw classes of types that {@code field} is parameterized with. + */ + public static TypeToken<?> getTypeParamTypeToken(Field field) { + List<Type> typeParams = getTypeParams(field.getGenericType()); + Preconditions.checkArgument(typeParams.size() == 1, + "Expected exactly one type parameter for field " + field); + return TypeToken.of(typeParams.get(0)); + } + + /** + * Gets the type parameter from a field. Assumes that there is at least one type parameter. + * + * @param field The field to extract the type parameter from. + * @return The field type parameter. + */ + public static Type getTypeParam(Field field) { + return extractTypeToken(field.getGenericType()); + } + + /** + * Extracts the actual type parameter for a singly parameterized type. + * + * @param type The parameterized type to extract the type argument from. + * @return The type of the single specified type parameter for {@code type}. + * @throws IllegalArgumentException if the supplied type does not have exactly one specified type + * parameter + */ + public static Type extractTypeToken(Type type) { + Preconditions.checkNotNull(type); + Preconditions.checkArgument(type instanceof ParameterizedType, "Missing type parameter."); + Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); + Preconditions.checkArgument(typeArguments.length == 1, + "Expected a type with exactly 1 type argument"); + return typeArguments[0]; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/Verifiers.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/Verifiers.java b/commons/src/main/java/com/twitter/common/args/Verifiers.java new file mode 100644 index 0000000..adc75c2 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/Verifiers.java @@ -0,0 +1,95 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args; + +import java.lang.annotation.Annotation; +import java.util.Map; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.TypeToken; + +import com.twitter.common.args.apt.Configuration; +import com.twitter.common.collections.Pair; + +import static com.twitter.common.args.apt.Configuration.ConfigurationException; +import static com.twitter.common.args.apt.Configuration.VerifierInfo; + +/** + * Utility class to manage relationships between constraints and types. + * + * @author William Farner + */ +public final class Verifiers { + + private final ImmutableMap<Pair<Class<?>, Class<? extends Annotation>>, + Verifier<?>> registry; + + private Verifiers(Map<Pair<Class<?>, Class<? extends Annotation>>, + Verifier<?>> registry) { + + this.registry = ImmutableMap.copyOf(registry); + } + + @Nullable + <T> Verifier<T> get(TypeToken<T> type, Annotation constraint) { + for (Map.Entry<Pair<Class<?>, Class<? extends Annotation>>, Verifier<?>> entry + : registry.entrySet()) { + if (entry.getKey().getSecond() == constraint.annotationType() + && entry.getKey().getFirst().isAssignableFrom(type.getRawType())) { + + // We control the registry which ensures a proper mapping of class -> verifier. + @SuppressWarnings("unchecked") + Verifier<T> verifier = (Verifier<T>) entry.getValue(); + return verifier; + } + } + + return null; + } + + static Verifiers fromConfiguration(Configuration configuration) { + ImmutableMap.Builder<Pair<Class<?>, Class<? extends Annotation>>, + Verifier<?>> registry = ImmutableMap.builder(); + + for (VerifierInfo info : configuration.verifierInfo()) { + Class<?> verifiedType = forName(info.verifiedType); + Class<? extends Annotation> verifyingAnnotation = forName(info.verifyingAnnotation); + Class<? extends Verifier<?>> verifierClass = forName(info.verifierClass); + try { + registry.put( + Pair.<Class<?>, Class<? extends Annotation>>of(verifiedType, verifyingAnnotation), + verifierClass.newInstance()); + } catch (InstantiationException e) { + throw new ConfigurationException(e); + } catch (IllegalAccessException e) { + throw new ConfigurationException(e); + } + } + return new Verifiers(registry.build()); + } + + @SuppressWarnings("unchecked") + private static <T> Class<T> forName(String name) { + try { + return (Class<T>) Class.forName(name); + } catch (ClassNotFoundException e) { + throw new ConfigurationException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/CanExecute.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/CanExecute.java b/commons/src/main/java/com/twitter/common/args/constraints/CanExecute.java new file mode 100644 index 0000000..1804674 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/CanExecute.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates an entity must be executable. + * + * @author Steven Nie + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface CanExecute { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/CanExecuteFileVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/CanExecuteFileVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/CanExecuteFileVerifier.java new file mode 100644 index 0000000..4486351 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/CanExecuteFileVerifier.java @@ -0,0 +1,43 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.io.File; +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a file is executable. + * + * @author Steven Nie + */ +@VerifierFor(CanExecute.class) +public class CanExecuteFileVerifier implements Verifier<File> { + @Override + public void verify(File value, Annotation annotation) { + checkArgument(value.canExecute(), "File must be executable"); + } + + @Override + public String toString(Class<? extends File> argType, Annotation annotation) { + return "file must be executable"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/CanRead.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/CanRead.java b/commons/src/main/java/com/twitter/common/args/constraints/CanRead.java new file mode 100644 index 0000000..178e3ec --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/CanRead.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates an entity must be readable. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface CanRead { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/CanReadFileVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/CanReadFileVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/CanReadFileVerifier.java new file mode 100644 index 0000000..2fe4415 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/CanReadFileVerifier.java @@ -0,0 +1,43 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.io.File; +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a file is readable. + * + * @author William Farner + */ +@VerifierFor(CanRead.class) +public class CanReadFileVerifier implements Verifier<File> { + @Override + public void verify(File value, Annotation annotation) { + checkArgument(value.canRead(), "File must be readable"); + } + + @Override + public String toString(Class<? extends File> argType, Annotation annotation) { + return "file must be readable"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/CanWrite.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/CanWrite.java b/commons/src/main/java/com/twitter/common/args/constraints/CanWrite.java new file mode 100644 index 0000000..3ea346a --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/CanWrite.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates an entity must be writable. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface CanWrite { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/CanWriteFileVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/CanWriteFileVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/CanWriteFileVerifier.java new file mode 100644 index 0000000..08f1483 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/CanWriteFileVerifier.java @@ -0,0 +1,43 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.io.File; +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a file can be written to. + * + * @author William Farner + */ +@VerifierFor(CanWrite.class) +public class CanWriteFileVerifier implements Verifier<File> { + @Override + public void verify(File value, Annotation annotation) { + checkArgument(value.canWrite(), "File must be writable."); + } + + @Override + public String toString(Class<? extends File> argType, Annotation annotation) { + return "file must be writeable"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/Exists.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/Exists.java b/commons/src/main/java/com/twitter/common/args/constraints/Exists.java new file mode 100644 index 0000000..f85ccce --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/Exists.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates an entity must exist. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface Exists { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/ExistsFileVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/ExistsFileVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/ExistsFileVerifier.java new file mode 100644 index 0000000..c430997 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/ExistsFileVerifier.java @@ -0,0 +1,43 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.io.File; +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a file exists. + * + * @author William Farner + */ +@VerifierFor(Exists.class) +public class ExistsFileVerifier implements Verifier<File> { + @Override + public void verify(File value, Annotation annotation) { + checkArgument(value.exists(), "file must exist"); + } + + @Override + public String toString(Class<? extends File> argType, Annotation annotation) { + return "file must exist"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/IsDirectory.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/IsDirectory.java b/commons/src/main/java/com/twitter/common/args/constraints/IsDirectory.java new file mode 100644 index 0000000..361cf30 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/IsDirectory.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates an entity must represent a directory. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface IsDirectory { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/IsDirectoryFileVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/IsDirectoryFileVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/IsDirectoryFileVerifier.java new file mode 100644 index 0000000..f08a20d --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/IsDirectoryFileVerifier.java @@ -0,0 +1,43 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.io.File; +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a file is a directory. + * + * @author William Farner + */ +@VerifierFor(IsDirectory.class) +public class IsDirectoryFileVerifier implements Verifier<File> { + @Override + public void verify(File value, Annotation annotation) { + checkArgument(value.isDirectory(), "Must be a directory."); + } + + @Override + public String toString(Class<? extends File> argType, Annotation annotation) { + return "file must be a directory"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/NotEmpty.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/NotEmpty.java b/commons/src/main/java/com/twitter/common/args/constraints/NotEmpty.java new file mode 100644 index 0000000..86c52d4 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/NotEmpty.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates that an entity is non-empty. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface NotEmpty { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyIterableVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyIterableVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyIterableVerifier.java new file mode 100644 index 0000000..10d204b --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyIterableVerifier.java @@ -0,0 +1,44 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Annotation; + +import com.google.common.collect.Iterables; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifies that an iterable is not empty. + * + * @author William Farner + */ +@VerifierFor(NotEmpty.class) +public class NotEmptyIterableVerifier implements Verifier<Iterable<?>> { + @Override + public void verify(Iterable<?> value, Annotation annotation) { + checkArgument(!Iterables.isEmpty(value), "Value must not be empty."); + } + + @Override + public String toString(Class<? extends Iterable<?>> argType, Annotation annotation) { + return "must have at least 1 item"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyStringVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyStringVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyStringVerifier.java new file mode 100644 index 0000000..b377b52 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/NotEmptyStringVerifier.java @@ -0,0 +1,42 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a string is not empty. + * + * @author William Farner + */ +@VerifierFor(NotEmpty.class) +public class NotEmptyStringVerifier implements Verifier<String> { + @Override + public void verify(String s, Annotation annotation) { + checkArgument(!s.isEmpty(), "Value must not be empty."); + } + + @Override + public String toString(Class<? extends String> argType, Annotation annotation) { + return "must be non-empty"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/NotNegative.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/NotNegative.java b/commons/src/main/java/com/twitter/common/args/constraints/NotNegative.java new file mode 100644 index 0000000..3733103 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/NotNegative.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates that an entity is non-negative. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface NotNegative { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/NotNegativeNumberVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/NotNegativeNumberVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/NotNegativeNumberVerifier.java new file mode 100644 index 0000000..7dc2987 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/NotNegativeNumberVerifier.java @@ -0,0 +1,42 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a number is non-negative. + * + * @author William Farner + */ +@VerifierFor(NotNegative.class) +public class NotNegativeNumberVerifier implements Verifier<Number> { + @Override + public void verify(Number number, Annotation annotation) { + checkArgument(number.doubleValue() >= 0, "Value must be non-negative."); + } + + @Override + public String toString(Class<? extends Number> argType, Annotation annotation) { + return "must be >= 0"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/NotNull.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/NotNull.java b/commons/src/main/java/com/twitter/common/args/constraints/NotNull.java new file mode 100644 index 0000000..1b425fb --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/NotNull.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation to indicate that an entity must be non-null. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface NotNull { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/NotNullVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/NotNullVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/NotNullVerifier.java new file mode 100644 index 0000000..2d4e140 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/NotNullVerifier.java @@ -0,0 +1,42 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * A verifier that ensures a value is non-null. + * + * @author William Farner + */ +@VerifierFor(NotNull.class) +public class NotNullVerifier implements Verifier<Object> { + @Override + public void verify(Object value, Annotation annotation) { + checkArgument(value != null, "Value must not be null."); + } + + @Override + public String toString(Class<?> argType, Annotation annotation) { + return "not null"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/Positive.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/Positive.java b/commons/src/main/java/com/twitter/common/args/constraints/Positive.java new file mode 100644 index 0000000..a80bba6 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/Positive.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates an entity must be positive. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface Positive { +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/PositiveNumberVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/PositiveNumberVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/PositiveNumberVerifier.java new file mode 100644 index 0000000..06bf3a3 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/PositiveNumberVerifier.java @@ -0,0 +1,42 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Annotation; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifier to ensure that a number is positive. + * + * @author William Farner + */ +@VerifierFor(Positive.class) +public class PositiveNumberVerifier implements Verifier<Number> { + @Override + public void verify(Number number, Annotation annotation) { + checkArgument(number.doubleValue() > 0, "Value must be positive."); + } + + @Override + public String toString(Class<? extends Number> argType, Annotation annotation) { + return "must be > 0"; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/Range.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/Range.java b/commons/src/main/java/com/twitter/common/args/constraints/Range.java new file mode 100644 index 0000000..ee4630d --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/Range.java @@ -0,0 +1,43 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation that indicates a field must be within a given numeric range. + * + * @author William Farner + */ +@Target(FIELD) +@Retention(RUNTIME) +public @interface Range { + + /** + * The lower bound on the acceptable range (inclusive). + */ + double lower(); + + /** + * The upper bound on the acceptable range (inclusive). + */ + double upper(); +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/constraints/RangeNumberVerifier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/constraints/RangeNumberVerifier.java b/commons/src/main/java/com/twitter/common/args/constraints/RangeNumberVerifier.java new file mode 100644 index 0000000..a4c2072 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/constraints/RangeNumberVerifier.java @@ -0,0 +1,77 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.constraints; + +import java.lang.annotation.Annotation; +import java.math.BigDecimal; + +import com.google.common.base.Function; +import com.google.common.base.Functions; + +import com.twitter.common.args.Verifier; +import com.twitter.common.args.VerifierFor; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Verifies that a number (inclusively) lies within a range. + * + * @author William Farner + */ +@VerifierFor(Range.class) +public class RangeNumberVerifier implements Verifier<Number> { + @Override + public void verify(Number value, Annotation annotation) { + Range range = getRange(annotation); + + checkArgument(range.lower() < range.upper(), + "Range lower bound must be greater than upper bound."); + + double dblValue = value.doubleValue(); + checkArgument(dblValue >= range.lower() && dblValue <= range.upper(), + String.format("Value must be in range [%f, %f]", range.lower(), range.upper())); + } + + @Override + public String toString(Class<? extends Number> argType, Annotation annotation) { + Range range = getRange(annotation); + + Function<Number, Number> converter; + if (Float.class.isAssignableFrom(argType) + || Double.class.isAssignableFrom(argType) + || BigDecimal.class.isAssignableFrom(argType)) { + + converter = Functions.identity(); + } else { + converter = new Function<Number, Number>() { + @Override public Number apply(Number item) { + return item.longValue(); + } + }; + } + + return String.format("must be >= %s and <= %s", + converter.apply(range.lower()), + converter.apply(range.upper())); + } + + private Range getRange(Annotation annotation) { + checkArgument(annotation instanceof Range, "Annotation is not a range: " + annotation); + + return (Range) annotation; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/AmountParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/AmountParser.java b/commons/src/main/java/com/twitter/common/args/parsers/AmountParser.java new file mode 100644 index 0000000..1f4065d --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/AmountParser.java @@ -0,0 +1,89 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.parsers; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.common.reflect.TypeToken; + +import com.twitter.common.args.ArgParser; +import com.twitter.common.args.Parser; +import com.twitter.common.args.ParserOracle; +import com.twitter.common.quantity.Amount; +import com.twitter.common.quantity.Unit; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Amount parser. + * + * @author William Farner + */ +@ArgParser +public class AmountParser extends TypeParameterizedParser<Amount<?, ?>> { + + private static final Pattern AMOUNT_PATTERN = Pattern.compile("(\\d+)([A-Za-z]+)"); + + public AmountParser() { + super(2); + } + + @Override + Amount<?, ?> doParse(ParserOracle parserOracle, String raw, List<Type> typeParams) { + Type valueType = typeParams.get(0); + Parser<?> parser = parserOracle.get(TypeToken.of(valueType)); + + Matcher matcher = AMOUNT_PATTERN.matcher(raw); + checkArgument(matcher.matches(), + "Value '" + raw + "' must be of the format 1ns, 4mb, etc."); + + Number number = (Number) parser.parse(parserOracle, valueType, matcher.group(1)); + String unitRaw = matcher.group(2); + + Type unitType = typeParams.get(1); + @SuppressWarnings("rawtypes") + Parser<Unit> unitParser = parserOracle.get(TypeToken.of(Unit.class)); + @SuppressWarnings("rawtypes") + Unit unit = unitParser.parse(parserOracle, unitType, unitRaw); + checkArgument(unit.getClass() == unitType, String.format( + "Unit type (%s) does not match argument type (%s).", + unit.getClass(), unitType)); + + return create(valueType, number, unit); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private static Amount<?, ?> create(Type valueType, Number number, Unit unit) { + if (valueType == Integer.class) { + return Amount.of(number.intValue(), unit); + } else if (valueType == Double.class) { + return Amount.of(number.doubleValue(), unit); + } else if (valueType == Long.class) { + return Amount.of(number.longValue(), unit); + } else if (valueType == Byte.class) { + return Amount.of(number.byteValue(), unit); + } else if (valueType == Short.class) { + return Amount.of(number.shortValue(), unit); + } else if (valueType == Float.class) { + return Amount.of(number.floatValue(), unit); + } + throw new IllegalArgumentException("Unrecognized number class " + valueType); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/BooleanParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/BooleanParser.java b/commons/src/main/java/com/twitter/common/args/parsers/BooleanParser.java new file mode 100644 index 0000000..7564d27 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/BooleanParser.java @@ -0,0 +1,33 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.parsers; + +import com.twitter.common.args.ArgParser; + +/** + * Boolean parser. + * + * @author William Farner + */ +@ArgParser +public class BooleanParser extends NonParameterizedTypeParser<Boolean> { + @Override + public Boolean doParse(String raw) { + // Magic boolean syntax, no argument value means true. + return raw.isEmpty() || Boolean.parseBoolean(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/ByteParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/ByteParser.java b/commons/src/main/java/com/twitter/common/args/parsers/ByteParser.java new file mode 100644 index 0000000..68b4823 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/ByteParser.java @@ -0,0 +1,32 @@ +// ================================================================================================= +// Copyright 2011 Twitter, Inc. +// ------------------------------------------------------------------------------------------------- +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this work except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file, or at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ================================================================================================= + +package com.twitter.common.args.parsers; + +import com.twitter.common.args.ArgParser; + +/** + * Byte parser. + * + * @author William Farner + */ +@ArgParser +public class ByteParser extends NumberParser<Byte> { + @Override + Byte parseNumber(String raw) { + return Byte.parseByte(raw); + } +}
