Not anonymous inner classes in functions - Anonymous inner classes makes persistence very brittle. - Adds more tests.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f22b3eb4 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f22b3eb4 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f22b3eb4 Branch: refs/heads/master Commit: f22b3eb4319d7c9d6e2604b0266bef8287889b86 Parents: 74207bd Author: Aled Sage <[email protected]> Authored: Wed Oct 7 10:20:46 2015 +0100 Committer: Aled Sage <[email protected]> Committed: Mon Oct 12 10:18:15 2015 +0100 ---------------------------------------------------------------------- .../brooklyn/core/entity/EntityFunctions.java | 178 ++++++++- .../brooklyn/feed/http/HttpValueFunctions.java | 3 + .../brooklyn/feed/http/JsonFunctions.java | 385 ++++++++++++++----- .../brooklyn/feed/ssh/SshValueFunctions.java | 80 +++- .../brooklyn/feed/http/JsonFunctionsTest.java | 15 +- .../feed/ssh/SshValueFunctionsTest.java | 43 +++ .../brooklyn/feed/jmx/JmxValueFunctions.java | 55 ++- .../feed/jmx/JmxValueFunctionsTest.java | 120 ++++++ .../brooklyn/util/guava/MaybeFunctions.java | 52 ++- .../brooklyn/util/math/MathFunctions.java | 204 +++++++++- .../brooklyn/util/text/StringFunctions.java | 301 +++++++++++++-- .../brooklyn/util/guava/MaybeFunctionsTest.java | 47 +++ .../brooklyn/util/math/MathFunctionsTest.java | 16 +- .../brooklyn/util/text/StringFunctionsTest.java | 41 +- 14 files changed, 1342 insertions(+), 198 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java index 331fb7d..a4459ed 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java @@ -43,7 +43,10 @@ import com.google.common.collect.Iterables; public class EntityFunctions { - public static <T> Function<Entity, T> attribute(final AttributeSensor<T> attribute) { + /** @deprecated since 0.9.0 kept only to allow conversion of non-static inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<Entity, T> attributeOld(final AttributeSensor<T> attribute) { + // TODO PERSISTENCE WORKAROUND class GetEntityAttributeFunction implements Function<Entity, T> { @Override public T apply(Entity input) { return (input == null) ? null : input.getAttribute(attribute); @@ -52,7 +55,10 @@ public class EntityFunctions { return new GetEntityAttributeFunction(); } - public static <T> Function<Entity, T> config(final ConfigKey<T> key) { + /** @deprecated since 0.9.0 kept only to allow conversion of non-static inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<Entity, T> configOld(final ConfigKey<T> key) { + // TODO PERSISTENCE WORKAROUND class GetEntityConfigFunction implements Function<Entity, T> { @Override public T apply(Entity input) { return (input == null) ? null : input.getConfig(key); @@ -61,7 +67,10 @@ public class EntityFunctions { return new GetEntityConfigFunction(); } - public static Function<Entity, String> displayName() { + /** @deprecated since 0.9.0 kept only to allow conversion of non-static inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Entity, String> displayNameOld() { + // TODO PERSISTENCE WORKAROUND class GetEntityDisplayName implements Function<Entity, String> { @Override public String apply(Entity input) { return (input == null) ? null : input.getDisplayName(); @@ -70,7 +79,10 @@ public class EntityFunctions { return new GetEntityDisplayName(); } - public static Function<Identifiable, String> id() { + /** @deprecated since 0.9.0 kept only to allow conversion of non-static inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Identifiable, String> idOld() { + // TODO PERSISTENCE WORKAROUND class GetIdFunction implements Function<Identifiable, String> { @Override public String apply(Identifiable input) { return (input == null) ? null : input.getId(); @@ -79,10 +91,10 @@ public class EntityFunctions { return new GetIdFunction(); } - /** returns a function which sets the given sensors on the entity passed in, - * with {@link Entities#UNCHANGED} and {@link Entities#REMOVE} doing those actions. */ - public static Function<Entity,Void> settingSensorsConstant(final Map<AttributeSensor<?>,Object> values) { - checkNotNull(values, "values"); + /** @deprecated since 0.9.0 kept only to allow conversion of non-static inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Entity,Void> settingSensorsConstantOld(final Map<AttributeSensor<?>,Object> values) { + // TODO PERSISTENCE WORKAROUND class SettingSensorsConstantFunction implements Function<Entity, Void> { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Void apply(Entity input) { @@ -104,14 +116,10 @@ public class EntityFunctions { return new SettingSensorsConstantFunction(); } - /** as {@link #settingSensorsConstant(Map)} but as a {@link Runnable} */ - public static Runnable settingSensorsConstant(final Entity entity, final Map<AttributeSensor<?>,Object> values) { - checkNotNull(entity, "entity"); - checkNotNull(values, "values"); - return Functionals.runnable(Suppliers.compose(settingSensorsConstant(values), Suppliers.ofInstance(entity))); - } - - public static <K,V> Function<Entity, Void> updatingSensorMapEntry(final AttributeSensor<Map<K,V>> mapSensor, final K key, final Supplier<? extends V> valueSupplier) { + /** @deprecated since 0.9.0 kept only to allow conversion of non-static inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <K,V> Function<Entity, Void> updatingSensorMapEntryOld(final AttributeSensor<Map<K,V>> mapSensor, final K key, final Supplier<? extends V> valueSupplier) { + // TODO PERSISTENCE WORKAROUND class UpdatingSensorMapEntryFunction implements Function<Entity, Void> { @Override public Void apply(Entity input) { ServiceStateLogic.updateMapSensorEntry((EntityLocal)input, mapSensor, key, valueSupplier.get()); @@ -120,11 +128,11 @@ public class EntityFunctions { } return new UpdatingSensorMapEntryFunction(); } - public static <K,V> Runnable updatingSensorMapEntry(final Entity entity, final AttributeSensor<Map<K,V>> mapSensor, final K key, final Supplier<? extends V> valueSupplier) { - return Functionals.runnable(Suppliers.compose(updatingSensorMapEntry(mapSensor, key, valueSupplier), Suppliers.ofInstance(entity))); - } - public static Supplier<Collection<Application>> applications(final ManagementContext mgmt) { + /** @deprecated since 0.9.0 kept only to allow conversion of non-static inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Supplier<Collection<Application>> applicationsOld(final ManagementContext mgmt) { + // TODO PERSISTENCE WORKAROUND class AppsSupplier implements Supplier<Collection<Application>> { @Override public Collection<Application> get() { @@ -134,6 +142,136 @@ public class EntityFunctions { return new AppsSupplier(); } + public static <T> Function<Entity, T> attribute(AttributeSensor<T> attribute) { + return new GetEntityAttributeFunction<T>(checkNotNull(attribute, "attribute")); + } + + protected static class GetEntityAttributeFunction<T> implements Function<Entity, T> { + private final AttributeSensor<T> attribute; + protected GetEntityAttributeFunction(AttributeSensor<T> attribute) { + this.attribute = attribute; + } + @Override public T apply(Entity input) { + return (input == null) ? null : input.getAttribute(attribute); + } + }; + + public static <T> Function<Entity, T> config(ConfigKey<T> key) { + return new GetEntityConfigFunction<T>(checkNotNull(key, "key")); + } + + protected static class GetEntityConfigFunction<T> implements Function<Entity, T> { + private final ConfigKey<T> key; + + protected GetEntityConfigFunction(ConfigKey<T> key) { + this.key = key; + } + + @Override public T apply(Entity input) { + return (input == null) ? null : input.getConfig(key); + } + }; + + public static Function<Entity, String> displayName() { + return GetEntityDisplayName.INSTANCE; + } + + protected static class GetEntityDisplayName implements Function<Entity, String> { + public static final GetEntityDisplayName INSTANCE = new GetEntityDisplayName(); + @Override public String apply(Entity input) { + return (input == null) ? null : input.getDisplayName(); + } + }; + + public static Function<Identifiable, String> id() { + return GetIdFunction.INSTANCE; + } + + protected static class GetIdFunction implements Function<Identifiable, String> { + public static final GetIdFunction INSTANCE = new GetIdFunction(); + @Override public String apply(Identifiable input) { + return (input == null) ? null : input.getId(); + } + }; + + + /** returns a function which sets the given sensors on the entity passed in, + * with {@link Entities#UNCHANGED} and {@link Entities#REMOVE} doing those actions. */ + public static Function<Entity,Void> settingSensorsConstant(final Map<AttributeSensor<?>,Object> values) { + return new SettingSensorsConstantFunction(checkNotNull(values, "values")); + } + + protected static class SettingSensorsConstantFunction implements Function<Entity, Void> { + private final Map<AttributeSensor<?>, Object> values; + + protected SettingSensorsConstantFunction(Map<AttributeSensor<?>, Object> values) { + this.values = values; + } + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override public Void apply(Entity input) { + for (Map.Entry<AttributeSensor<?>,Object> entry : values.entrySet()) { + AttributeSensor sensor = (AttributeSensor)entry.getKey(); + Object value = entry.getValue(); + if (value==Entities.UNCHANGED) { + // nothing + } else if (value==Entities.REMOVE) { + ((EntityInternal)input).sensors().remove(sensor); + } else { + value = TypeCoercions.coerce(value, sensor.getTypeToken()); + ((EntityInternal)input).sensors().set(sensor, value); + } + } + return null; + } + } + + /** as {@link #settingSensorsConstant(Map)} but as a {@link Runnable} */ + public static Runnable settingSensorsConstant(final Entity entity, final Map<AttributeSensor<?>,Object> values) { + checkNotNull(entity, "entity"); + checkNotNull(values, "values"); + return Functionals.runnable(Suppliers.compose(settingSensorsConstant(values), Suppliers.ofInstance(entity))); + } + + public static <K,V> Function<Entity, Void> updatingSensorMapEntry(final AttributeSensor<Map<K,V>> mapSensor, final K key, final Supplier<? extends V> valueSupplier) { + return new UpdatingSensorMapEntryFunction<K,V>(mapSensor, key, valueSupplier); + } + + protected static class UpdatingSensorMapEntryFunction<K, V> implements Function<Entity, Void> { + private final AttributeSensor<Map<K, V>> mapSensor; + private final K key; + private final Supplier<? extends V> valueSupplier; + + public UpdatingSensorMapEntryFunction(AttributeSensor<Map<K, V>> mapSensor, K key, Supplier<? extends V> valueSupplier) { + this.mapSensor = mapSensor; + this.key = key; + this.valueSupplier = valueSupplier; + } + @Override public Void apply(Entity input) { + ServiceStateLogic.updateMapSensorEntry((EntityLocal)input, mapSensor, key, valueSupplier.get()); + return null; + } + } + + public static <K,V> Runnable updatingSensorMapEntry(final Entity entity, final AttributeSensor<Map<K,V>> mapSensor, final K key, final Supplier<? extends V> valueSupplier) { + return Functionals.runnable(Suppliers.compose(updatingSensorMapEntry(mapSensor, key, valueSupplier), Suppliers.ofInstance(entity))); + } + + public static Supplier<Collection<Application>> applications(ManagementContext mgmt) { + return new AppsSupplier(checkNotNull(mgmt, "mgmt")); + } + + protected static class AppsSupplier implements Supplier<Collection<Application>> { + private final ManagementContext mgmt; + + public AppsSupplier(ManagementContext mgmt) { + this.mgmt = mgmt; + } + @Override + public Collection<Application> get() { + return mgmt.getApplications(); + } + } + public static Function<Entity, Location> locationMatching(Predicate<? super Location> filter) { return new LocationMatching(filter); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java b/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java index 75dab74..0fec133 100644 --- a/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java +++ b/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java @@ -39,6 +39,7 @@ public class HttpValueFunctions { /** @deprecated since 0.7.0; only here for deserialization of persisted state */ private static Function<HttpToolResponse, Integer> responseCodeLegacy() { + // TODO PERSISTENCE WORKAROUND kept anonymous function in case referenced in persisted state return new Function<HttpToolResponse, Integer>() { @Override public Integer apply(HttpToolResponse input) { return input.getResponseCode(); @@ -70,6 +71,7 @@ public class HttpValueFunctions { /** @deprecated since 0.7.0; only here for deserialization of persisted state */ private static Function<HttpToolResponse, String> stringContentsFunctionLegacy() { + // TODO PERSISTENCE WORKAROUND kept anonymous function in case referenced in persisted state return new Function<HttpToolResponse, String>() { @Override public String apply(HttpToolResponse input) { return input.getContentAsString(); @@ -105,6 +107,7 @@ public class HttpValueFunctions { /** @deprecated since 0.7.0; only here for deserialization of persisted state */ private static Function<HttpToolResponse, Long> latencyLegacy() { + // TODO PERSISTENCE WORKAROUND kept anonymous function in case referenced in persisted state return new Function<HttpToolResponse, Long>() { public Long apply(HttpToolResponse input) { return input.getLatencyFullContent(); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java b/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java index a3e04cd..beff29f 100644 --- a/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java +++ b/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java @@ -34,14 +34,20 @@ import org.apache.brooklyn.util.guava.MaybeFunctions; import com.google.common.base.Function; import com.google.common.base.Splitter; import com.google.common.collect.Lists; -import com.google.gson.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.jayway.jsonpath.JsonPath; public class JsonFunctions { private JsonFunctions() {} // instead use static utility methods - public static Function<String, JsonElement> asJson() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String, JsonElement> asJsonOld() { + // TODO PERSISTENCE WORKAROUND return new Function<String, JsonElement>() { @Override public JsonElement apply(String input) { return new JsonParser().parse(input); @@ -49,7 +55,10 @@ public class JsonFunctions { }; } - public static <T> Function<JsonElement, List<T>> forEach(final Function<JsonElement, T> func) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<JsonElement, List<T>> forEachOld(final Function<JsonElement, T> func) { + // TODO PERSISTENCE WORKAROUND return new Function<JsonElement, List<T>>() { @Override public List<T> apply(JsonElement input) { JsonArray array = (JsonArray) input; @@ -62,7 +71,129 @@ public class JsonFunctions { }; } + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<JsonElement, JsonElement> walkOld(final Iterable<String> elements) { + // TODO PERSISTENCE WORKAROUND + return new Function<JsonElement, JsonElement>() { + @Override public JsonElement apply(JsonElement input) { + JsonElement curr = input; + for (String element : elements) { + JsonObject jo = curr.getAsJsonObject(); + curr = jo.get(element); + if (curr==null) + throw new NoSuchElementException("No element '"+element+" in JSON, when walking "+elements); + } + return curr; + } + }; + } + + /** as {@link #walk(Iterable))} but if any element is not found it simply returns null */ + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<JsonElement, JsonElement> walkNOld(final Iterable<String> elements) { + // TODO PERSISTENCE WORKAROUND + return new Function<JsonElement, JsonElement>() { + @Override public JsonElement apply(JsonElement input) { + JsonElement curr = input; + for (String element : elements) { + if (curr==null) return null; + JsonObject jo = curr.getAsJsonObject(); + curr = jo.get(element); + } + return curr; + } + }; + } + + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkMOld(final Iterable<String> elements) { + // TODO PERSISTENCE WORKAROUND + return new Function<Maybe<JsonElement>, Maybe<JsonElement>>() { + @Override public Maybe<JsonElement> apply(Maybe<JsonElement> input) { + Maybe<JsonElement> curr = input; + for (String element : elements) { + if (curr.isAbsent()) return curr; + JsonObject jo = curr.get().getAsJsonObject(); + JsonElement currO = jo.get(element); + if (currO==null) return Maybe.absent("No element '"+element+" in JSON, when walking "+elements); + curr = Maybe.of(currO); + } + return curr; + } + }; + } + + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<JsonElement,T> getPathOld(final String path) { + // TODO PERSISTENCE WORKAROUND + return new Function<JsonElement, T>() { + @SuppressWarnings("unchecked") + @Override public T apply(JsonElement input) { + String jsonString = input.toString(); + Object rawElement = JsonPath.read(jsonString, path); + return (T) rawElement; + } + }; + } + + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<JsonElement, T> castOld(final Class<T> expected) { + // TODO PERSISTENCE WORKAROUND + return new Function<JsonElement, T>() { + @Override public T apply(JsonElement input) { + return doCast(input, expected); + } + }; + } + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<Maybe<JsonElement>, T> castMOld(final Class<T> expected, final T defaultValue) { + // TODO PERSISTENCE WORKAROUND + return new Function<Maybe<JsonElement>, T>() { + @Override + public T apply(Maybe<JsonElement> input) { + if (input.isAbsent()) return defaultValue; + return cast(expected).apply(input.get()); + } + }; + } + + public static Function<String, JsonElement> asJson() { + return new AsJson(); + } + + protected static class AsJson implements Function<String, JsonElement> { + @Override public JsonElement apply(String input) { + return new JsonParser().parse(input); + } + } + + public static <T> Function<JsonElement, List<T>> forEach(final Function<JsonElement, T> func) { + return new ForEach<T>(func); + } + + protected static class ForEach<T> implements Function<JsonElement, List<T>> { + private final Function<JsonElement, T> func; + public ForEach(Function<JsonElement, T> func) { + this.func = func; + } + + @Override public List<T> apply(JsonElement input) { + JsonArray array = (JsonArray) input; + List<T> result = Lists.newArrayList(); + for (int i = 0; i < array.size(); i++) { + result.add(func.apply(array.get(i))); + } + return result; + } + } + /** as {@link #walkM(Iterable)} taking a single string consisting of a dot separated path */ public static Function<JsonElement, JsonElement> walk(String elementOrDotSeparatedElements) { return walk( Splitter.on('.').split(elementOrDotSeparatedElements) ); @@ -78,21 +209,25 @@ public class JsonFunctions { public static Function<JsonElement, JsonElement> walk(final Iterable<String> elements) { // could do this instead, pointing at Maybe for this, and for walkN, but it's slightly less efficient // return Functionals.chain(MaybeFunctions.<JsonElement>wrap(), walkM(elements), MaybeFunctions.<JsonElement>get()); + return new Walk(elements); + } - return new Function<JsonElement, JsonElement>() { - @Override public JsonElement apply(JsonElement input) { - JsonElement curr = input; - for (String element : elements) { - JsonObject jo = curr.getAsJsonObject(); - curr = jo.get(element); - if (curr==null) - throw new NoSuchElementException("No element '"+element+" in JSON, when walking "+elements); - } - return curr; + protected static class Walk implements Function<JsonElement, JsonElement> { + private final Iterable<String> elements; + public Walk(Iterable<String> elements) { + this.elements = elements; + } + @Override public JsonElement apply(JsonElement input) { + JsonElement curr = input; + for (String element : elements) { + JsonObject jo = curr.getAsJsonObject(); + curr = jo.get(element); + if (curr==null) + throw new NoSuchElementException("No element '"+element+" in JSON, when walking "+elements); } - }; + return curr; + } } - /** as {@link #walk(String)} but if any element is not found it simply returns null */ public static Function<JsonElement, JsonElement> walkN(@Nullable String elements) { @@ -106,17 +241,24 @@ public class JsonFunctions { /** as {@link #walk(Iterable))} but if any element is not found it simply returns null */ public static Function<JsonElement, JsonElement> walkN(final Iterable<String> elements) { - return new Function<JsonElement, JsonElement>() { - @Override public JsonElement apply(JsonElement input) { - JsonElement curr = input; - for (String element : elements) { - if (curr==null) return null; - JsonObject jo = curr.getAsJsonObject(); - curr = jo.get(element); - } - return curr; + return new WalkN(elements); + } + + protected static class WalkN implements Function<JsonElement, JsonElement> { + private final Iterable<String> elements; + + public WalkN(Iterable<String> elements) { + this.elements = elements; + } + @Override public JsonElement apply(JsonElement input) { + JsonElement curr = input; + for (String element : elements) { + if (curr==null) return null; + JsonObject jo = curr.getAsJsonObject(); + curr = jo.get(element); } - }; + return curr; + } } /** as {@link #walk(String))} and {@link #walk(Iterable)} */ @@ -133,89 +275,116 @@ public class JsonFunctions { * simply preserving a {@link Maybe#absent()} object if additional walks are requested upon it * (cf jquery) */ public static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkM(final Iterable<String> elements) { - return new Function<Maybe<JsonElement>, Maybe<JsonElement>>() { - @Override public Maybe<JsonElement> apply(Maybe<JsonElement> input) { - Maybe<JsonElement> curr = input; - for (String element : elements) { - if (curr.isAbsent()) return curr; - JsonObject jo = curr.get().getAsJsonObject(); - JsonElement currO = jo.get(element); - if (currO==null) return Maybe.absent("No element '"+element+" in JSON, when walking "+elements); - curr = Maybe.of(currO); - } - return curr; - } - }; + return new WalkM(elements); } + protected static class WalkM implements Function<Maybe<JsonElement>, Maybe<JsonElement>> { + private final Iterable<String> elements; + + public WalkM(Iterable<String> elements) { + this.elements = elements; + } + + @Override public Maybe<JsonElement> apply(Maybe<JsonElement> input) { + Maybe<JsonElement> curr = input; + for (String element : elements) { + if (curr.isAbsent()) return curr; + JsonObject jo = curr.get().getAsJsonObject(); + JsonElement currO = jo.get(element); + if (currO==null) return Maybe.absent("No element '"+element+" in JSON, when walking "+elements); + curr = Maybe.of(currO); + } + return curr; + } + } + /** * returns an element from a single json primitive value given a full path {@link com.jayway.jsonpath.JsonPath} */ public static <T> Function<JsonElement,T> getPath(final String path) { - return new Function<JsonElement, T>() { - @SuppressWarnings("unchecked") - @Override public T apply(JsonElement input) { - String jsonString = input.toString(); - Object rawElement = JsonPath.read(jsonString, path); - return (T) rawElement; - } - }; + return new GetPath<T>(path); } - @SuppressWarnings("unchecked") + protected static class GetPath<T> implements Function<JsonElement, T> { + private final String path; + + public GetPath(String path) { + this.path = path; + } + @SuppressWarnings("unchecked") + @Override public T apply(JsonElement input) { + String jsonString = input.toString(); + Object rawElement = JsonPath.read(jsonString, path); + return (T) rawElement; + } + }; + public static <T> Function<JsonElement, T> cast(final Class<T> expected) { - return new Function<JsonElement, T>() { - @Override public T apply(JsonElement input) { - if (input == null) { - return (T) null; - } else if (input.isJsonNull()) { - return (T) null; - } else if (expected == boolean.class || expected == Boolean.class) { - return (T) (Boolean) input.getAsBoolean(); - } else if (expected == char.class || expected == Character.class) { - return (T) (Character) input.getAsCharacter(); - } else if (expected == byte.class || expected == Byte.class) { - return (T) (Byte) input.getAsByte(); - } else if (expected == short.class || expected == Short.class) { - return (T) (Short) input.getAsShort(); - } else if (expected == int.class || expected == Integer.class) { - return (T) (Integer) input.getAsInt(); - } else if (expected == long.class || expected == Long.class) { - return (T) (Long) input.getAsLong(); - } else if (expected == float.class || expected == Float.class) { - return (T) (Float) input.getAsFloat(); - } else if (expected == double.class || expected == Double.class) { - return (T) (Double) input.getAsDouble(); - } else if (expected == BigDecimal.class) { - return (T) input.getAsBigDecimal(); - } else if (expected == BigInteger.class) { - return (T) input.getAsBigInteger(); - } else if (Number.class.isAssignableFrom(expected)) { - // TODO Will result in a class-cast if it's an unexpected sub-type of Number not handled above - return (T) input.getAsNumber(); - } else if (expected == String.class) { - return (T) input.getAsString(); - } else if (expected.isArray()) { - JsonArray array = input.getAsJsonArray(); - Class<?> componentType = expected.getComponentType(); - if (JsonElement.class.isAssignableFrom(componentType)) { - JsonElement[] result = new JsonElement[array.size()]; - for (int i = 0; i < array.size(); i++) { - result[i] = array.get(i); - } - return (T) result; - } else { - Object[] result = (Object[]) Array.newInstance(componentType, array.size()); - for (int i = 0; i < array.size(); i++) { - result[i] = cast(componentType).apply(array.get(i)); - } - return (T) result; - } - } else { - throw new IllegalArgumentException("Cannot cast json element to type "+expected); + return new Cast<T>(expected); + } + + protected static class Cast<T> implements Function<JsonElement, T> { + private final Class<T> expected; + + public Cast(Class<T> expected) { + this.expected = expected; + } + + @Override public T apply(JsonElement input) { + return doCast(input, expected); + } + }; + + @SuppressWarnings("unchecked") + protected static <T> T doCast(JsonElement input, Class<T> expected) { + if (input == null) { + return (T) null; + } else if (input.isJsonNull()) { + return (T) null; + } else if (expected == boolean.class || expected == Boolean.class) { + return (T) (Boolean) input.getAsBoolean(); + } else if (expected == char.class || expected == Character.class) { + return (T) (Character) input.getAsCharacter(); + } else if (expected == byte.class || expected == Byte.class) { + return (T) (Byte) input.getAsByte(); + } else if (expected == short.class || expected == Short.class) { + return (T) (Short) input.getAsShort(); + } else if (expected == int.class || expected == Integer.class) { + return (T) (Integer) input.getAsInt(); + } else if (expected == long.class || expected == Long.class) { + return (T) (Long) input.getAsLong(); + } else if (expected == float.class || expected == Float.class) { + return (T) (Float) input.getAsFloat(); + } else if (expected == double.class || expected == Double.class) { + return (T) (Double) input.getAsDouble(); + } else if (expected == BigDecimal.class) { + return (T) input.getAsBigDecimal(); + } else if (expected == BigInteger.class) { + return (T) input.getAsBigInteger(); + } else if (Number.class.isAssignableFrom(expected)) { + // TODO Will result in a class-cast if it's an unexpected sub-type of Number not handled above + return (T) input.getAsNumber(); + } else if (expected == String.class) { + return (T) input.getAsString(); + } else if (expected.isArray()) { + JsonArray array = input.getAsJsonArray(); + Class<?> componentType = expected.getComponentType(); + if (JsonElement.class.isAssignableFrom(componentType)) { + JsonElement[] result = new JsonElement[array.size()]; + for (int i = 0; i < array.size(); i++) { + result[i] = array.get(i); } + return (T) result; + } else { + Object[] result = (Object[]) Array.newInstance(componentType, array.size()); + for (int i = 0; i < array.size(); i++) { + result[i] = cast(componentType).apply(array.get(i)); + } + return (T) result; } - }; + } else { + throw new IllegalArgumentException("Cannot cast json element to type "+expected); + } } public static <T> Function<Maybe<JsonElement>, T> castM(final Class<T> expected) { @@ -223,13 +392,21 @@ public class JsonFunctions { } public static <T> Function<Maybe<JsonElement>, T> castM(final Class<T> expected, final T defaultValue) { - return new Function<Maybe<JsonElement>, T>() { - @Override - public T apply(Maybe<JsonElement> input) { - if (input.isAbsent()) return defaultValue; - return cast(expected).apply(input.get()); - } - }; + return new CastM<T>(expected, defaultValue); } + protected static class CastM<T> implements Function<Maybe<JsonElement>, T> { + private final Class<T> expected; + private final T defaultValue; + + public CastM(Class<T> expected, T defaultValue) { + this.expected = expected; + this.defaultValue = defaultValue; + } + @Override + public T apply(Maybe<JsonElement> input) { + if (input.isAbsent()) return defaultValue; + return cast(expected).apply(input.get()); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java index 370c3ce..20a95c2 100644 --- a/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java +++ b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java @@ -20,13 +20,18 @@ package org.apache.brooklyn.feed.ssh; import javax.annotation.Nullable; +import org.apache.brooklyn.util.guava.Functionals; + import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Predicates; public class SshValueFunctions { - public static Function<SshPollValue, Integer> exitStatus() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<SshPollValue, Integer> exitStatusOld() { + // TODO PERSISTENCE WORKAROUND return new Function<SshPollValue, Integer>() { @Override public Integer apply(SshPollValue input) { return input.getExitStatus(); @@ -34,7 +39,10 @@ public class SshValueFunctions { }; } - public static Function<SshPollValue, String> stdout() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<SshPollValue, String> stdoutOld() { + // TODO PERSISTENCE WORKAROUND return new Function<SshPollValue, String>() { @Override public String apply(SshPollValue input) { return input.getStdout(); @@ -42,7 +50,10 @@ public class SshValueFunctions { }; } - public static Function<SshPollValue, String> stderr() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<SshPollValue, String> stderrOld() { + // TODO PERSISTENCE WORKAROUND return new Function<SshPollValue, String>() { @Override public String apply(SshPollValue input) { return input.getStderr(); @@ -50,12 +61,10 @@ public class SshValueFunctions { }; } - public static Function<SshPollValue, Boolean> exitStatusEquals(final int expected) { - return chain(SshValueFunctions.exitStatus(), Functions.forPredicate(Predicates.equalTo(expected))); - } - - // TODO Do we want these chain methods? Does guava have them already? Duplicated in HttpValueFunctions. - public static <A,B,C> Function<A,C> chain(final Function<A,? extends B> f1, final Function<B,C> f2) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <A,B,C> Function<A,C> chainOld(final Function<A,? extends B> f1, final Function<B,C> f2) { + // TODO PERSISTENCE WORKAROUND return new Function<A,C>() { @Override public C apply(@Nullable A input) { return f2.apply(f1.apply(input)); @@ -63,11 +72,62 @@ public class SshValueFunctions { }; } - public static <A,B,C,D> Function<A,D> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,D> f3) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <A,B,C,D> Function<A,D> chainOld(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,D> f3) { + // TODO PERSISTENCE WORKAROUND return new Function<A,D>() { @Override public D apply(@Nullable A input) { return f3.apply(f2.apply(f1.apply(input))); } }; } + + public static Function<SshPollValue, Integer> exitStatus() { + return new ExitStatus(); + } + + protected static class ExitStatus implements Function<SshPollValue, Integer> { + @Override public Integer apply(SshPollValue input) { + return input.getExitStatus(); + } + } + + public static Function<SshPollValue, String> stdout() { + return new Stdout(); + } + + protected static class Stdout implements Function<SshPollValue, String> { + @Override public String apply(SshPollValue input) { + return input.getStdout(); + } + } + + public static Function<SshPollValue, String> stderr() { + return new Stderr(); + } + + protected static class Stderr implements Function<SshPollValue, String> { + @Override public String apply(SshPollValue input) { + return input.getStderr(); + } + } + + public static Function<SshPollValue, Boolean> exitStatusEquals(final int expected) { + return chain(SshValueFunctions.exitStatus(), Functions.forPredicate(Predicates.equalTo(expected))); + } + + /** + * @deprecated since 0.9.0; use {@link Functionals#chain(Function, Function)} + */ + public static <A,B,C> Function<A,C> chain(final Function<A,? extends B> f1, final Function<B,C> f2) { + return Functionals.chain(f1, f2); + } + + /** + * @deprecated since 0.9.0; use {@link Functionals#chain(Function, Function, Function)} + */ + public static <A,B,C,D> Function<A,D> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,D> f3) { + return Functionals.chain(f1, f2, f3); + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java b/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java index 928035e..ba654a4 100644 --- a/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java +++ b/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java @@ -20,10 +20,9 @@ package org.apache.brooklyn.feed.http; import java.util.NoSuchElementException; -import org.apache.brooklyn.feed.http.JsonFunctions; import org.apache.brooklyn.util.collections.Jsonya; -import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.Jsonya.Navigator; +import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.guava.Functionals; import org.apache.brooklyn.util.guava.Maybe; import org.testng.Assert; @@ -78,12 +77,18 @@ public class JsonFunctionsTest { Assert.assertTrue(m.isAbsent()); } - @Test(expectedExceptions=Exception.class) - public void testWalkMWrong2() { - Maybe<JsonElement> m = JsonFunctions.walkM("europe", "spain", "barcelona").apply( Maybe.of( europeMap()) ); + @Test(expectedExceptions=IllegalStateException.class) + public void testCastMWhenAbsent() { +// Maybe<JsonElement> m = JsonFunctions.walkM("europe", "spain", "barcelona").apply( Maybe.of( europeMap()) ); + Maybe<JsonElement> m = Maybe.absent(); JsonFunctions.castM(String.class).apply(m); } + @Test(expectedExceptions=UnsupportedOperationException.class) + public void testCastMWrong() { + Maybe<JsonElement> m = JsonFunctions.walkM("europe", "france").apply( Maybe.of( europeMap()) ); + JsonFunctions.castM(String.class).apply(m); + } @Test public void testWalkN() { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/core/src/test/java/org/apache/brooklyn/feed/ssh/SshValueFunctionsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/feed/ssh/SshValueFunctionsTest.java b/core/src/test/java/org/apache/brooklyn/feed/ssh/SshValueFunctionsTest.java new file mode 100644 index 0000000..51e818f --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/feed/ssh/SshValueFunctionsTest.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License 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 org.apache.brooklyn.feed.ssh; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +public class SshValueFunctionsTest { + + private SshPollValue val = new SshPollValue(null, 123, "mystdout", "mystderr"); + + @Test + public void testExitCode() throws Exception { + assertEquals(SshValueFunctions.exitStatus().apply(val), (Integer)123); + } + + @Test + public void testStdout() throws Exception { + assertEquals(SshValueFunctions.stdout().apply(val), "mystdout"); + } + + @Test + public void testStderr() throws Exception { + assertEquals(SshValueFunctions.stderr().apply(val), "mystderr"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java index 5741099..a0549b2 100644 --- a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java +++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java @@ -24,40 +24,81 @@ import java.util.Map; import javax.management.openmbean.CompositeData; import javax.management.openmbean.TabularData; +import org.apache.brooklyn.api.location.Location; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; +import com.google.common.base.Predicate; import com.google.common.collect.Maps; public class JmxValueFunctions { private static final Logger log = LoggerFactory.getLogger(JmxValueFunctions.class); - - /** - * @return a closure that converts a TabularDataSupport to a map. - */ - public static Function<TabularData, Map> tabularDataToMap() { + + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<TabularData, Map> tabularDataToMapOld() { + // TODO PERSISTENCE WORKAROUND return new Function<TabularData, Map>() { @Override public Map apply(TabularData input) { return tabularDataToMap(input); }}; } - public static Function<TabularData, Map> tabularDataToMapOfMaps() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<TabularData, Map> tabularDataToMapOfMapsOld() { + // TODO PERSISTENCE WORKAROUND return new Function<TabularData, Map>() { @Override public Map apply(TabularData input) { return tabularDataToMapOfMaps(input); }}; } - public static Function<CompositeData,Map> compositeDataToMap() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<CompositeData,Map> compositeDataToMapOld() { + // TODO PERSISTENCE WORKAROUND return new Function<CompositeData, Map>() { @Override public Map apply(CompositeData input) { return compositeDataToMap(input); }}; } + /** + * @return a closure that converts a TabularDataSupport to a map. + */ + public static Function<TabularData, Map> tabularDataToMap() { + return new TabularDataToMap(); + } + + protected static class TabularDataToMap implements Function<TabularData, Map> { + @Override public Map apply(TabularData input) { + return tabularDataToMap(input); + } + } + + public static Function<TabularData, Map> tabularDataToMapOfMaps() { + return new TabularDataToMapOfMaps(); + } + + protected static class TabularDataToMapOfMaps implements Function<TabularData, Map> { + @Override public Map apply(TabularData input) { + return tabularDataToMapOfMaps(input); + } + } + + public static Function<CompositeData,Map> compositeDataToMap() { + return new CompositeDataToMap(); + } + + protected static class CompositeDataToMap implements Function<CompositeData, Map> { + @Override public Map apply(CompositeData input) { + return compositeDataToMap(input); + } + } + public static Map tabularDataToMap(TabularData table) { Map<String, Object> result = Maps.newLinkedHashMap(); for (Object entry : table.values()) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxValueFunctionsTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxValueFunctionsTest.java b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxValueFunctionsTest.java new file mode 100644 index 0000000..83f4899 --- /dev/null +++ b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxValueFunctionsTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License 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 org.apache.brooklyn.feed.jmx; + +import static org.testng.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class JmxValueFunctionsTest { + + @Test + public void testCompositeDataToMap() throws Exception { + CompositeType compositeType = new CompositeType( + "MyCompositeType", + "my composite descr", + new String[] {"key1", "key2"}, + new String[] {"key1 descr", "key2 descr"}, + new OpenType[] {SimpleType.STRING, SimpleType.STRING}); + Map<String, ?> items = ImmutableMap.of( + "key1", "val1", + "key2", "val2"); + CompositeData data = new CompositeDataSupport(compositeType, items); + + Map<String,?> result = JmxValueFunctions.compositeDataToMap(data); + assertEquals(result, items); + + Map<?,?> result2 = JmxValueFunctions.compositeDataToMap().apply(data); + assertEquals(result2, items); + } + + @Test + public void testTabularDataToMapOfMaps() throws Exception { + CompositeType rowType = new CompositeType( + "MyRowType", + "my row descr", + new String[] {"key1", "key2"}, + new String[] {"key1 descr", "key2 descr"}, + new OpenType[] {SimpleType.STRING, SimpleType.STRING}); + TabularType tabularType = new TabularType( + "MyTabularType", + "my table descr", + rowType, + new String[] {"key1"}); + Map<String, ?> row1 = ImmutableMap.of( + "key1", "row1.val1", + "key2", "row1.val2"); + Map<String, ?> row2 = ImmutableMap.of( + "key1", "row2.val1", + "key2", "row2.val2"); + TabularDataSupport table = new TabularDataSupport(tabularType); + table.put(new CompositeDataSupport(rowType, row1)); + table.put(new CompositeDataSupport(rowType, row2)); + + Map<List<?>, Map<String, Object>> result = JmxValueFunctions.tabularDataToMapOfMaps(table); + assertEquals(result, ImmutableMap.of(ImmutableList.of("row1.val1"), row1, ImmutableList.of("row2.val1"), row2)); + + Map<?,?> result2 = JmxValueFunctions.tabularDataToMapOfMaps().apply(table); + assertEquals(result2, ImmutableMap.of(ImmutableList.of("row1.val1"), row1, ImmutableList.of("row2.val1"), row2)); + } + + @Test + public void testTabularDataToMap() throws Exception { + CompositeType rowType = new CompositeType( + "MyRowType", + "my row descr", + new String[] {"key1", "key2"}, + new String[] {"key1 descr", "key2 descr"}, + new OpenType[] {SimpleType.STRING, SimpleType.STRING}); + TabularType tabularType = new TabularType( + "MyTabularType", + "my table descr", + rowType, + new String[] {"key1"}); + Map<String, ?> row1 = ImmutableMap.of( + "key1", "row1.val1", + "key2", "row1.val2"); + Map<String, ?> row2 = ImmutableMap.of( + "key1", "row2.val1", + "key2", "row2.val2"); + TabularDataSupport table = new TabularDataSupport(tabularType); + table.put(new CompositeDataSupport(rowType, row1)); + table.put(new CompositeDataSupport(rowType, row2)); + + Map<?,?> result = JmxValueFunctions.tabularDataToMap(table); + assertEquals(result, row2); + + Map<?,?> result2 = JmxValueFunctions.tabularDataToMap().apply(table); + assertEquals(result2, row2); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java index 905135c..70769dd 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java @@ -22,7 +22,10 @@ import com.google.common.base.Function; public class MaybeFunctions { - public static <T> Function<T, Maybe<T>> wrap() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<T, Maybe<T>> wrapOld() { + // TODO PERSISTENCE WORKAROUND return new Function<T, Maybe<T>>() { @Override public Maybe<T> apply(T input) { @@ -31,7 +34,10 @@ public class MaybeFunctions { }; } - public static <T> Function<Maybe<T>, T> get() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<Maybe<T>, T> getOld() { + // TODO PERSISTENCE WORKAROUND return new Function<Maybe<T>, T>() { @Override public T apply(Maybe<T> input) { @@ -40,7 +46,10 @@ public class MaybeFunctions { }; } - public static <T> Function<Maybe<T>, T> or(final T value) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<Maybe<T>, T> orOld(final T value) { + // TODO PERSISTENCE WORKAROUND return new Function<Maybe<T>, T>() { @Override public T apply(Maybe<T> input) { @@ -49,4 +58,41 @@ public class MaybeFunctions { }; } + public static <T> Function<T, Maybe<T>> wrap() { + return new WrapMaybe<T>(); + } + + protected static class WrapMaybe<T> implements Function<T, Maybe<T>> { + @Override + public Maybe<T> apply(T input) { + return Maybe.fromNullable(input); + } + }; + + public static <T> Function<Maybe<T>, T> get() { + return new GetMaybe<T>(); + } + + protected static class GetMaybe<T> implements Function<Maybe<T>, T> { + @Override + public T apply(Maybe<T> input) { + return input.get(); + } + } + + public static <T> Function<Maybe<T>, T> or(final T value) { + return new OrMaybe<T>(value); + } + + protected static class OrMaybe<T> implements Function<Maybe<T>, T> { + private final T value; + + public OrMaybe(T value) { + this.value = value; + } + @Override + public T apply(Maybe<T> input) { + return input.or(value); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/utils/common/src/main/java/org/apache/brooklyn/util/math/MathFunctions.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/math/MathFunctions.java b/utils/common/src/main/java/org/apache/brooklyn/util/math/MathFunctions.java index 92dbe36..865aca3 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/math/MathFunctions.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/math/MathFunctions.java @@ -20,13 +20,17 @@ package org.apache.brooklyn.util.math; import javax.annotation.Nullable; +import org.apache.brooklyn.util.guava.Functionals; import org.apache.brooklyn.util.text.Strings; import com.google.common.base.Function; public class MathFunctions { - public static Function<Number, Integer> plus(final int addend) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, Integer> plusOld(final int addend) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, Integer>() { public Integer apply(@Nullable Number input) { if (input==null) return null; @@ -35,7 +39,10 @@ public class MathFunctions { }; } - public static Function<Number, Long> plus(final long addend) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, Long> plusOld(final long addend) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, Long>() { public Long apply(@Nullable Number input) { if (input==null) return null; @@ -44,7 +51,10 @@ public class MathFunctions { }; } - public static Function<Number, Double> plus(final double addend) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, Double> plusOld(final double addend) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, Double>() { public Double apply(@Nullable Number input) { if (input==null) return null; @@ -53,7 +63,10 @@ public class MathFunctions { }; } - public static Function<Number, Integer> times(final int multiplicand) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, Integer> timesOld(final int multiplicand) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, Integer>() { public Integer apply(@Nullable Number input) { if (input==null) return null; @@ -62,7 +75,10 @@ public class MathFunctions { }; } - public static Function<Number, Long> times(final long multiplicand) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, Long> timesOld(final long multiplicand) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, Long>() { public Long apply(@Nullable Number input) { if (input==null) return null; @@ -71,7 +87,10 @@ public class MathFunctions { }; } - public static Function<Number, Double> times(final double multiplicand) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, Double> timesOld(final double multiplicand) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, Double>() { public Double apply(@Nullable Number input) { if (input==null) return null; @@ -80,7 +99,10 @@ public class MathFunctions { }; } - public static Function<Number, Double> divide(final double divisor) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, Double> divideOld(final double divisor) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, Double>() { public Double apply(@Nullable Number input) { if (input==null) return null; @@ -89,7 +111,10 @@ public class MathFunctions { }; } - public static <T> Function<T, Double> divide(final Function<T, ? extends Number> input, final double divisor) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static <T> Function<T, Double> divideOld(final Function<T, ? extends Number> input, final double divisor) { + // TODO PERSISTENCE WORKAROUND return new Function<T, Double>() { public Double apply(@Nullable T input2) { if (input==null) return null; @@ -101,7 +126,10 @@ public class MathFunctions { } /** returns a string of up to maxLen length (longer in extreme cases) also capped at significantDigits significantDigits */ - public static Function<Number, String> readableString(final int significantDigits, final int maxLen) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, String> readableStringOld(final int significantDigits, final int maxLen) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, String>() { public String apply(@Nullable Number input) { if (input==null) return null; @@ -111,7 +139,10 @@ public class MathFunctions { } /** returns a string where the input number is expressed as percent, with given number of significant digits */ - public static Function<Number, String> percent(final int significantDigits) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Number, String> percentOld(final int significantDigits) { + // TODO PERSISTENCE WORKAROUND return new Function<Number, String>() { public String apply(@Nullable Number input) { if (input==null) return null; @@ -120,4 +151,157 @@ public class MathFunctions { }; } + public static Function<Number, Integer> plus(int addend) { + return new PlusInt(addend); + } + + protected static class PlusInt implements Function<Number, Integer> { + private final int addend; + + public PlusInt(int addend) { + this.addend = addend; + } + public Integer apply(@Nullable Number input) { + if (input==null) return null; + return input.intValue() + addend; + } + } + + public static Function<Number, Long> plus(long addend) { + return new PlusLong(addend); + } + + protected static class PlusLong implements Function<Number, Long> { + private final long addend; + + public PlusLong(long addend) { + this.addend = addend; + } + public Long apply(@Nullable Number input) { + if (input==null) return null; + return input.longValue() + addend; + } + } + + public static Function<Number, Double> plus(final double addend) { + return new PlusDouble(addend); + } + + protected static class PlusDouble implements Function<Number, Double> { + private final double addend; + + public PlusDouble(double addend) { + this.addend = addend; + } + public Double apply(@Nullable Number input) { + if (input==null) return null; + return input.doubleValue() + addend; + } + } + + public static Function<Number, Integer> times(final int multiplicand) { + return new TimesInt(multiplicand); + } + + protected static class TimesInt implements Function<Number, Integer> { + private final int multiplicand; + + public TimesInt(int multiplicand) { + this.multiplicand = multiplicand; + } + public Integer apply(@Nullable Number input) { + if (input==null) return null; + return input.intValue() * multiplicand; + } + } + + public static Function<Number, Long> times(long multiplicand) { + return new TimesLong(multiplicand); + } + + protected static class TimesLong implements Function<Number, Long> { + private final long multiplicand; + + public TimesLong(long multiplicand) { + this.multiplicand = multiplicand; + } + public Long apply(@Nullable Number input) { + if (input==null) return null; + return input.longValue() * multiplicand; + } + } + + public static Function<Number, Double> times(final double multiplicand) { + return new TimesDouble(multiplicand); + } + + protected static class TimesDouble implements Function<Number, Double> { + private final double multiplicand; + + public TimesDouble(double multiplicand) { + this.multiplicand = multiplicand; + } + public Double apply(@Nullable Number input) { + if (input==null) return null; + return input.doubleValue() * multiplicand; + } + } + + public static Function<Number, Double> divide(double divisor) { + return new DivideDouble(divisor); + } + + protected static class DivideDouble implements Function<Number, Double> { + private final double divisor; + + public DivideDouble(double divisor) { + this.divisor = divisor; + } + public Double apply(@Nullable Number input) { + if (input==null) return null; + return input.doubleValue() / divisor; + } + } + + /** + * @deprecated since 0.9.0; use {@link Functionals#chain(Function, Function)} and {@link MathFunctions#divide(double)} + */ + public static <T> Function<T, Double> divide(final Function<T, ? extends Number> preprocessor, final double divisor) { + return Functionals.chain(preprocessor, divide(divisor)); + } + + /** returns a string of up to maxLen length (longer in extreme cases) also capped at significantDigits significantDigits */ + public static Function<Number, String> readableString(int significantDigits, int maxLen) { + return new ReadableString(significantDigits, maxLen); + } + + protected static class ReadableString implements Function<Number, String> { + private final int significantDigits; + private final int maxLen; + public ReadableString(int significantDigits, int maxLen) { + this.significantDigits = significantDigits; + this.maxLen = maxLen; + } + public String apply(@Nullable Number input) { + if (input==null) return null; + return Strings.makeRealString(input.doubleValue(), maxLen, significantDigits, 0); + } + }; + + /** returns a string where the input number is expressed as percent, with given number of significant digits */ + public static Function<Number, String> percent(int significantDigits) { + return new Percent(significantDigits); + } + + private static class Percent implements Function<Number, String> { + final int significantDigits; + public Percent(int significantDigits) { + this.significantDigits = significantDigits; + } + + public String apply(@Nullable Number input) { + if (input==null) return null; + return readableString(significantDigits, significantDigits+3).apply(input.doubleValue() * 100d)+"%"; + } + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f22b3eb4/utils/common/src/main/java/org/apache/brooklyn/util/text/StringFunctions.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/StringFunctions.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/StringFunctions.java index 8ac249d..dd9a980 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/text/StringFunctions.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/StringFunctions.java @@ -18,7 +18,7 @@ */ package org.apache.brooklyn.util.text; -import java.util.List; +import static com.google.common.base.Preconditions.checkNotNull; import javax.annotation.Nullable; @@ -31,7 +31,10 @@ import com.google.common.collect.Iterables; public class StringFunctions { - public static Function<String,String> append(final String suffix) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String,String> appendOld(final String suffix) { + // TODO PERSISTENCE WORKAROUND return new Function<String, String>() { @Override @Nullable @@ -42,7 +45,10 @@ public class StringFunctions { }; } - public static Function<String,String> prepend(final String prefix) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String,String> prependOld(final String prefix) { + // TODO PERSISTENCE WORKAROUND return new Function<String, String>() { @Override @Nullable @@ -53,8 +59,10 @@ public class StringFunctions { }; } - /** given e.g. "hello %s" returns a function which will insert a string into that pattern */ - public static Function<Object, String> formatter(final String pattern) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Object, String> formatterOld(final String pattern) { + // TODO PERSISTENCE WORKAROUND return new Function<Object, String>() { public String apply(@Nullable Object input) { return String.format(pattern, input); @@ -62,8 +70,10 @@ public class StringFunctions { }; } - /** given e.g. "hello %s %s" returns a function which will insert an array of two strings into that pattern */ - public static Function<Object[], String> formatterForArray(final String pattern) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Object[], String> formatterForArrayOld(final String pattern) { + // TODO PERSISTENCE WORKAROUND return new Function<Object[], String>() { public String apply(@Nullable Object[] input) { return String.format(pattern, input); @@ -71,18 +81,10 @@ public class StringFunctions { }; } - /** given e.g. "hello %s %s" returns a function which will insert an Iterable of two strings into that pattern */ - public static Function<Iterable<?>, String> formatterForIterable(final String pattern) { - return new Function<Iterable<?>, String>() { - public String apply(@Nullable Iterable<?> input) { - Object[] arr = (input == null) ? null : Iterables.toArray(input, Object.class); - return String.format(pattern, arr); - } - }; - } - - /** joins the given objects in a collection as a toString with the given separator */ - public static Function<Iterable<?>, String> joiner(final String separator) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Iterable<?>, String> joinerOld(final String separator) { + // TODO PERSISTENCE WORKAROUND return new Function<Iterable<?>, String>() { public String apply(@Nullable Iterable<?> input) { return Strings.join(input, separator); @@ -90,8 +92,10 @@ public class StringFunctions { }; } - /** joins the given objects as a toString with the given separator, but expecting an array of objects, not a collection */ - public static Function<Object[], String> joinerForArray(final String separator) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<Object[], String> joinerForArrayOld(final String separator) { + // TODO PERSISTENCE WORKAROUND return new Function<Object[], String>() { public String apply(@Nullable Object[] input) { if (input == null) return Strings.EMPTY; @@ -100,13 +104,10 @@ public class StringFunctions { }; } - /** provided here as a convenience; prefer {@link Functions#toStringFunction()} */ - public static Function<Object,String> toStringFunction() { - return Functions.toStringFunction(); - } - - /** returns function which gives length of input, with -1 for nulls */ - public static Function<String,Integer> length() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String,Integer> lengthOld() { + // TODO PERSISTENCE WORKAROUND return new Function<String,Integer>() { @Override public Integer apply(@Nullable String input) { @@ -116,10 +117,10 @@ public class StringFunctions { }; } - /** Surrounds an input string with the given prefix and suffix */ - public static Function<String,String> surround(final String prefix, final String suffix) { - Preconditions.checkNotNull(prefix); - Preconditions.checkNotNull(suffix); + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String,String> surroundOld(final String prefix, final String suffix) { + // TODO PERSISTENCE WORKAROUND return new Function<String,String>() { @Override public String apply(@Nullable String input) { @@ -129,7 +130,10 @@ public class StringFunctions { }; } - public static Function<String, String> trim() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String, String> trimOld() { + // TODO PERSISTENCE WORKAROUND return new Function<String, String>() { @Override public String apply(@Nullable String input) { @@ -140,7 +144,10 @@ public class StringFunctions { }; } - public static Function<String, String> toLowerCase() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String, String> toLowerCaseOld() { + // TODO PERSISTENCE WORKAROUND return new Function<String, String>() { @Override public String apply(String input) { @@ -149,7 +156,10 @@ public class StringFunctions { }; } - public static Function<String, String> toUpperCase() { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String, String> toUpperCaseOld() { + // TODO PERSISTENCE WORKAROUND return new Function<String, String>() { @Override public String apply(String input) { @@ -158,7 +168,10 @@ public class StringFunctions { }; } - public static Function<String, String> convertCase(final CaseFormat src, final CaseFormat target) { + /** @deprecated since 0.9.0 kept only to allow conversion of anonymous inner classes */ + @SuppressWarnings("unused") @Deprecated + private static Function<String, String> convertCaseOld(final CaseFormat src, final CaseFormat target) { + // TODO PERSISTENCE WORKAROUND return new Function<String, String>() { @Override public String apply(String input) { @@ -166,4 +179,220 @@ public class StringFunctions { } }; } + + public static Function<String,String> append(final String suffix) { + return new AppendFunction(checkNotNull(suffix, "suffix")); + } + + private static class AppendFunction implements Function<String, String> { + private final String suffix; + + public AppendFunction(String suffix) { + this.suffix = suffix; + } + @Override + @Nullable + public String apply(@Nullable String input) { + if (input==null) return null; + return input + suffix; + } + }; + + public static Function<String,String> prepend(final String prefix) { + return new PrependFunction(checkNotNull(prefix, "prefix")); + } + + protected static class PrependFunction implements Function<String, String> { + private final String prefix; + + public PrependFunction(String prefix) { + this.prefix = prefix; + } + + @Override + @Nullable + public String apply(@Nullable String input) { + if (input==null) return null; + return prefix + input; + } + } + + /** given e.g. "hello %s" returns a function which will insert a string into that pattern */ + public static Function<Object, String> formatter(final String pattern) { + return new FormatterFunction(pattern); + } + + protected static class FormatterFunction implements Function<Object, String> { + private final String pattern; + + FormatterFunction(String pattern) { + this.pattern = pattern; + } + public String apply(@Nullable Object input) { + return String.format(pattern, input); + } + }; + + /** given e.g. "hello %s %s" returns a function which will insert an array of two strings into that pattern */ + public static Function<Object[], String> formatterForArray(final String pattern) { + return new FormatterForArrayFunction(checkNotNull(pattern, "pattern")); + } + + protected static class FormatterForArrayFunction implements Function<Object[], String> { + private final String pattern; + + public FormatterForArrayFunction(String pattern) { + this.pattern = pattern; + } + public String apply(@Nullable Object[] input) { + return String.format(pattern, input); + } + } + + /** + * Given e.g. "hello %s %s" returns a function which will insert an Iterable of two strings into that pattern + * + * @since 0.9.0 + */ + public static Function<Iterable<?>, String> formatterForIterable(final String pattern) { + return new FormatterForIterableFunction(pattern); + } + + protected static class FormatterForIterableFunction implements Function<Iterable<?>, String> { + final String pattern; + + public FormatterForIterableFunction(String pattern) { + this.pattern = pattern; + } + + public String apply(@Nullable Iterable<?> input) { + Object[] arr = (input == null) ? null : Iterables.toArray(input, Object.class); + return String.format(pattern, arr); + } + } + + /** joins the given objects in a collection as a toString with the given separator */ + public static Function<Iterable<?>, String> joiner(final String separator) { + return new JoinerFunction(separator); + } + + private static class JoinerFunction implements Function<Iterable<?>, String> { + private final String separator; + + public JoinerFunction(String separator) { + this.separator = separator; + } + public String apply(@Nullable Iterable<?> input) { + return Strings.join(input, separator); + } + } + + /** joins the given objects as a toString with the given separator, but expecting an array of objects, not a collection */ + public static Function<Object[], String> joinerForArray(final String separator) { + return new JoinerForArrayFunction(checkNotNull(separator, "separator")); + } + + private static class JoinerForArrayFunction implements Function<Object[], String> { + private final String separator; + + protected JoinerForArrayFunction(String separator) { + this.separator = separator; + } + public String apply(@Nullable Object[] input) { + if (input == null) return Strings.EMPTY; + return Strings.join(input, separator); + } + } + + /** provided here as a convenience; prefer {@link Functions#toStringFunction()} */ + public static Function<Object,String> toStringFunction() { + return Functions.toStringFunction(); + } + + /** returns function which gives length of input, with -1 for nulls */ + public static Function<String,Integer> length() { + return new LengthFunction(); + } + + protected static class LengthFunction implements Function<String,Integer> { + @Override + public Integer apply(@Nullable String input) { + if (input == null) return -1; + return input.length(); + } + } + + /** Surrounds an input string with the given prefix and suffix */ + public static Function<String,String> surround(final String prefix, final String suffix) { + Preconditions.checkNotNull(prefix); + Preconditions.checkNotNull(suffix); + return new SurroundFunction(prefix, suffix); + } + + protected static class SurroundFunction implements Function<String,String> { + private final String prefix; + private final String suffix; + public SurroundFunction(String prefix, String suffix) { + this.prefix = prefix; + this.suffix = suffix; + } + @Override + public String apply(@Nullable String input) { + if (input == null) return null; + return prefix+input+suffix; + } + } + + public static Function<String, String> trim() { + return new TrimFunction(); + } + + protected static class TrimFunction implements Function<String, String> { + @Override + public String apply(@Nullable String input) { + if (input == null) return null; + if (Strings.isBlank(input)) return Strings.EMPTY; + return CharMatcher.BREAKING_WHITESPACE.trimFrom(input); + } + } + + public static Function<String, String> toLowerCase() { + return new LowerCaseFunction(); + } + + protected static class LowerCaseFunction implements Function<String, String> { + @Override + public String apply(String input) { + return input.toLowerCase(); + } + } + + public static Function<String, String> toUpperCase() { + return new UpperCaseFunction(); + } + + protected static class UpperCaseFunction implements Function<String, String> { + @Override + public String apply(String input) { + return input.toUpperCase(); + } + } + + public static Function<String, String> convertCase(final CaseFormat src, final CaseFormat target) { + return new ConvertCaseFunction(checkNotNull(src, "src"), checkNotNull(target, "target")); + } + + protected static class ConvertCaseFunction implements Function<String, String> { + private final CaseFormat src; + private final CaseFormat target; + + public ConvertCaseFunction(CaseFormat src, CaseFormat target) { + this.src = src; + this.target = target; + } + @Override + public String apply(String input) { + return src.to(target, input); + } + } }
