Return-Path: X-Original-To: apmail-brooklyn-commits-archive@minotaur.apache.org Delivered-To: apmail-brooklyn-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 2C8B118747 for ; Tue, 18 Aug 2015 11:01:14 +0000 (UTC) Received: (qmail 74552 invoked by uid 500); 18 Aug 2015 11:01:14 -0000 Delivered-To: apmail-brooklyn-commits-archive@brooklyn.apache.org Received: (qmail 74529 invoked by uid 500); 18 Aug 2015 11:01:14 -0000 Mailing-List: contact commits-help@brooklyn.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.incubator.apache.org Delivered-To: mailing list commits@brooklyn.incubator.apache.org Received: (qmail 74520 invoked by uid 99); 18 Aug 2015 11:01:14 -0000 Received: from Unknown (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Aug 2015 11:01:14 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id 560C41AA661 for ; Tue, 18 Aug 2015 11:01:13 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 1.775 X-Spam-Level: * X-Spam-Status: No, score=1.775 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.006, URIBL_BLOCKED=0.001] autolearn=disabled Received: from mx1-eu-west.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id m6L6u8NOZYzS for ; Tue, 18 Aug 2015 11:00:56 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-eu-west.apache.org (ASF Mail Server at mx1-eu-west.apache.org) with SMTP id 0CA9C2AD08 for ; Tue, 18 Aug 2015 11:00:21 +0000 (UTC) Received: (qmail 68836 invoked by uid 99); 18 Aug 2015 11:00:17 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Aug 2015 11:00:17 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 103A4DFF6A; Tue, 18 Aug 2015 11:00:17 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: heneveld@apache.org To: commits@brooklyn.incubator.apache.org Date: Tue, 18 Aug 2015 11:00:50 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [35/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/flags/TypeCoercions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java deleted file mode 100644 index 31f27be..0000000 --- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java +++ /dev/null @@ -1,879 +0,0 @@ -/* - * 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 brooklyn.util.flags; - -import groovy.lang.Closure; -import groovy.time.TimeDuration; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.URI; -import java.net.URL; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.event.AttributeSensor; -import org.apache.brooklyn.api.event.Sensor; -import org.apache.brooklyn.core.internal.BrooklynInitialization; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.entity.basic.BrooklynTaskTags; -import brooklyn.entity.basic.ClosureEntityFactory; -import brooklyn.entity.basic.ConfigurableEntityFactory; -import brooklyn.entity.basic.ConfigurableEntityFactoryFromEntityFactory; -import brooklyn.event.basic.Sensors; -import brooklyn.util.JavaGroovyEquivalents; -import brooklyn.util.collections.MutableSet; -import brooklyn.util.collections.QuorumCheck; -import brooklyn.util.collections.QuorumCheck.QuorumChecks; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.guava.Maybe; -import brooklyn.util.javalang.Enums; -import brooklyn.util.net.Cidr; -import brooklyn.util.net.Networking; -import brooklyn.util.net.UserAndHostAndPort; -import brooklyn.util.task.Tasks; -import brooklyn.util.text.StringEscapes.JavaStringEscapes; -import brooklyn.util.text.Strings; -import brooklyn.util.time.Duration; -import brooklyn.util.time.Time; -import brooklyn.util.yaml.Yamls; - -import com.google.common.base.CaseFormat; -import com.google.common.base.Function; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.collect.Table; -import com.google.common.net.HostAndPort; -import com.google.common.primitives.Primitives; -import com.google.common.reflect.TypeToken; - -@SuppressWarnings("rawtypes") -public class TypeCoercions { - - private static final Logger log = LoggerFactory.getLogger(TypeCoercions.class); - - private TypeCoercions() {} - - /** Store the coercion {@link Function functions} in a {@link Table table}. */ - @GuardedBy("TypeCoercions.class") - private static Table registry = HashBasedTable.create(); - - /** - * Attempts to coerce {@code value} to {@code targetType}. - *

- * Maintains a registry of adapter functions for type pairs in a {@link Table} which - * is searched after checking various strategies, including the following: - *

    - *
  • {@code value.asTargetType()} - *
  • {@code TargetType.fromType(value)} (if {@code value instanceof Type}) - *
  • {@code value.targetTypeValue()} (handy for primitives) - *
  • {@code TargetType.valueOf(value)} (for enums) - *
- *

- * A default set of adapters will handle most common Java-type coercions - * as well as String coercion to: - *

    - *
  • {@link Set}, {@link List}, {@link Map} and similar -- parses as YAML - *
  • {@link Date} -- parses using {@link Time#parseDate(String)} - *
  • {@link Duration} -- parses using {@link Duration#parse(String)} - *
- */ - public static T coerce(Object value, Class targetType) { - return coerce(value, TypeToken.of(targetType)); - } - - /** @see #coerce(Object, Class) */ - public static Maybe tryCoerce(Object value, TypeToken targetTypeToken) { - try { - return Maybe.of( coerce(value, targetTypeToken) ); - } catch (Throwable t) { - Exceptions.propagateIfFatal(t); - return Maybe.absent(t); - } - } - - /** @see #coerce(Object, Class) */ - @SuppressWarnings({ "unchecked" }) - public static T coerce(Object value, TypeToken targetTypeToken) { - if (value==null) return null; - Class targetType = targetTypeToken.getRawType(); - - //recursive coercion of parameterized collections and map entries - if (targetTypeToken.getType() instanceof ParameterizedType) { - if (value instanceof Collection && Collection.class.isAssignableFrom(targetType)) { - Type[] arguments = ((ParameterizedType) targetTypeToken.getType()).getActualTypeArguments(); - if (arguments.length != 1) { - throw new IllegalStateException("Unexpected number of parameters in collection type: " + arguments); - } - Collection coerced = Lists.newLinkedList(); - TypeToken listEntryType = TypeToken.of(arguments[0]); - for (Object entry : (Iterable) value) { - coerced.add(coerce(entry, listEntryType)); - } - if (Set.class.isAssignableFrom(targetType)) { - return (T) Sets.newLinkedHashSet(coerced); - } else { - return (T) Lists.newArrayList(coerced); - } - } else if (value instanceof Map && Map.class.isAssignableFrom(targetType)) { - Type[] arguments = ((ParameterizedType) targetTypeToken.getType()).getActualTypeArguments(); - if (arguments.length != 2) { - throw new IllegalStateException("Unexpected number of parameters in map type: " + arguments); - } - Map coerced = Maps.newLinkedHashMap(); - TypeToken mapKeyType = TypeToken.of(arguments[0]); - TypeToken mapValueType = TypeToken.of(arguments[1]); - for (Map.Entry entry : ((Map) value).entrySet()) { - coerced.put(coerce(entry.getKey(), mapKeyType), coerce(entry.getValue(), mapValueType)); - } - return (T) Maps.newLinkedHashMap(coerced); - } - } - - if (targetType.isInstance(value)) return (T) value; - - // TODO use registry first? - - //deal with primitive->primitive casting - if (isPrimitiveOrBoxer(targetType) && isPrimitiveOrBoxer(value.getClass())) { - // Don't just rely on Java to do its normal casting later; if caller writes - // long `l = coerce(new Integer(1), Long.class)` then letting java do its casting will fail, - // because an Integer will not automatically be unboxed and cast to a long - return castPrimitive(value, (Class)targetType); - } - - //deal with string->primitive - if (value instanceof String && isPrimitiveOrBoxer(targetType)) { - return stringToPrimitive((String)value, (Class)targetType); - } - - //deal with primitive->string - if (isPrimitiveOrBoxer(value.getClass()) && targetType.equals(String.class)) { - return (T) value.toString(); - } - - //look for value.asType where Type is castable to targetType - String targetTypeSimpleName = getVerySimpleName(targetType); - if (targetTypeSimpleName!=null && targetTypeSimpleName.length()>0) { - for (Method m: value.getClass().getMethods()) { - if (m.getName().startsWith("as") && m.getParameterTypes().length==0 && - targetType.isAssignableFrom(m.getReturnType()) ) { - if (m.getName().equals("as"+getVerySimpleName(m.getReturnType()))) { - try { - return (T) m.invoke(value); - } catch (Exception e) { - throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): "+m.getName()+" adapting failed, "+e); - } - } - } - } - } - - //now look for static TargetType.fromType(Type t) where value instanceof Type - for (Method m: targetType.getMethods()) { - if (((m.getModifiers()&Modifier.STATIC)==Modifier.STATIC) && - m.getName().startsWith("from") && m.getParameterTypes().length==1 && - m.getParameterTypes()[0].isInstance(value)) { - if (m.getName().equals("from"+getVerySimpleName(m.getParameterTypes()[0]))) { - try { - return (T) m.invoke(null, value); - } catch (Exception e) { - throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): "+m.getName()+" adapting failed, "+e); - } - } - } - } - - //ENHANCEMENT could look in type hierarchy of both types for a conversion method... - - //primitives get run through again boxed up - Class boxedT = UNBOXED_TO_BOXED_TYPES.get(targetType); - Class boxedVT = UNBOXED_TO_BOXED_TYPES.get(value.getClass()); - if (boxedT!=null || boxedVT!=null) { - try { - if (boxedT==null) boxedT=targetType; - Object boxedV; - if (boxedVT==null) { boxedV = value; } - else { boxedV = boxedVT.getConstructor(value.getClass()).newInstance(value); } - return (T) coerce(boxedV, boxedT); - } catch (Exception e) { - throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): unboxing failed, "+e); - } - } - - //for enums call valueOf with the string representation of the value - if (targetType.isEnum()) { - T result = (T) stringToEnum((Class) targetType, null).apply(String.valueOf(value)); - if (result != null) return result; - } - - //now look in registry - synchronized (TypeCoercions.class) { - Map adapters = registry.row(targetType); - for (Map.Entry entry : adapters.entrySet()) { - if (entry.getKey().isInstance(value)) { - T result = (T) entry.getValue().apply(value); - - // Check if need to unwrap again (e.g. if want List and are given a String "1,2,3" - // then we'll have so far converted to List.of("1", "2", "3"). Call recursively. - // First check that value has changed, to avoid stack overflow! - if (!Objects.equal(value, result) && targetTypeToken.getType() instanceof ParameterizedType) { - // Could duplicate check for `result instanceof Collection` etc; but recursive call - // will be fine as if that doesn't match we'll safely reach `targetType.isInstance(value)` - // and just return the result. - return coerce(result, targetTypeToken); - } - return result; - } - } - } - - //not found - throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): no adapter known"); - } - - /** - * Returns a function that does a type coercion to the given type. For example, - * {@code TypeCoercions.function(Double.class)} will return a function that will - * coerce its input value to a {@link Double} (or throw a {@link ClassCoercionException} - * if that is not possible). - */ - public static Function function(final Class type) { - return new CoerceFunction(type); - } - - private static class CoerceFunction implements Function { - private final Class type; - - public CoerceFunction(Class type) { - this.type = type; - } - @Override - public T apply(Object input) { - return coerce(input, type); - } - } - - /** - * Type coercion {@link Function function} for {@link Enum enums}. - *

- * Tries to convert the string to {@link CaseFormat#UPPER_UNDERSCORE} first, - * handling all of the different {@link CaseFormat format} possibilites. Failing - * that, it tries a case-insensitive comparison with the valid enum values. - *

- * Returns {@code defaultValue} if the string cannot be converted. - * - * @see TypeCoercions#coerce(Object, Class) - * @see Enum#valueOf(Class, String) - */ - public static > Function stringToEnum(final Class type, @Nullable final E defaultValue) { - return new StringToEnumFunction(type, defaultValue); - } - - private static class StringToEnumFunction> implements Function { - private final Class type; - private final E defaultValue; - - public StringToEnumFunction(Class type, @Nullable E defaultValue) { - this.type = type; - this.defaultValue = defaultValue; - } - @Override - public E apply(String input) { - Preconditions.checkNotNull(input, "input"); - List options = ImmutableList.of( - input, - CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, input), - CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, input), - CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, input), - CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, input)); - for (String value : options) { - try { - return Enum.valueOf(type, value); - } catch (IllegalArgumentException iae) { - continue; - } - } - Maybe result = Enums.valueOfIgnoreCase(type, input); - return (result.isPresent()) ? result.get() : defaultValue; - } - } - - /** - * Sometimes need to explicitly cast primitives, rather than relying on Java casting. - * For example, when using generics then type-erasure means it doesn't actually cast, - * which causes tests to fail with 0 != 0.0 - */ - @SuppressWarnings("unchecked") - public static T castPrimitive(Object value, Class targetType) { - if (value==null) return null; - assert isPrimitiveOrBoxer(targetType) : "targetType="+targetType; - assert isPrimitiveOrBoxer(value.getClass()) : "value="+targetType+"; valueType="+value.getClass(); - - Class sourceWrapType = Primitives.wrap(value.getClass()); - Class targetWrapType = Primitives.wrap(targetType); - - // optimization, for when already correct type - if (sourceWrapType == targetWrapType) { - return (T) value; - } - - if (targetWrapType == Boolean.class) { - // only char can be mapped to boolean - // (we could say 0=false, nonzero=true, but there is no compelling use case so better - // to encourage users to write as boolean) - if (sourceWrapType == Character.class) - return (T) stringToPrimitive(value.toString(), targetType); - - throw new ClassCoercionException("Cannot cast "+sourceWrapType+" ("+value+") to "+targetType); - } else if (sourceWrapType == Boolean.class) { - // boolean can't cast to anything else - - throw new ClassCoercionException("Cannot cast "+sourceWrapType+" ("+value+") to "+targetType); - } - - // for whole-numbers (where casting to long won't lose anything)... - long v = 0; - boolean islong = true; - if (sourceWrapType == Character.class) { - v = (long) ((Character)value).charValue(); - } else if (sourceWrapType == Byte.class) { - v = (long) ((Byte)value).byteValue(); - } else if (sourceWrapType == Short.class) { - v = (long) ((Short)value).shortValue(); - } else if (sourceWrapType == Integer.class) { - v = (long) ((Integer)value).intValue(); - } else if (sourceWrapType == Long.class) { - v = ((Long)value).longValue(); - } else { - islong = false; - } - if (islong) { - if (targetWrapType == Character.class) return (T) Character.valueOf((char)v); - if (targetWrapType == Byte.class) return (T) Byte.valueOf((byte)v); - if (targetWrapType == Short.class) return (T) Short.valueOf((short)v); - if (targetWrapType == Integer.class) return (T) Integer.valueOf((int)v); - if (targetWrapType == Long.class) return (T) Long.valueOf((long)v); - if (targetWrapType == Float.class) return (T) Float.valueOf((float)v); - if (targetWrapType == Double.class) return (T) Double.valueOf((double)v); - throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType); - } - - // for real-numbers (cast to double)... - double d = 0; - boolean isdouble = true; - if (sourceWrapType == Float.class) { - d = (double) ((Float)value).floatValue(); - } else if (sourceWrapType == Double.class) { - d = (double) ((Double)value).doubleValue(); - } else { - isdouble = false; - } - if (isdouble) { - if (targetWrapType == Character.class) return (T) Character.valueOf((char)d); - if (targetWrapType == Byte.class) return (T) Byte.valueOf((byte)d); - if (targetWrapType == Short.class) return (T) Short.valueOf((short)d); - if (targetWrapType == Integer.class) return (T) Integer.valueOf((int)d); - if (targetWrapType == Long.class) return (T) Long.valueOf((long)d); - if (targetWrapType == Float.class) return (T) Float.valueOf((float)d); - if (targetWrapType == Double.class) return (T) Double.valueOf((double)d); - throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType); - } else { - throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType); - } - } - - public static boolean isPrimitiveOrBoxer(Class type) { - return Primitives.allPrimitiveTypes().contains(type) || Primitives.allWrapperTypes().contains(type); - } - - @SuppressWarnings("unchecked") - public static T stringToPrimitive(String value, Class targetType) { - assert Primitives.allPrimitiveTypes().contains(targetType) || Primitives.allWrapperTypes().contains(targetType) : "targetType="+targetType; - // If char, then need to do explicit conversion - if (targetType == Character.class || targetType == char.class) { - if (value.length() == 1) { - return (T) (Character) value.charAt(0); - } else if (value.length() != 1) { - throw new ClassCoercionException("Cannot coerce type String to "+targetType.getCanonicalName()+" ("+value+"): adapting failed"); - } - } - value = value.trim(); - // For boolean we could use valueOf, but that returns false whereas we'd rather throw errors on bad values - if (targetType == Boolean.class || targetType == boolean.class) { - if ("true".equalsIgnoreCase(value)) return (T) Boolean.TRUE; - if ("false".equalsIgnoreCase(value)) return (T) Boolean.FALSE; - if ("yes".equalsIgnoreCase(value)) return (T) Boolean.TRUE; - if ("no".equalsIgnoreCase(value)) return (T) Boolean.FALSE; - if ("t".equalsIgnoreCase(value)) return (T) Boolean.TRUE; - if ("f".equalsIgnoreCase(value)) return (T) Boolean.FALSE; - if ("y".equalsIgnoreCase(value)) return (T) Boolean.TRUE; - if ("n".equalsIgnoreCase(value)) return (T) Boolean.FALSE; - - throw new ClassCoercionException("Cannot coerce type String to "+targetType.getCanonicalName()+" ("+value+"): adapting failed"); - } - - // Otherwise can use valueOf reflectively - Class wrappedType; - if (Primitives.allPrimitiveTypes().contains(targetType)) { - wrappedType = Primitives.wrap(targetType); - } else { - wrappedType = targetType; - } - - try { - return (T) wrappedType.getMethod("valueOf", String.class).invoke(null, value); - } catch (Exception e) { - ClassCoercionException tothrow = new ClassCoercionException("Cannot coerce "+JavaStringEscapes.wrapJavaString(value)+" to "+targetType.getCanonicalName()+" ("+value+"): adapting failed"); - tothrow.initCause(e); - throw tothrow; - } - } - - /** returns the simple class name, and for any inner class the portion after the $ */ - public static String getVerySimpleName(Class c) { - String s = c.getSimpleName(); - if (s.indexOf('$')>=0) - s = s.substring(s.lastIndexOf('$')+1); - return s; - } - public static final Map BOXED_TO_UNBOXED_TYPES = ImmutableMap.builder(). - put(Integer.class, Integer.TYPE). - put(Long.class, Long.TYPE). - put(Boolean.class, Boolean.TYPE). - put(Byte.class, Byte.TYPE). - put(Double.class, Double.TYPE). - put(Float.class, Float.TYPE). - put(Character.class, Character.TYPE). - put(Short.class, Short.TYPE). - build(); - public static final Map UNBOXED_TO_BOXED_TYPES = ImmutableMap.builder(). - put(Integer.TYPE, Integer.class). - put(Long.TYPE, Long.class). - put(Boolean.TYPE, Boolean.class). - put(Byte.TYPE, Byte.class). - put(Double.TYPE, Double.class). - put(Float.TYPE, Float.class). - put(Character.TYPE, Character.class). - put(Short.TYPE, Short.class). - build(); - - /** for automatic conversion */ - public static Object getMatchingConstructor(Class target, Object ...arguments) { - Constructor[] cc = target.getConstructors(); - for (Constructor c: cc) { - if (c.getParameterTypes().length != arguments.length) - continue; - boolean matches = true; - Class[] tt = c.getParameterTypes(); - for (int i=0; i Function registerAdapter(Class sourceType, Class targetType, Function fn) { - return registry.put(targetType, sourceType, fn); - } - - static { BrooklynInitialization.initTypeCoercionStandardAdapters(); } - - public static void initStandardAdapters() { - registerAdapter(CharSequence.class, String.class, new Function() { - @Override - public String apply(CharSequence input) { - return input.toString(); - } - }); - registerAdapter(byte[].class, String.class, new Function() { - @Override - public String apply(byte[] input) { - return new String(input); - } - }); - registerAdapter(Collection.class, Set.class, new Function() { - @SuppressWarnings("unchecked") - @Override - public Set apply(Collection input) { - return Sets.newLinkedHashSet(input); - } - }); - registerAdapter(Collection.class, List.class, new Function() { - @SuppressWarnings("unchecked") - @Override - public List apply(Collection input) { - return Lists.newArrayList(input); - } - }); - registerAdapter(String.class, InetAddress.class, new Function() { - @Override - public InetAddress apply(String input) { - return Networking.getInetAddressWithFixedName(input); - } - }); - registerAdapter(String.class, HostAndPort.class, new Function() { - @Override - public HostAndPort apply(String input) { - return HostAndPort.fromString(input); - } - }); - registerAdapter(String.class, UserAndHostAndPort.class, new Function() { - @Override - public UserAndHostAndPort apply(String input) { - return UserAndHostAndPort.fromString(input); - } - }); - registerAdapter(String.class, Cidr.class, new Function() { - @Override - public Cidr apply(String input) { - return new Cidr(input); - } - }); - registerAdapter(String.class, URL.class, new Function() { - @Override - public URL apply(String input) { - try { - return new URL(input); - } catch (Exception e) { - throw Exceptions.propagate(e); - } - } - }); - registerAdapter(String.class, URI.class, new Function() { - @Override - public URI apply(String input) { - return URI.create(input); - } - }); - registerAdapter(Closure.class, ConfigurableEntityFactory.class, new Function() { - @SuppressWarnings("unchecked") - @Override - public ConfigurableEntityFactory apply(Closure input) { - return new ClosureEntityFactory(input); - } - }); - @SuppressWarnings({"unused", "deprecation"}) - Function ignoredVarHereToAllowSuppressDeprecationWarning1 = registerAdapter(brooklyn.entity.basic.EntityFactory.class, ConfigurableEntityFactory.class, new Function() { - @SuppressWarnings("unchecked") - @Override - public ConfigurableEntityFactory apply(brooklyn.entity.basic.EntityFactory input) { - if (input instanceof ConfigurableEntityFactory) return (ConfigurableEntityFactory)input; - return new ConfigurableEntityFactoryFromEntityFactory(input); - } - }); - @SuppressWarnings({"unused", "deprecation"}) - Function ignoredVarHereToAllowSuppressDeprecationWarning2 = registerAdapter(Closure.class, brooklyn.entity.basic.EntityFactory.class, new Function() { - @SuppressWarnings("unchecked") - @Override - public brooklyn.entity.basic.EntityFactory apply(Closure input) { - return new ClosureEntityFactory(input); - } - }); - registerAdapter(Closure.class, Predicate.class, new Function() { - @Override - public Predicate apply(final Closure closure) { - return new Predicate() { - @Override public boolean apply(Object input) { - return (Boolean) closure.call(input); - } - }; - } - }); - registerAdapter(Closure.class, Function.class, new Function() { - @Override - public Function apply(final Closure closure) { - return new Function() { - @Override public Object apply(Object input) { - return closure.call(input); - } - }; - } - }); - registerAdapter(Object.class, Duration.class, new Function() { - @Override - public Duration apply(final Object input) { - return brooklyn.util.time.Duration.of(input); - } - }); - registerAdapter(Object.class, TimeDuration.class, new Function() { - @SuppressWarnings("deprecation") - @Override - public TimeDuration apply(final Object input) { - log.warn("deprecated automatic coercion of Object to TimeDuration (set breakpoint in TypeCoercions to inspect, convert to Duration)"); - return JavaGroovyEquivalents.toTimeDuration(input); - } - }); - registerAdapter(TimeDuration.class, Long.class, new Function() { - @Override - public Long apply(final TimeDuration input) { - log.warn("deprecated automatic coercion of TimeDuration to Long (set breakpoint in TypeCoercions to inspect, use Duration instead of Long!)"); - return input.toMilliseconds(); - } - }); - registerAdapter(Integer.class, AtomicLong.class, new Function() { - @Override public AtomicLong apply(final Integer input) { - return new AtomicLong(input); - } - }); - registerAdapter(Long.class, AtomicLong.class, new Function() { - @Override public AtomicLong apply(final Long input) { - return new AtomicLong(input); - } - }); - registerAdapter(String.class, AtomicLong.class, new Function() { - @Override public AtomicLong apply(final String input) { - return new AtomicLong(Long.parseLong(input.trim())); - } - }); - registerAdapter(Integer.class, AtomicInteger.class, new Function() { - @Override public AtomicInteger apply(final Integer input) { - return new AtomicInteger(input); - } - }); - registerAdapter(String.class, AtomicInteger.class, new Function() { - @Override public AtomicInteger apply(final String input) { - return new AtomicInteger(Integer.parseInt(input.trim())); - } - }); - /** This always returns a {@link Double}, cast as a {@link Number}; - * however primitives and boxers get exact typing due to call in #stringToPrimitive */ - registerAdapter(String.class, Number.class, new Function() { - @Override - public Number apply(String input) { - return Double.valueOf(input); - } - }); - registerAdapter(BigDecimal.class, Double.class, new Function() { - @Override - public Double apply(BigDecimal input) { - return input.doubleValue(); - } - }); - registerAdapter(BigInteger.class, Long.class, new Function() { - @Override - public Long apply(BigInteger input) { - return input.longValue(); - } - }); - registerAdapter(BigInteger.class, Integer.class, new Function() { - @Override - public Integer apply(BigInteger input) { - return input.intValue(); - } - }); - registerAdapter(String.class, BigDecimal.class, new Function() { - @Override - public BigDecimal apply(String input) { - return new BigDecimal(input); - } - }); - registerAdapter(Double.class, BigDecimal.class, new Function() { - @Override - public BigDecimal apply(Double input) { - return BigDecimal.valueOf(input); - } - }); - registerAdapter(String.class, BigInteger.class, new Function() { - @Override - public BigInteger apply(String input) { - return new BigInteger(input); - } - }); - registerAdapter(Long.class, BigInteger.class, new Function() { - @Override - public BigInteger apply(Long input) { - return BigInteger.valueOf(input); - } - }); - registerAdapter(Integer.class, BigInteger.class, new Function() { - @Override - public BigInteger apply(Integer input) { - return BigInteger.valueOf(input); - } - }); - registerAdapter(String.class, Date.class, new Function() { - @Override - public Date apply(final String input) { - return Time.parseDate(input); - } - }); - registerAdapter(String.class, Class.class, new Function() { - @Override - public Class apply(final String input) { - try { - return Class.forName(input); - } catch (ClassNotFoundException e) { - throw Exceptions.propagate(e); - } - } - }); - registerAdapter(String.class, AttributeSensor.class, new Function() { - @Override - public AttributeSensor apply(final String input) { - Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current()); - if (entity!=null) { - Sensor result = entity.getEntityType().getSensor(input); - if (result instanceof AttributeSensor) - return (AttributeSensor) result; - } - return Sensors.newSensor(Object.class, input); - } - }); - registerAdapter(String.class, Sensor.class, new Function() { - @Override - public AttributeSensor apply(final String input) { - Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current()); - if (entity!=null) { - Sensor result = entity.getEntityType().getSensor(input); - if (result != null) - return (AttributeSensor) result; - } - return Sensors.newSensor(Object.class, input); - } - }); - registerAdapter(String.class, List.class, new Function() { - @Override - public List apply(final String input) { - return JavaStringEscapes.unwrapJsonishListIfPossible(input); - } - }); - registerAdapter(String.class, Set.class, new Function() { - @Override - public Set apply(final String input) { - return MutableSet.copyOf(JavaStringEscapes.unwrapJsonishListIfPossible(input)).asUnmodifiable(); - } - }); - registerAdapter(String.class, QuorumCheck.class, new Function() { - @Override - public QuorumCheck apply(final String input) { - return QuorumChecks.of(input); - } - }); - registerAdapter(Iterable.class, String[].class, new Function() { - @Nullable - @Override - public String[] apply(@Nullable Iterable list) { - if (list == null) return null; - String[] result = new String[Iterables.size(list)]; - int count = 0; - for (Object element : list) { - result[count++] = coerce(element, String.class); - } - return result; - } - }); - registerAdapter(Iterable.class, Integer[].class, new Function() { - @Nullable - @Override - public Integer[] apply(@Nullable Iterable list) { - if (list == null) return null; - Integer[] result = new Integer[Iterables.size(list)]; - int count = 0; - for (Object element : list) { - result[count++] = coerce(element, Integer.class); - } - return result; - } - }); - registerAdapter(Iterable.class, int[].class, new Function() { - @Nullable - @Override - public int[] apply(@Nullable Iterable list) { - if (list == null) return null; - int[] result = new int[Iterables.size(list)]; - int count = 0; - for (Object element : list) { - result[count++] = coerce(element, int.class); - } - return result; - } - }); - registerAdapter(String.class, Map.class, new Function() { - @Override - public Map apply(final String input) { - Exception error = null; - - // first try wrapping in braces if needed - if (!input.trim().startsWith("{")) { - try { - return apply("{ "+input+" }"); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - // prefer this error - error = e; - // fall back to parsing without braces, e.g. if it's multiline - } - } - - try { - return Yamls.getAs( Yamls.parseAll(input), Map.class ); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - if (error!=null && input.indexOf('\n')==-1) { - // prefer the original error if it wasn't braced and wasn't multiline - e = error; - } - throw new IllegalArgumentException("Cannot parse string as map with flexible YAML parsing; "+ - (e instanceof ClassCastException ? "yaml treats it as a string" : - (e instanceof IllegalArgumentException && Strings.isNonEmpty(e.getMessage())) ? e.getMessage() : - ""+e) ); - } - - // NB: previously we supported this also, when we did json above; - // yaml support is better as it supports quotes (and better than json because it allows dropping quotes) - // snake-yaml, our parser, also accepts key=value -- although i'm not sure this is strictly yaml compliant; - // our tests will catch it if snake behaviour changes, and we can reinstate this - // (but note it doesn't do quotes; see http://code.google.com/p/guava-libraries/issues/detail?id=412 for that): -// return ImmutableMap.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().withKeyValueSeparator("=").split(input)); - } - }); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/http/HttpTool.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/http/HttpTool.java b/core/src/main/java/brooklyn/util/http/HttpTool.java deleted file mode 100644 index a812cfc..0000000 --- a/core/src/main/java/brooklyn/util/http/HttpTool.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * 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 brooklyn.util.http; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import java.net.URI; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.codec.binary.Base64; -import org.apache.http.ConnectionReuseStrategy; -import org.apache.http.HttpEntity; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeSocketFactory; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import org.apache.http.conn.ssl.TrustStrategy; -import org.apache.http.conn.ssl.X509HostnameVerifier; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.client.LaxRedirectStrategy; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.util.EntityUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.util.crypto.SslTrustUtils; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.net.URLParamEncoder; -import brooklyn.util.text.Strings; -import brooklyn.util.time.Duration; - -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.base.Optional; -import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; - -public class HttpTool { - - private static final Logger LOG = LoggerFactory.getLogger(HttpTool.class); - - /** Apache HTTP commons utility for trusting all. - *

- * For generic java HTTP usage, see {@link SslTrustUtils#trustAll(java.net.URLConnection)} - * and static constants in the same class. */ - public static class TrustAllStrategy implements TrustStrategy { - @Override - public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { - return true; - } - } - - public static HttpClientBuilder httpClientBuilder() { - return new HttpClientBuilder(); - } - - public static class HttpClientBuilder { - private ClientConnectionManager clientConnectionManager; - private HttpParams httpParams; - private URI uri; - private Integer port; - private Credentials credentials; - private boolean laxRedirect; - private Boolean https; - private SchemeSocketFactory socketFactory; - private ConnectionReuseStrategy reuseStrategy; - private boolean trustAll; - private boolean trustSelfSigned; - - public HttpClientBuilder clientConnectionManager(ClientConnectionManager val) { - this.clientConnectionManager = checkNotNull(val, "clientConnectionManager"); - return this; - } - public HttpClientBuilder httpParams(HttpParams val) { - checkState(httpParams == null, "Must not call httpParams multiple times, or after other methods like connectionTimeout"); - this.httpParams = checkNotNull(val, "httpParams"); - return this; - } - public HttpClientBuilder connectionTimeout(Duration val) { - if (httpParams == null) httpParams = new BasicHttpParams(); - long millis = checkNotNull(val, "connectionTimeout").toMilliseconds(); - if (millis > Integer.MAX_VALUE) throw new IllegalStateException("HttpClient only accepts upto max-int millis for connectionTimeout, but given "+val); - HttpConnectionParams.setConnectionTimeout(httpParams, (int) millis); - return this; - } - public HttpClientBuilder socketTimeout(Duration val) { - if (httpParams == null) httpParams = new BasicHttpParams(); - long millis = checkNotNull(val, "socketTimeout").toMilliseconds(); - if (millis > Integer.MAX_VALUE) throw new IllegalStateException("HttpClient only accepts upto max-int millis for socketTimeout, but given "+val); - HttpConnectionParams.setSoTimeout(httpParams, (int) millis); - return this; - } - public HttpClientBuilder reuseStrategy(ConnectionReuseStrategy val) { - this.reuseStrategy = checkNotNull(val, "reuseStrategy"); - return this; - } - public HttpClientBuilder uri(String val) { - return uri(URI.create(checkNotNull(val, "uri"))); - } - public HttpClientBuilder uri(URI val) { - this.uri = checkNotNull(val, "uri"); - if (https == null) https = ("https".equalsIgnoreCase(uri.getScheme())); - return this; - } - public HttpClientBuilder port(int val) { - this.port = val; - return this; - } - public HttpClientBuilder credentials(Credentials val) { - this.credentials = checkNotNull(val, "credentials"); - return this; - } - public void credential(Optional val) { - if (val.isPresent()) credentials = val.get(); - } - /** similar to curl --post301 -L` */ - public HttpClientBuilder laxRedirect(boolean val) { - this.laxRedirect = val; - return this; - } - public HttpClientBuilder https(boolean val) { - this.https = val; - return this; - } - public HttpClientBuilder socketFactory(SchemeSocketFactory val) { - this.socketFactory = checkNotNull(val, "socketFactory"); - return this; - } - public HttpClientBuilder trustAll() { - this.trustAll = true; - return this; - } - public HttpClientBuilder trustSelfSigned() { - this.trustSelfSigned = true; - return this; - } - public HttpClient build() { - final DefaultHttpClient httpClient = new DefaultHttpClient(clientConnectionManager); - httpClient.setParams(httpParams); - - // support redirects for POST (similar to `curl --post301 -L`) - // http://stackoverflow.com/questions/3658721/httpclient-4-error-302-how-to-redirect - if (laxRedirect) { - httpClient.setRedirectStrategy(new LaxRedirectStrategy()); - } - if (reuseStrategy != null) { - httpClient.setReuseStrategy(reuseStrategy); - } - if (https == Boolean.TRUE || (uri!=null && uri.toString().startsWith("https:"))) { - try { - if (port == null) { - port = (uri != null && uri.getPort() >= 0) ? uri.getPort() : 443; - } - if (socketFactory == null) { - if (trustAll) { - TrustStrategy trustStrategy = new TrustAllStrategy(); - X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; - socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier); - } else if (trustSelfSigned) { - TrustStrategy trustStrategy = new TrustSelfSignedStrategy(); - X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; - socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier); - } else { - // Using default https scheme: based on default java truststore, which is pretty strict! - } - } - if (socketFactory != null) { - Scheme sch = new Scheme("https", port, socketFactory); - httpClient.getConnectionManager().getSchemeRegistry().register(sch); - } - } catch (Exception e) { - LOG.warn("Error setting trust for uri {}", uri); - throw Exceptions.propagate(e); - } - } - - // Set credentials - if (uri != null && credentials != null) { - String hostname = uri.getHost(); - int port = uri.getPort(); - httpClient.getCredentialsProvider().setCredentials(new AuthScope(hostname, port), credentials); - } - if (uri==null && credentials!=null) { - LOG.warn("credentials have no effect in builder unless URI for host is specified"); - } - - return httpClient; - } - } - - protected static abstract class HttpRequestBuilder, R extends HttpRequest> { - protected R req; - - protected HttpRequestBuilder(R req) { - this.req = req; - } - @SuppressWarnings("unchecked") - protected B self() { - return (B) this; - } - public B headers(Map headers) { - if (headers!=null) { - for (Map.Entry entry : headers.entrySet()) { - req.addHeader(entry.getKey(), entry.getValue()); - } - } - return self(); - } - public B headers(Multimap headers) { - if (headers!=null) { - for (Map.Entry entry : headers.entries()) { - req.addHeader(entry.getKey(), entry.getValue()); - } - } - return self(); - } - public R build() { - return req; - } - } - - protected static abstract class HttpEntityEnclosingRequestBaseBuilder, R extends HttpEntityEnclosingRequestBase> extends HttpRequestBuilder { - protected HttpEntityEnclosingRequestBaseBuilder(R req) { - super(req); - } - public B body(byte[] body) { - if (body != null) { - HttpEntity httpEntity = new ByteArrayEntity(body); - req.setEntity(httpEntity); - } - return self(); - } - } - - public static class HttpGetBuilder extends HttpRequestBuilder { - public HttpGetBuilder(URI uri) { - super(new HttpGet(uri)); - } - } - - public static class HttpHeadBuilder extends HttpRequestBuilder { - public HttpHeadBuilder(URI uri) { - super(new HttpHead(uri)); - } - } - - public static class HttpDeleteBuilder extends HttpRequestBuilder { - public HttpDeleteBuilder(URI uri) { - super(new HttpDelete(uri)); - } - } - - public static class HttpPostBuilder extends HttpEntityEnclosingRequestBaseBuilder { - HttpPostBuilder(URI uri) { - super(new HttpPost(uri)); - } - } - - public static class HttpFormPostBuilder extends HttpRequestBuilder { - HttpFormPostBuilder(URI uri) { - super(new HttpPost(uri)); - } - - public HttpFormPostBuilder params(Map params) { - if (params != null) { - Collection httpParams = new ArrayList(params.size()); - for (Entry param : params.entrySet()) { - httpParams.add(new BasicNameValuePair(param.getKey(), param.getValue())); - } - req.setEntity(new UrlEncodedFormEntity(httpParams)); - } - return self(); - } - } - - public static class HttpPutBuilder extends HttpEntityEnclosingRequestBaseBuilder { - public HttpPutBuilder(URI uri) { - super(new HttpPut(uri)); - } - } - - public static HttpToolResponse httpGet(HttpClient httpClient, URI uri, Map headers) { - HttpGet req = new HttpGetBuilder(uri).headers(headers).build(); - return execAndConsume(httpClient, req); - } - - public static HttpToolResponse httpPost(HttpClient httpClient, URI uri, Map headers, byte[] body) { - HttpPost req = new HttpPostBuilder(uri).headers(headers).body(body).build(); - return execAndConsume(httpClient, req); - } - - public static HttpToolResponse httpPut(HttpClient httpClient, URI uri, Map headers, byte[] body) { - HttpPut req = new HttpPutBuilder(uri).headers(headers).body(body).build(); - return execAndConsume(httpClient, req); - } - - public static HttpToolResponse httpPost(HttpClient httpClient, URI uri, Map headers, Map params) { - HttpPost req = new HttpFormPostBuilder(uri).headers(headers).params(params).build(); - return execAndConsume(httpClient, req); - } - - public static HttpToolResponse httpDelete(HttpClient httpClient, URI uri, Map headers) { - HttpDelete req = new HttpDeleteBuilder(uri).headers(headers).build(); - return execAndConsume(httpClient, req); - } - - public static HttpToolResponse httpHead(HttpClient httpClient, URI uri, Map headers) { - HttpHead req = new HttpHeadBuilder(uri).headers(headers).build(); - return execAndConsume(httpClient, req); - } - - public static HttpToolResponse execAndConsume(HttpClient httpClient, HttpUriRequest req) { - long startTime = System.currentTimeMillis(); - try { - HttpResponse httpResponse = httpClient.execute(req); - - try { - return new HttpToolResponse(httpResponse, startTime); - } finally { - EntityUtils.consume(httpResponse.getEntity()); - } - } catch (Exception e) { - throw Exceptions.propagate(e); - } - } - - public static boolean isStatusCodeHealthy(int code) { return (code>=200 && code<=299); } - - public static String toBasicAuthorizationValue(UsernamePasswordCredentials credentials) { - return "Basic "+Base64.encodeBase64String( (credentials.getUserName()+":"+credentials.getPassword()).getBytes() ); - } - - public static String encodeUrlParams(Map data) { - if (data==null) return ""; - Iterable args = Iterables.transform(data.entrySet(), - new Function,String>() { - @Override public String apply(Map.Entry entry) { - Object k = entry.getKey(); - Object v = entry.getValue(); - return URLParamEncoder.encode(Strings.toString(k)) + (v != null ? "=" + URLParamEncoder.encode(Strings.toString(v)) : ""); - } - }); - return Joiner.on("&").join(args); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/http/HttpToolResponse.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/http/HttpToolResponse.java b/core/src/main/java/brooklyn/util/http/HttpToolResponse.java deleted file mode 100644 index 1837a87..0000000 --- a/core/src/main/java/brooklyn/util/http/HttpToolResponse.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 brooklyn.util.http; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.event.feed.http.HttpPollValue; -import brooklyn.util.guava.Maybe; -import brooklyn.util.stream.Streams; -import brooklyn.util.time.Duration; -import brooklyn.util.time.Time; - -import com.google.common.base.Objects; -import com.google.common.base.Throwables; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; -import com.google.common.io.ByteStreams; - -public class HttpToolResponse implements HttpPollValue { - - private static final Logger log = LoggerFactory.getLogger(HttpToolResponse.class); - - private final Object mutex = new Object(); - private final HttpResponse response; - private final long startTime; - private final long durationMillisOfFirstResponse; - private final long durationMillisOfFullContent; - private int responseCode; - private String reasonPhrase; - private Map> headerLists; - private byte[] content; - - - public HttpToolResponse(HttpResponse response, long startTime) { - this.response = response; - this.startTime = startTime; - - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - HttpEntity entity = response.getEntity(); - if (entity != null) { - entity.getContentLength(); - durationMillisOfFirstResponse = Duration.sinceUtc(startTime).toMilliseconds(); - - ByteStreams.copy(entity.getContent(), out); - content = out.toByteArray(); - - entity.getContentLength(); - } else { - durationMillisOfFirstResponse = Duration.sinceUtc(startTime).toMilliseconds(); - content = new byte[0]; - } - durationMillisOfFullContent = Duration.sinceUtc(startTime).toMilliseconds(); - if (log.isTraceEnabled()) - log.trace("HttpPollValue latency "+Time.makeTimeStringRounded(durationMillisOfFirstResponse)+" / "+Time.makeTimeStringRounded(durationMillisOfFullContent)+", content size "+content.length); - } catch (IOException e) { - throw Throwables.propagate(e); - } - } - - public HttpToolResponse(int responseCode, Map> headers, byte[] content, - long startTime, long durationMillisOfFirstResponse, long durationMillisOfFullContent) { - this.response = null; - this.responseCode = responseCode; - this.headerLists = ImmutableMap.copyOf(headers); - this.content = content; - this.startTime = startTime; - this.durationMillisOfFirstResponse = durationMillisOfFirstResponse; - this.durationMillisOfFullContent = durationMillisOfFullContent; - } - - public int getResponseCode() { - synchronized (mutex) { - if (responseCode == 0) { - responseCode = response.getStatusLine().getStatusCode(); - } - } - return responseCode; - } - - public String getReasonPhrase() { - synchronized (mutex) { - if (reasonPhrase == null) { - reasonPhrase = response.getStatusLine().getReasonPhrase(); - } - } - return reasonPhrase; - } - - /** returns the timestamp (millis since 1970) when this request was started */ - public long getStartTime() { - return startTime; - } - - /** returns latency, in milliseconds, if value was initialized with a start time */ - public long getLatencyFullContent() { - return durationMillisOfFullContent; - } - - /** returns latency, in milliseconds, before response started coming in */ - public long getLatencyFirstResponse() { - return durationMillisOfFirstResponse; - } - - public Map> getHeaderLists() { - synchronized (mutex) { - if (headerLists == null) { - Map> headerListsMutable = Maps.newLinkedHashMap(); - for (Header header : response.getAllHeaders()) { - List vals = headerListsMutable.get(header.getName()); - if (vals == null) { - vals = new ArrayList(); - headerListsMutable.put(header.getName(), vals); - } - vals.add(header.getValue()); - } - headerLists = Collections.unmodifiableMap(headerListsMutable); - } - } - return headerLists; - } - - public byte[] getContent() { - synchronized (mutex) { - if (content == null) { - InputStream in = null; - try { - in = response.getEntity().getContent(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteStreams.copy(in, out); - content = out.toByteArray(); - } catch (IOException e) { - throw Throwables.propagate(e); - } finally { - Streams.closeQuietly(in); - } - } - } - return content; - } - - public String getContentAsString() { - return new String(getContent()); - } - - public Maybe getResponse() { - return Maybe.fromNullable(response); - } - - @Override - public String toString() { - return Objects.toStringHelper(getClass()) - .add("responseCode", responseCode) - .toString(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java b/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java deleted file mode 100644 index 5048b0e..0000000 --- a/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 brooklyn.util.internal; - -import java.util.Map; - -import org.apache.brooklyn.api.management.ExecutionContext; - -import brooklyn.config.ConfigKey; - -/** Interface for resolving key values; typically implemented by the config key, - * but discouraged for external usage. - */ -public interface ConfigKeySelfExtracting extends ConfigKey { - - /** - * Extracts the value for this config key from the given map. - */ - T extractValue(Map configMap, ExecutionContext exec); - - /** - * @return True if there is an entry in the configMap that could be extracted - */ - boolean isSet(Map configMap); -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/Repeater.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/internal/Repeater.java b/core/src/main/java/brooklyn/util/internal/Repeater.java deleted file mode 100644 index ef149ba..0000000 --- a/core/src/main/java/brooklyn/util/internal/Repeater.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * 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 brooklyn.util.internal; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.util.JavaGroovyEquivalents; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.flags.FlagUtils; -import brooklyn.util.flags.SetFromFlag; -import brooklyn.util.time.Duration; -import brooklyn.util.time.Time; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.Callables; - -/** - * Simple DSL to repeat a fragment of code periodically until a condition is satisfied. - * - * In its simplest case, it is passed two {@link groovy.lang.Closure}s / {@link Callable} - - * the first is executed, then the second. If the second closure returns false, the loop - * is repeated; if true, it finishes. Further customization can be applied to set the period - * between loops and place a maximum limit on how long the loop should run for. - *

- * It is configured in a fluent manner. For example, in Groovy: - *

- * {@code
- * Repeater.create("Wait until the Frobnitzer is ready")
- *     .repeat {
- *         status = frobnitzer.getStatus()
- *     }
- *     .until {
- *         status == "Ready" || status == "Failed"
- *     }
- *     .limitIterationsTo(30)
- *     .run()
- * }
- * 
- * - * Or in Java: - *
- * {@code
- * Repeater.create("Wait until the Frobnitzer is ready")
- *     .until(new Callable() {
- *              public Boolean call() {
- *                  String status = frobnitzer.getStatus()
- *                  return "Ready".equals(status) || "Failed".equals(status);
- *              }})
- *     .limitIterationsTo(30)
- *     .run()
- * }
- * 
- * - * @deprecated since 0.7.0, use {@link brooklyn.util.repeat.Repeater} instead - */ -@Deprecated -public class Repeater { - - // TODO Was converted to Java, from groovy. Needs thorough review and improvements - // to use idiomatic java - - private static final Logger log = LoggerFactory.getLogger(Repeater.class); - - static { TimeExtras.init(); } - - @SetFromFlag - private String description; - private Callable body = Callables.returning(null); - private Callable exitCondition; - @SetFromFlag - private Long period = null; - @SetFromFlag("timeout") - private Long durationLimit = null; - private int iterationLimit = 0; - private boolean rethrowException = false; - private boolean rethrowExceptionImmediately = false; - private boolean warnOnUnRethrownException = true; - - public Repeater() { - this(MutableMap.of(), null); - } - - public Repeater(Map flags) { - this(flags, null); - } - - public Repeater(String description) { - this(MutableMap.of(), description); - } - - /** - * Construct a new instance of Repeater. - * - * @param flags can include period, timeout, description - * @param description a description of the operation that will appear in debug logs. - */ - public Repeater(Map flags, String description) { - setFromFlags(flags); - this.description = JavaGroovyEquivalents.elvis(description, this.description, "Repeater"); - } - - public void setFromFlags(Map flags) { - FlagUtils.setFieldsFromFlags(flags, this); - } - - public static Repeater create() { - return create(MutableMap.of()); - } - public static Repeater create(Map flags) { - return create(flags, null); - } - public static Repeater create(String description) { - return create(MutableMap.of(), description); - } - public static Repeater create(Map flags, String description) { - return new Repeater(flags, description); - } - - /** - * Sets the main body of the loop to be a no-op. - * - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater repeat() { - return repeat(Callables.returning(null)); - } - - /** - * Sets the main body of the loop. - * - * @param body a closure or other Runnable that is executed in the main body of the loop. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater repeat(Runnable body) { - checkNotNull(body, "body must not be null"); - this.body = (body instanceof Callable) ? (Callable)body : Executors.callable(body); - return this; - } - - /** - * Sets the main body of the loop. - * - * @param body a closure or other Callable that is executed in the main body of the loop. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater repeat(Callable body) { - checkNotNull(body, "body must not be null"); - this.body = body; - return this; - } - - /** - * Set how long to wait between loop iterations. - * - * @param period how long to wait between loop iterations. - * @param unit the unit of measurement of the period. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater every(long period, TimeUnit unit) { - Preconditions.checkArgument(period > 0, "period must be positive: %s", period); - checkNotNull(unit, "unit must not be null"); - this.period = unit.toMillis(period); - return this; - } - - /** - * @see #every(long, TimeUnit) - */ - public Repeater every(Duration duration) { - Preconditions.checkNotNull(duration, "duration must not be null"); - Preconditions.checkArgument(duration.toMilliseconds()>0, "period must be positive: %s", duration); - this.period = duration.toMilliseconds(); - return this; - } - - public Repeater every(groovy.time.Duration duration) { - return every(Duration.of(duration)); - } - - /** - * @see #every(long, TimeUnit) - * @deprecated specify unit - */ - public Repeater every(long duration) { - return every(duration, TimeUnit.MILLISECONDS); - } - - /** - * Set code fragment that tests if the loop has completed. - * - * @param exitCondition a closure or other Callable that returns a boolean. If this code returns {@literal true} then the - * loop will stop executing. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater until(Callable exitCondition) { - Preconditions.checkNotNull(exitCondition, "exitCondition must not be null"); - this.exitCondition = exitCondition; - return this; - } - - /** - * If the exit condition check throws an exception, it will be recorded and the last exception will be thrown on failure. - * - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater rethrowException() { - this.rethrowException = true; - return this; - } - - /** - * If the repeated body or the exit condition check throws an exception, then propagate that exception immediately. - * - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater rethrowExceptionImmediately() { - this.rethrowExceptionImmediately = true; - return this; - } - - public Repeater suppressWarnings() { - this.warnOnUnRethrownException = false; - return this; - } - - /** - * Set the maximum number of iterations. - * - * The loop will exit if the condition has not been satisfied after this number of iterations. - * - * @param iterationLimit the maximum number of iterations. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater limitIterationsTo(int iterationLimit) { - Preconditions.checkArgument(iterationLimit > 0, "iterationLimit must be positive: %s", iterationLimit); - this.iterationLimit = iterationLimit; - return this; - } - - /** - * Set the amount of time to wait for the condition. - * The repeater will wait at least this long for the condition to be true, - * and will exit soon after even if the condition is false. - * - * @param deadline the time that the loop should wait. - * @param unit the unit of measurement of the period. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater limitTimeTo(long deadline, TimeUnit unit) { - Preconditions.checkArgument(deadline > 0, "deadline must be positive: %s", deadline); - Preconditions.checkNotNull(unit, "unit must not be null"); - this.durationLimit = unit.toMillis(deadline); - return this; - } - - /** - * @see #limitTimeTo(long, TimeUnit) - */ - public Repeater limitTimeTo(Duration duration) { - Preconditions.checkNotNull(duration, "duration must not be null"); - Preconditions.checkArgument(duration.toMilliseconds() > 0, "deadline must be positive: %s", duration); - this.durationLimit = duration.toMilliseconds(); - return this; - } - - /** - * Run the loop. - * - * @return true if the exit condition was satisfied; false if the loop terminated for any other reason. - */ - public boolean run() { - Preconditions.checkState(body != null, "repeat() method has not been called to set the body"); - Preconditions.checkState(exitCondition != null, "until() method has not been called to set the exit condition"); - Preconditions.checkState(period != null, "every() method has not been called to set the loop period time units"); - - Throwable lastError = null; - int iterations = 0; - long endTime = -1; - if (durationLimit != null) { - endTime = System.currentTimeMillis() + durationLimit; - } - - while (true) { - iterations++; - - try { - body.call(); - } catch (Exception e) { - log.warn(description, e); - if (rethrowExceptionImmediately) throw Exceptions.propagate(e); - } - - boolean done = false; - try { - lastError = null; - done = exitCondition.call(); - } catch (Exception e) { - if (log.isDebugEnabled()) log.debug(description, e); - lastError = e; - if (rethrowExceptionImmediately) throw Exceptions.propagate(e); - } - if (done) { - if (log.isDebugEnabled()) log.debug("{}: condition satisfied", description); - return true; - } else { - if (log.isDebugEnabled()) { - String msg = String.format("%s: unsatisfied during iteration %s %s", description, iterations, - (iterationLimit > 0 ? "(max "+iterationLimit+" attempts)" : "") + - (endTime > 0 ? "("+Time.makeTimeStringRounded(endTime - System.currentTimeMillis())+" remaining)" : "")); - if (iterations == 1) { - log.debug(msg); - } else { - log.trace(msg); - } - } - } - - if (iterationLimit > 0 && iterations == iterationLimit) { - if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and exceeded iteration limit", description); - if (rethrowException && lastError != null) { - log.warn("{}: error caught checking condition (rethrowing): {}", description, lastError.getMessage()); - throw Exceptions.propagate(lastError); - } - if (warnOnUnRethrownException && lastError != null) - log.warn("{}: error caught checking condition: {}", description, lastError.getMessage()); - return false; - } - - if (endTime > 0) { - if (System.currentTimeMillis() > endTime) { - if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and deadline {} passed", - description, Time.makeTimeStringRounded(endTime - System.currentTimeMillis())); - if (rethrowException && lastError != null) { - log.error("{}: error caught checking condition: {}", description, lastError.getMessage()); - throw Exceptions.propagate(lastError); - } - return false; - } - } - - Time.sleep(period); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.java b/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.java deleted file mode 100644 index 1e2b435..0000000 --- a/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 brooklyn.util.internal.ssh; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.util.exceptions.Exceptions; - -/** - * Allow replayable request to be retried a limited number of times, and impose an exponential back-off - * delay before returning. - *

- * Copied and modified from jclouds; original author was James Murty - */ -public class BackoffLimitedRetryHandler { - - private static final Logger LOG = LoggerFactory.getLogger(BackoffLimitedRetryHandler.class); - - private final int retryCountLimit; - - private final long delayStart; - - public BackoffLimitedRetryHandler() { - this(5, 50L); - } - - public BackoffLimitedRetryHandler(int retryCountLimit, long delayStart) { - this.retryCountLimit = retryCountLimit; - this.delayStart = delayStart; - } - - public void imposeBackoffExponentialDelay(int failureCount, String commandDescription) { - imposeBackoffExponentialDelay(delayStart, 2, failureCount, retryCountLimit, commandDescription); - } - - public void imposeBackoffExponentialDelay(long period, int pow, int failureCount, int max, String commandDescription) { - imposeBackoffExponentialDelay(period, period * 10l, pow, failureCount, max, commandDescription); - } - - public void imposeBackoffExponentialDelay(long period, - long maxPeriod, - int pow, - int failureCount, - int max, - String commandDescription) { - long delayMs = (long) (period * Math.pow(failureCount, pow)); - delayMs = (delayMs > maxPeriod) ? maxPeriod : delayMs; - if (LOG.isDebugEnabled()) LOG.debug("Retry {}/{}: delaying for {} ms: {}", - new Object[] {failureCount, max, delayMs, commandDescription}); - try { - Thread.sleep(delayMs); - } catch (InterruptedException e) { - Exceptions.propagate(e); - } - } - -}