http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.java b/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.java new file mode 100644 index 0000000..9a5f9ad --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.java @@ -0,0 +1,36 @@ +// ================================================================================================= +// 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; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Character parser. + * + * @author William Farner + */ +@ArgParser +public class CharacterParser extends NonParameterizedTypeParser<Character> { + @Override + public Character doParse(String raw) { + checkArgument(raw.length() == 1, + "String " + raw + " cannot be assigned to a character."); + return raw.charAt(0); + } +}
http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java b/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java new file mode 100644 index 0000000..bf32dc1 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java @@ -0,0 +1,51 @@ +// ================================================================================================= +// 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 com.google.common.base.Preconditions; + +import com.twitter.common.args.ArgParser; +import com.twitter.common.args.ParserOracle; +import com.twitter.common.args.TypeUtil; + +/** + * Class parser. + * + * @author William Farner + */ +@ArgParser +public class ClassParser extends TypeParameterizedParser<Class<?>> { + + public ClassParser() { + super(1); + } + + @Override + public Class<?> doParse(ParserOracle parserOracle, String raw, final List<Type> typeParams) { + Class<?> rawClassType = TypeUtil.getRawType(typeParams.get(0)); + try { + Class<?> actualClass = Class.forName(raw); + Preconditions.checkArgument(rawClassType.isAssignableFrom(actualClass)); + return actualClass; + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Could not find class " + raw); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/DateParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/DateParser.java b/commons/src/main/java/com/twitter/common/args/parsers/DateParser.java new file mode 100644 index 0000000..651004b --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/DateParser.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.parsers; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.twitter.common.args.ArgParser; + +/** + * Date parser. + * + * @author William Farner + */ +@ArgParser +public class DateParser extends NonParameterizedTypeParser<Date> { + + private static final String FORMAT = "MM/dd/yyyy HH:mm"; + private static final SimpleDateFormat SIMPLE_FORMAT = new SimpleDateFormat(FORMAT); + + @Override + public Date doParse(String raw) { + try { + return SIMPLE_FORMAT.parse(raw); + } catch (ParseException e) { + throw new IllegalArgumentException("Failed to parse " + raw + " in format " + FORMAT); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.java b/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.java new file mode 100644 index 0000000..1965625 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.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; + +/** + * Double parser. + * + * @author William Farner + */ +@ArgParser +public class DoubleParser extends NumberParser<Double> { + @Override + Double parseNumber(String raw) { + return Double.parseDouble(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java b/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java new file mode 100644 index 0000000..bcb4bf8 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java @@ -0,0 +1,83 @@ +// ================================================================================================= +// 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.Collections; +import java.util.List; +import java.util.StringTokenizer; + +import com.google.common.base.Preconditions; + +import com.twitter.common.args.ParserOracle; +import com.twitter.common.quantity.Amount; +import com.twitter.common.quantity.Time; + +/** + * Utility class for parsing durations of the form "1d23h59m59s" (as well as subvariants, i.e. + * "10h5s" would also work, as would "2d"). These values are useful representations in HTTP query + * parameters for durations. + * + */ +public class DurationParser extends TypeParameterizedParser<Amount<?, ?>> { + + private static final String SUFFIXES = "dhms"; + private static final Time[] TIME_UNITS = {Time.DAYS, Time.HOURS, Time.MINUTES, Time.SECONDS}; + + public DurationParser() { + super(2); + } + + @Override + Amount<?, ?> doParse(ParserOracle parserOracle, String raw, List<Type> paramParsers) + throws IllegalArgumentException { + Type secondParamClass = paramParsers.get(1); + Preconditions.checkArgument( + secondParamClass == Time.class, + String.format("Expected %s for " + + "second type parameter, but got got %s", Time.class.getName(), + secondParamClass)); + return parse(raw); + } + + /** + * Parses a duration of the form "1d23h59m59s" (as well as subvariants, i.e. "10h5s" would also + * work, as would "2d"). + * + * @param spec the textual duration specification + * @return the parsed form + * @throws IllegalArgumentException if the specification can not be parsed + */ + public static Amount<Long, Time> parse(String spec) { + long time = 0L; + final List<Object> tokens = Collections.list(new StringTokenizer(spec, SUFFIXES, true)); + Preconditions.checkArgument(tokens.size() > 1); + for (int i = 1; i < tokens.size(); i += 2) { + final String token = (String) tokens.get(i); + Preconditions.checkArgument(token.length() == 1, "Too long suffix '%s'", token); + final int suffixIndex = SUFFIXES.indexOf(token.charAt(0)); + Preconditions.checkArgument(suffixIndex != -1, "Unrecognized suffix '%s'", token); + try { + final int value = Integer.parseInt((String) tokens.get(i - 1)); + time += Amount.of(value, TIME_UNITS[suffixIndex]).as(Time.SECONDS); + } catch (NumberFormatException e) { + Preconditions.checkArgument(false, "Invalid number %s", tokens.get(i - 1)); + } + } + return Amount.of(time, Time.SECONDS); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java b/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java new file mode 100644 index 0000000..1741b7d --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java @@ -0,0 +1,39 @@ +// ================================================================================================= +// 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 com.twitter.common.args.ArgParser; +import com.twitter.common.args.Parser; +import com.twitter.common.args.ParserOracle; + +/** + * An {@link Enum} parser that matches enum values via {@link Enum#valueOf(Class, String)}. + * + * @author John Sirois + */ +@ArgParser +public class EnumParser<T extends Enum<T>> implements Parser<T> { + + @Override + public T parse(ParserOracle parserOracle, Type type, String raw) throws IllegalArgumentException { + @SuppressWarnings("unchecked") + Class<T> enumClass = (Class<T>) type; + return Enum.valueOf(enumClass, raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/FileParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/FileParser.java b/commons/src/main/java/com/twitter/common/args/parsers/FileParser.java new file mode 100644 index 0000000..a3cf1b2 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/FileParser.java @@ -0,0 +1,34 @@ +// ================================================================================================= +// 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.io.File; + +import com.twitter.common.args.ArgParser; + +/** + * File parser. + * + * @author William Farner + */ +@ArgParser +public class FileParser extends NonParameterizedTypeParser<File> { + @Override + public File doParse(String raw) { + return new File(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.java b/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.java new file mode 100644 index 0000000..3330bba --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.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; + +/** + * Float parser. + * + * @author William Farner + */ +@ArgParser +public class FloatParser extends NumberParser<Float> { + @Override + Float parseNumber(String raw) { + return Float.parseFloat(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.java b/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.java new file mode 100644 index 0000000..584240b --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.java @@ -0,0 +1,35 @@ +// ================================================================================================= +// 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.net.InetSocketAddress; + +import com.twitter.common.args.ArgParser; +import com.twitter.common.net.InetSocketAddressHelper; + +/** + * InetSocketAddress parser. + * + * @author William Farner + */ +@ArgParser +public class InetSocketAddressParser extends NonParameterizedTypeParser<InetSocketAddress> { + @Override + public InetSocketAddress doParse(String raw) { + return InetSocketAddressHelper.parse(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.java b/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.java new file mode 100644 index 0000000..c4bcd23 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.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; + +/** + * Integer parser. + * + * @author William Farner + */ +@ArgParser +public class IntegerParser extends NumberParser<Integer> { + @Override + Integer parseNumber(String raw) { + return Integer.parseInt(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java b/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java new file mode 100644 index 0000000..79434c0 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java @@ -0,0 +1,55 @@ +// ================================================================================================= +// 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 com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +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.args.Parsers; + +/** + * List parser. + * + * @author William Farner + */ +@ArgParser +public class ListParser extends TypeParameterizedParser<List<?>> { + + public ListParser() { + super(1); + } + + @Override + List<?> doParse(final ParserOracle parserOracle, String raw, final List<Type> typeParams) { + final Type listType = typeParams.get(0); + final Parser<?> parser = parserOracle.get(TypeToken.of(listType)); + return ImmutableList.copyOf(Iterables.transform(Parsers.MULTI_VALUE_SPLITTER.split(raw), + new Function<String, Object>() { + @Override public Object apply(String raw) { + return parser.parse(parserOracle, listType, raw); + } + })); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/LongParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/LongParser.java b/commons/src/main/java/com/twitter/common/args/parsers/LongParser.java new file mode 100644 index 0000000..83c6752 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/LongParser.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; + +/** + * Long parser. + * + * @author William Farner + */ +@ArgParser +public class LongParser extends NumberParser<Long> { + @Override + Long parseNumber(String raw) { + return Long.parseLong(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java b/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java new file mode 100644 index 0000000..19de492 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java @@ -0,0 +1,71 @@ +// ================================================================================================= +// 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.Map; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +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.args.Parsers; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Map parser. + * + * @author William Farner + */ +@ArgParser +public class MapParser extends TypeParameterizedParser<Map<?, ?>> { + + private static final Splitter KEY_VALUE_SPLITTER = + Splitter.on("=").trimResults().omitEmptyStrings(); + + public MapParser() { + super(2); + } + + @SuppressWarnings("unchecked") + @Override + Map<?, ?> doParse(ParserOracle parserOracle, String raw, List<Type> typeParams) { + Type keyType = typeParams.get(0); + Parser<?> keyParser = parserOracle.get(TypeToken.of(keyType)); + + Type valueType = typeParams.get(1); + Parser<?> valueParser = parserOracle.get(TypeToken.of(valueType)); + + ImmutableMap.Builder<Object, Object> map = ImmutableMap.builder(); + for (String keyAndValue : Parsers.MULTI_VALUE_SPLITTER.split(raw)) { + List<String> fields = ImmutableList.copyOf(KEY_VALUE_SPLITTER.split(keyAndValue)); + checkArgument(fields.size() == 2, + "Failed to parse key/value pair " + keyAndValue); + + map.put(keyParser.parse(parserOracle, keyType, fields.get(0)), + valueParser.parse(parserOracle, valueType, fields.get(1))); + } + + return map.build(); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.java b/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.java new file mode 100644 index 0000000..187de17 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.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.parsers; + +import java.lang.reflect.Type; + +import com.twitter.common.args.Parser; +import com.twitter.common.args.ParserOracle; + +/** + * Base class for parsers of types that are not parameterized. + * + * @author William Farner + */ +public abstract class NonParameterizedTypeParser<T> implements Parser<T> { + + /** + * Performs the parsing of the raw string. + * + * @param raw Value to parse. + * @return The parsed value. + * @throws IllegalArgumentException If the value could not be parsed into the target type. + */ + public abstract T doParse(String raw) throws IllegalArgumentException; + + @Override + public T parse(ParserOracle parserOracle, Type type, String raw) throws IllegalArgumentException { + return doParse(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.java b/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.java new file mode 100644 index 0000000..4214f59 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.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.parsers; + +/** + * Parser that handles common functionality for parsing numbers. + * + * @author William Farner + */ +public abstract class NumberParser<T extends Number> extends NonParameterizedTypeParser<T> { + + /** + * Performs the actual parsing of the value into the target type. + * + * @param raw Raw value to parse. + * @return The parsed value. + * @throws NumberFormatException If the raw value does not represent a valid number of the target + * type. + */ + abstract T parseNumber(String raw) throws NumberFormatException; + + @Override + public T doParse(String raw) throws IllegalArgumentException { + try { + return parseNumber(raw); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(String.format("Invalid value: " + e.getMessage())); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java b/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java new file mode 100644 index 0000000..5356321 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java @@ -0,0 +1,60 @@ +// ================================================================================================= +// 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 com.google.common.collect.ImmutableList; +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.args.Parsers; +import com.twitter.common.collections.Pair; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Pair parser. + * + * @author William Farner + */ +@ArgParser +public class PairParser extends TypeParameterizedParser<Pair<?, ?>> { + + public PairParser() { + super(2); + } + + @Override + Pair<?, ?> doParse(ParserOracle parserOracle, String raw, List<Type> typeParams) { + Type leftType = typeParams.get(0); + Parser<?> leftParser = parserOracle.get(TypeToken.of(leftType)); + + Type rightType = typeParams.get(1); + Parser<?> rightParser = parserOracle.get(TypeToken.of(rightType)); + + List<String> parts = ImmutableList.copyOf(Parsers.MULTI_VALUE_SPLITTER.split(raw)); + checkArgument(parts.size() == 2, + "Only two values may be specified for a pair, you gave " + parts.size()); + + return Pair.of(leftParser.parse(parserOracle, leftType, parts.get(0)), + rightParser.parse(parserOracle, rightType, parts.get(1))); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java b/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java new file mode 100644 index 0000000..1834628 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java @@ -0,0 +1,38 @@ +// ================================================================================================= +// Copyright 2013 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.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import com.twitter.common.args.ArgParser; + +/** + * A regular expression parser. + */ +@ArgParser +public class PatternParser extends NonParameterizedTypeParser<Pattern> { + + @Override + public Pattern doParse(String raw) throws IllegalArgumentException { + try { + return Pattern.compile(raw); + } catch (PatternSyntaxException e) { + throw new IllegalArgumentException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java b/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java new file mode 100644 index 0000000..0cba553 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java @@ -0,0 +1,33 @@ +package com.twitter.common.args.parsers; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Range; + +import com.twitter.common.args.ArgParser; + +/** + * A parser that handles closed ranges. For the input "4-6", it will capture [4, 5, 6]. + */ +@ArgParser +public class RangeParser extends NonParameterizedTypeParser<Range<Integer>> { + @Override + public Range<Integer> doParse(String raw) throws IllegalArgumentException { + ImmutableList<String> numbers = + ImmutableList.copyOf(Splitter.on('-').omitEmptyStrings().split(raw)); + try { + int from = Integer.parseInt(numbers.get(0)); + int to = Integer.parseInt(numbers.get(1)); + if (numbers.size() != 2) { + throw new IllegalArgumentException("Failed to parse the range:" + raw); + } + if (to < from) { + return Range.closed(to, from); + } else { + return Range.closed(from, to); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Failed to parse the range:" + raw, e); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java b/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java new file mode 100644 index 0000000..fecaeb2 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java @@ -0,0 +1,57 @@ +// ================================================================================================= +// 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.Set; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +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.args.Parsers; + +/** + * Set parser. + * + * @author William Farner + */ +@ArgParser +public class SetParser extends TypeParameterizedParser<Set<?>> { + + public SetParser() { + super(1); + } + + @Override + Set<?> doParse(final ParserOracle parserOracle, String raw, List<Type> typeParams) { + final Type setType = typeParams.get(0); + final Parser<?> parser = parserOracle.get(TypeToken.of(setType)); + + return ImmutableSet.copyOf(Iterables.transform(Parsers.MULTI_VALUE_SPLITTER.split(raw), + new Function<String, Object>() { + @Override public Object apply(String raw) { + return parser.parse(parserOracle, setType, raw); + } + })); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.java b/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.java new file mode 100644 index 0000000..b13386c --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.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; + +/** + * Short parser. + * + * @author William Farner + */ +@ArgParser +public class ShortParser extends NumberParser<Short> { + @Override + Short parseNumber(String raw) { + return Short.parseShort(raw); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/StringParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/StringParser.java b/commons/src/main/java/com/twitter/common/args/parsers/StringParser.java new file mode 100644 index 0000000..a403917 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/StringParser.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; + +/** + * String parser. + * + * @author William Farner + */ +@ArgParser +public class StringParser extends NonParameterizedTypeParser<String> { + @Override + public String doParse(String raw) { + return raw; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java b/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java new file mode 100644 index 0000000..7ded11f --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java @@ -0,0 +1,68 @@ +// ================================================================================================= +// 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 com.twitter.common.args.Parser; +import com.twitter.common.args.ParserOracle; +import com.twitter.common.args.TypeUtil; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Parser that makes implementation of parsers for parameterized types simpler. + * + * @param <T> The raw type this parser can parse. + * + * @author William Farner + */ +public abstract class TypeParameterizedParser<T> implements Parser<T> { + + private final int typeParamCount; + + /** + * Creates a new type parameterized parser. + * + * @param typeParamCount Strict number of type parameters to allow on the assigned type. + */ + TypeParameterizedParser(int typeParamCount) { + this.typeParamCount = typeParamCount; + } + + /** + * Performs the actual parsing. + * + * @param parserOracle The registered parserOracle for delegation. + * @param raw The raw value to parse. + * @param typeParams The captured actual type parameters for {@code T}. + * @return The parsed value. + * @throws IllegalArgumentException If the value could not be parsed. + */ + abstract T doParse(ParserOracle parserOracle, String raw, List<Type> typeParams) + throws IllegalArgumentException; + + @Override public T parse(ParserOracle parserOracle, Type type, String raw) { + List<Type> typeParams = TypeUtil.getTypeParams(type); + checkArgument(typeParams.size() == typeParamCount, String.format( + "Expected %d type parameters for %s but got %d", + typeParamCount, type, typeParams.size())); + + return doParse(parserOracle, raw, typeParams); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java b/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java new file mode 100644 index 0000000..fce84c0 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java @@ -0,0 +1,39 @@ +// ================================================================================================= +// 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.net.URI; +import java.net.URISyntaxException; + +import com.twitter.common.args.ArgParser; + +/** + * URI parser. + * + * @author William Farner + */ +@ArgParser +public class URIParser extends NonParameterizedTypeParser<URI> { + @Override + public URI doParse(String raw) { + try { + return new URI(raw); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Malformed URI " + raw + ", " + e.getMessage()); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java b/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java new file mode 100644 index 0000000..33bcd49 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java @@ -0,0 +1,39 @@ +// ================================================================================================= +// 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.net.MalformedURLException; +import java.net.URL; + +import com.twitter.common.args.ArgParser; + +/** + * URL parser. + * + * @author William Farner + */ +@ArgParser +public class URLParser extends NonParameterizedTypeParser<URL> { + @Override + public URL doParse(String raw) { + try { + return new URL(raw); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Malformed URL " + raw + ", " + e.getMessage()); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java b/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java new file mode 100644 index 0000000..0ccba62 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java @@ -0,0 +1,57 @@ +// ================================================================================================= +// 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.util.EnumSet; +import java.util.Map; + +import com.google.common.base.Functions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; + +import com.twitter.common.args.ArgParser; +import com.twitter.common.quantity.Data; +import com.twitter.common.quantity.Time; +import com.twitter.common.quantity.Unit; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Unit parser. + * Units are matched (case sensitively) against the result of {@link Unit#toString()}. + */ +@ArgParser +public class UnitParser extends NonParameterizedTypeParser<Unit<?>> { + + private final Map<String, Unit<?>> unitValues; + + public UnitParser() { + unitValues = Maps.uniqueIndex( + ImmutableList.<Unit<?>>builder().add(Time.values()).add(Data.values()).build(), + Functions.toStringFunction()); + } + + @Override + public Unit<?> doParse(String raw) { + Unit<?> unit = unitValues.get(raw); + + checkArgument(unit != null, String.format( + "No Units found matching %s, options: (Time): %s, (Data): %s", + raw, EnumSet.allOf(Time.class), EnumSet.allOf(Data.class))); + return unit; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/CachingSupplier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/CachingSupplier.java b/commons/src/main/java/com/twitter/common/base/CachingSupplier.java new file mode 100644 index 0000000..561dfec --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/CachingSupplier.java @@ -0,0 +1,71 @@ +// ================================================================================================= +// 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.base; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; + +import com.twitter.common.quantity.Amount; +import com.twitter.common.quantity.Time; +import com.twitter.common.util.Clock; + +/** + * A supplier that caches responses from an underling supplier, expiring the cached value after + * a fixed expiration time. + * + * @param <T> Supplied value type. + * + * @author William Farner + */ +public class CachingSupplier<T> implements Supplier<T> { + + private final Supplier<T> wrapped; + private final long expirationNanos; + private final Clock clock; + + private long lastFetchNanos = -1; + private T cachedValue; + + /** + * Creates a new caching supplier. + * + * @param wrapped The supplier to delegate fetches to. + * @param expiration The maximum amount of time that a response from {@code supplier} will be + * cached for. The expiration must be positive. + */ + public CachingSupplier(Supplier<T> wrapped, Amount<Long, Time> expiration) { + this(wrapped, expiration, Clock.SYSTEM_CLOCK); + } + + @VisibleForTesting + CachingSupplier(Supplier<T> wrapped, Amount<Long, Time> expiration, Clock clock) { + this.wrapped = Preconditions.checkNotNull(wrapped); + this.expirationNanos = Preconditions.checkNotNull(expiration).as(Time.NANOSECONDS); + Preconditions.checkArgument(expiration.getValue() > 0, "Expiration must be positive."); + this.clock = Preconditions.checkNotNull(clock); + } + + @Override + public synchronized T get() { + if ((lastFetchNanos == -1) || (clock.nowNanos() - lastFetchNanos > expirationNanos)) { + cachedValue = wrapped.get(); + lastFetchNanos = clock.nowNanos(); + } + + return cachedValue; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.java b/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.java new file mode 100644 index 0000000..0d3692c --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.java @@ -0,0 +1,35 @@ +// ================================================================================================= +// 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.base; + +import java.util.concurrent.Callable; + +/** + * A supplier that may also be called. + * + * @param <T> The supplier type. + * @param <E> Supplier exception type. + * + * @author John Sirois + */ +public abstract class CallableExceptionalSupplier<T, E extends Exception> + implements ExceptionalSupplier<T, E>, Callable<T> { + + @Override public T call() throws Exception { + return get(); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Closure.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/Closure.java b/commons/src/main/java/com/twitter/common/base/Closure.java new file mode 100644 index 0000000..94ae264 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/Closure.java @@ -0,0 +1,28 @@ +// ================================================================================================= +// 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.base; + +/** + * A closure that does not throw any checked exceptions. + * + * @param <T> Closure value type. + * + * @author John Sirois + */ +public interface Closure<T> extends ExceptionalClosure<T, RuntimeException> { + // convenience typedef +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Closures.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/Closures.java b/commons/src/main/java/com/twitter/common/base/Closures.java new file mode 100644 index 0000000..f8dc61c --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/Closures.java @@ -0,0 +1,136 @@ +// ================================================================================================= +// 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.base; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Utilities for dealing with Closures. + * + * @author John Sirois + */ +public final class Closures { + + private static final Closure<?> NOOP = new Closure<Object>() { + @Override public void execute(Object item) { + // noop + } + }; + + private Closures() { + // utility + } + + /** + * Converts a closure into a function returning {@code null}. + */ + public static <T> Function<T, Void> asFunction(final ExceptionalClosure<T, ?> closure) { + checkNotNull(closure); + + // CHECKSTYLE:OFF IllegalCatch + return new Function<T, Void>() { + @Override public Void apply(T item) { + try { + closure.execute(item); + } catch (Exception e) { + Throwables.propagate(e); + } + return null; + } + }; + // CHECKSTYLE:ON IllegalCatch + } + + /** + * Varargs equivalent of {@link #combine(Iterable)}. + * + * @param closures Closures to combine. + * @param <T> Type accepted by the closures. + * @return A single closure that will fan out all calls to {@link Closure#execute(Object)} to + * the wrapped closures. + */ + public static <T> Closure<T> combine(Closure<T>... closures) { + return combine(ImmutableList.copyOf(closures)); + } + + /** + * Combines multiple closures into a single closure, whose calls are replicated sequentially + * in the order that they were provided. + * If an exception is encountered from a closure it propagates to the top-level closure and the + * remaining closures are not executed. + * + * @param closures Closures to combine. + * @param <T> Type accepted by the closures. + * @return A single closure that will fan out all calls to {@link Closure#execute(Object)} to + * the wrapped closures. + */ + public static <T> Closure<T> combine(Iterable<Closure<T>> closures) { + checkNotNull(closures); + checkArgument(Iterables.all(closures, Predicates.notNull())); + + final Iterable<Closure<T>> closuresCopy = ImmutableList.copyOf(closures); + + return new Closure<T>() { + @Override public void execute(T item) { + for (Closure<T> closure : closuresCopy) { + closure.execute(item); + } + } + }; + } + + /** + * Applies a filter to a closure, such that the closure will only be called when the filter is + * satisfied (returns {@code true}}. + * + * @param filter Filter to determine when {@code closure} is called. + * @param closure Closure to filter. + * @param <T> Type handled by the filter and the closure. + * @return A filtered closure. + */ + public static <T> Closure<T> filter(final Predicate<T> filter, final Closure<T> closure) { + checkNotNull(filter); + checkNotNull(closure); + + return new Closure<T>() { + @Override public void execute(T item) { + if (filter.apply(item)) { + closure.execute(item); + } + } + }; + } + + /** + * Returns a closure that will do nothing. + * + * @param <T> The closure argument type. + * @return A closure that does nothing. + */ + @SuppressWarnings("unchecked") + public static <T> Closure<T> noop() { + return (Closure<T>) NOOP; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Command.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/Command.java b/commons/src/main/java/com/twitter/common/base/Command.java new file mode 100644 index 0000000..306b552 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/Command.java @@ -0,0 +1,26 @@ +// ================================================================================================= +// 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.base; + +/** + * A command that does not throw any checked exceptions. + * + * @author John Sirois + */ +public interface Command extends ExceptionalCommand<RuntimeException> { + // convenience typedef +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Commands.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/Commands.java b/commons/src/main/java/com/twitter/common/base/Commands.java new file mode 100644 index 0000000..7d8d782 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/Commands.java @@ -0,0 +1,80 @@ +// ================================================================================================= +// 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.base; + +import com.google.common.collect.ImmutableList; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Utility functions for working with commands. + * + * @author John Sirois + */ +public final class Commands { + + /** + * A command that does nothing when executed. + */ + public static final Command NOOP = new Command() { + @Override public void execute() { + // noop + } + }; + + private Commands() { + // utility + } + + /** + * Converts a command into a supplier returning null. + * + * @return A supplier whose {@link com.twitter.common.base.Supplier#get()} will cause the given + * {@code command} to be executed and {@code null} to be returned. + */ + public static <E extends Exception> ExceptionalSupplier<Void, E> asSupplier( + final ExceptionalCommand<E> command) { + checkNotNull(command); + + return new ExceptionalSupplier<Void, E>() { + @Override public Void get() throws E { + command.execute(); + return null; + } + }; + } + + /** + * Combines multiple {@code commands} into a single command. A {@link RuntimeException} thrown + * during the execution of one of the commands will prevent the subsequent commands from being + * executed. + * + * @param commands Commands to compound. + * @return A command whose {@link Command#execute()} will cause the given {@code commands} to be + * executed serially. + */ + public static Command compound(Iterable<Command> commands) { + final ImmutableList<Command> executableCommands = ImmutableList.copyOf(commands); + return new Command() { + @Override public void execute() { + for (Command command : executableCommands) { + command.execute(); + } + } + }; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Either.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/Either.java b/commons/src/main/java/com/twitter/common/base/Either.java new file mode 100644 index 0000000..9b556a3 --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/Either.java @@ -0,0 +1,345 @@ +package com.twitter.common.base; + +import javax.annotation.Nullable; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +/** + * A value of one of two possible types. + * + * <p>Often Either processing is used as an alternative exception flow control. In these uses the + * left type represents failure by convention and the right type the success path result. + * + * @param <L> The left type. + * @param <R> The right type. + */ +public final class Either<L, R> { + private final Optional<L> left; + private final Optional<R> right; + + private Either(Optional<L> left, Optional<R> right) { + this.left = left; + this.right = right; + } + + /** + * Turns a left into a right and vice-versa. + * + * @return A new swapped either instance. + */ + public Either<R, L> swap() { + return new Either<R, L>(right, left); + } + + /** + * Returns an optional the will be {@link Optional#isPresent() present} is this is a left + * instance. + * + * @return An optional value for the left. + */ + public Optional<L> left() { + return left; + } + + /** + * Returns an optional the will be {@link Optional#isPresent() present} is this is a right + * instance. + * + * @return An optional value for the right. + */ + public Optional<R> right() { + return right; + } + + /** + * Returns {@code true} if this is a left instance. + * + * @return {@code true} if this is a left. + */ + public boolean isLeft() { + return left().isPresent(); + } + + /** + * Returns {@code true} if this is a right instance. + * + * @return {@code true} if this is a right. + */ + public boolean isRight() { + return right().isPresent(); + } + + /** + * Returns the underlying value if this is a left; otherwise, throws. + * + * @return The underlying value. + * @throws IllegalStateException if this is a right instance. + */ + public L getLeft() { + return left().get(); + } + + /** + * Returns the underlying value if this is a right; otherwise, throws. + * + * @return The underlying value. + * @throws IllegalStateException if this is a right instance. + */ + public R getRight() { + return right().get(); + } + + /** + * If this is a left, maps its value into a new left; otherwise just returns this right. + * + * @param transformer The transformation to apply to the left value. + * @param <M> The type a left value will be mapped to. + * @return The mapped left or else the right. + */ + public <M> Either<M, R> mapLeft(Function<? super L, M> transformer) { + if (isLeft()) { + return left(transformer.apply(getLeft())); + } else { + @SuppressWarnings("unchecked") // I am a right so my left is never accessible + Either<M, R> self = (Either<M, R>) this; + return self; + } + } + + /** + * If this is a right, maps its value into a new right; otherwise just returns this left. + * + * @param transformer The transformation to apply to the left value. + * @param <M> The type a right value will be mapped to. + * @return The mapped right or else the left. + */ + public <M> Either<L, M> mapRight(Function<? super R, M> transformer) { + if (isRight()) { + return right(transformer.apply(getRight())); + } else { + @SuppressWarnings("unchecked") // I am a left so my right is never accessible + Either<L, M> self = (Either<L, M>) this; + return self; + } + } + + /** + * Can transform either a left or a right into a result. + * + * @param <L> The left type. + * @param <R> The right type. + * @param <T> The transformation result type. + */ + public abstract static class Transformer<L, R, T> implements Function<Either<L, R>, T> { + + /** + * Maps left values to a result. + * + * @param left the left value to map. + * @return The mapped value. + */ + public abstract T mapLeft(L left); + + /** + * Maps right values to a result. + * + * @param right the right value to map. + * @return The mapped value. + */ + public abstract T mapRight(R right); + + @Override + public final T apply(Either<L, R> either) { + return either.map(this); + } + } + + /** + * Creates a transformer from left and right transformation functions. + * + * @param leftTransformer A transformer to process left values. + * @param rightTransformer A transformer to process right values. + * @param <L> The left type. + * @param <R> The right type. + * @param <T> The transformation result type. + * @return A new transformer composed of left and right transformer functions. + */ + public static <L, R, T> Transformer<L, R, T> transformer( + final Function<? super L, T> leftTransformer, + final Function<? super R, T> rightTransformer) { + + return new Transformer<L, R, T>() { + @Override public T mapLeft(L item) { + return leftTransformer.apply(item); + } + @Override public T mapRight(R item) { + return rightTransformer.apply(item); + } + }; + } + + /** + * Transforms this either instance to a value regardless of whether it is a left or a right. + * + * @param transformer The transformer to map this either instance. + * @param <T> The type the transformer produces. + * @return A value mapped by the transformer from this left or right instance. + */ + public <T> T map(final Transformer<? super L, ? super R, T> transformer) { + if (isLeft()) { + return transformer.mapLeft(getLeft()); + } else { + return transformer.mapRight(getRight()); + } + } + + @Override + public boolean equals(@Nullable Object o) { + if (!(o instanceof Either)) { + return false; + } + Either<?, ?> other = (Either<?, ?>) o; + return Objects.equal(left, other.left) + && Objects.equal(right, other.right); + } + + @Override + public int hashCode() { + return Objects.hashCode(left, right); + } + + @Override + public String toString() { + if (isLeft()) { + return String.format("Left(%s)", getLeft()); + } else { + return String.format("Right(%s)", getRight()); + } + } + + /** + * Creates a left either instance. + * + * @param value The left value to wrap - may not be null. + * @param <L> The left type. + * @param <R> The right type. + * @return A left either instance wrapping {@code value}. + */ + public static <L, R> Either<L, R> left(L value) { + return new Either<L, R>(Optional.of(value), Optional.<R>absent()); + } + + /** + * Creates a right either instance. + * + * @param value The right value to wrap - may not be null. + * @param <L> The left type. + * @param <R> The right type. + * @return A right either instance wrapping {@code value}. + */ + public static <L, R> Either<L, R> right(R value) { + return new Either<L, R>(Optional.<L>absent(), Optional.of(value)); + } + + /** + * Extracts all the lefts from a sequence of eithers lazily. + * + * @param results A sequence of either's to process. + * @param <L> The left type. + * @param <R> The right type. + * @return A lazy iterable that will produce the lefts present in results in order. + */ + public static <L, R> Iterable<L> lefts(Iterable<Either<L, R>> results) { + return Optional.presentInstances(Iterables.transform(results, + new Function<Either<L, R>, Optional<L>>() { + @Override public Optional<L> apply(Either<L, R> item) { + return item.left(); + } + })); + } + + /** + * Extracts all the rights from a sequence of eithers lazily. + * + * @param results A sequence of either's to process. + * @param <L> The left type. + * @param <R> The right type. + * @return A lazy iterable that will produce the rights present in results in order. + */ + public static <L, R> Iterable<R> rights(Iterable<Either<L, R>> results) { + return Optional.presentInstances(Iterables.transform(results, + new Function<Either<L, R>, Optional<R>>() { + @Override public Optional<R> apply(Either<L, R> item) { + return item.right(); + } + })); + } + + /** + * A convenience method equivalent to calling {@code guard(work, exceptionType)}. + */ + public static <X extends Exception, R> Either<X, R> guard( + Class<X> exceptionType, + ExceptionalSupplier<R, X> work) { + + @SuppressWarnings("unchecked") + Either<X, R> either = guard(work, exceptionType); + return either; + } + + /** + * A convenience method equivalent to calling + * {@code guard(Lists.asList(execpetionType, rest), work)}. + */ + public static <X extends Exception, R> Either<X, R> guard( + ExceptionalSupplier<R, X> work, + Class<? extends X> exceptionType, + Class<? extends X>... rest) { + + return guard(Lists.asList(exceptionType, rest), work); + } + + /** + * Thrown when guarded work throws an unguarded exception. The {@link #getCause() cause} will + * contain the original unguarded exception. + */ + public static class UnguardedException extends RuntimeException { + public UnguardedException(Throwable cause) { + super(cause); + } + } + + /** + * Converts work that can throw exceptions into an either with a left exception base type. This + * can be useful to fold an exception throwing library call into an either processing style + * pipeline. + * + * @param exceptionTypes The expected exception types. + * @param work The work to perform to get a result produce an error. + * @param <X> The base error type. + * @param <R> The success type. + * @return An either wrapping the result of performing {@code work}. + * @throws UnguardedException if work throws an unguarded exception type. + */ + public static <X extends Exception, R> Either<X, R> guard( + Iterable<Class<? extends X>> exceptionTypes, + ExceptionalSupplier<R, X> work) { + + try { + return right(work.get()); + // We're explicitly dealing with generic exception types here by design. + // SUPPRESS CHECKSTYLE RegexpSinglelineJava + } catch (Exception e) { + for (Class<? extends X> exceptionType : exceptionTypes) { + if (exceptionType.isInstance(e)) { + X exception = exceptionType.cast(e); + return left(exception); + } + } + throw new UnguardedException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java b/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java new file mode 100644 index 0000000..5bd540e --- /dev/null +++ b/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java @@ -0,0 +1,87 @@ +// ================================================================================================= +// 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.base; + +import com.google.common.base.Function; + +/** + * A utility for transporting checked exceptions across boundaries that do not allow for checked + * exception propagation. + * + * @param <E> The type of checked exception the ExceptionTransported can transport + * + * @author John Sirois + */ +public class ExceptionTransporter<E extends Exception> { + + /** + * An exception wrapper used to transport checked exceptions. Never leaves an + * {@link ExceptionTransporter#guard(com.google.common.base.Function)} call. + */ + private static final class TransportingException extends RuntimeException { + private TransportingException(Exception cause) { + super("It is a usage error to see this message!", cause); + } + } + + /** + * Guards a unit of work that internally can generate checked exceptions. Callers wrap up the + * work in a function that rethrows any checked exceptions using the supplied + * ExceptionTransporter. Guard will ensure the original exception is unwrapped an re-thrown. + * + * @param work The unit of work that guards its checked exceptions. + * @param <T> The type returned by the unit of work when it successfully completes. + * @param <X> The type of checked exception that the unit of work wishes to guard. + * @return the result of the unit of work if no excpetions are thrown + * @throws X when the unit of work uses the ExceptionTransporter to throw a checked exception + */ + public static <T, X extends Exception> T guard(Function<ExceptionTransporter<X>, T> work) + throws X { + + try { + return work.apply(new ExceptionTransporter<X>()); + } catch (TransportingException e) { + @SuppressWarnings("unchecked") + X cause = (X) e.getCause(); + throw cause; + } + } + + /** + * Throws the given {@code checked} exception across a boundary that does not allow checked + * exceptions. Although a RuntimeException is returned by this method signature, the method never + * actually completes normally. The return type does allow the following usage idiom however: + * <pre> + * public String apply(ExceptionTransporter transporter) { + * try { + * return doChecked(); + * } catch (CheckedException e) { + * // Although transport internally throws and does not return, we satisfy the compiler that + * // our method returns a value or throws by pretending to throw the RuntimeException that + * // never actually gets returned by transporter.transport(...) + * throw transporter.transport(e); + * } + * } + * </pre> + * + * @param checked The checked exception to transport. + * @return A RuntimeException that can be thrown to satisfy the compiler at the call site + */ + public RuntimeException transport(E checked) { + throw new TransportingException(checked); + } +}
