Repository: incubator-brooklyn Updated Branches: refs/heads/master dbf621a84 -> 147f9ec44
Rename o.a.b.util.groovy.internal to o.a.b.util.groovy Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/0eab0fa0 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/0eab0fa0 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/0eab0fa0 Branch: refs/heads/master Commit: 0eab0fa05e4b9f700cef855e974971faf494116c Parents: dbf621a Author: Aled Sage <[email protected]> Authored: Wed Aug 19 22:31:05 2015 +0100 Committer: Aled Sage <[email protected]> Committed: Wed Aug 19 22:31:24 2015 +0100 ---------------------------------------------------------------------- .../util/core/BrooklynLanguageExtensions.java | 2 +- .../brooklyn/util/core/internal/Repeater.java | 2 +- .../util/core/internal/RepeaterTest.groovy | 4 +- .../Infinispan5ServerIntegrationTest.groovy | 2 +- .../nosql/couchdb/AbstractCouchDBNodeTest.java | 2 +- .../webapp/WebAppLiveIntegrationTest.groovy | 2 +- ...namicWebAppClusterRebindIntegrationTest.java | 2 +- .../brooklyn/util/groovy/JavadocDummy.java | 30 ++ .../brooklyn/util/groovy/LanguageUtils.groovy | 383 +++++++++++++++++++ .../brooklyn/util/groovy/TimeExtras.groovy | 83 ++++ .../util/groovy/internal/JavadocDummy.java | 30 -- .../util/groovy/internal/LanguageUtils.groovy | 383 ------------------- .../util/groovy/internal/TimeExtras.groovy | 83 ---- .../util/groovy/LanguageUtilsTest.groovy | 152 ++++++++ .../brooklyn/util/groovy/PojoTestingFields.java | 28 ++ .../brooklyn/util/groovy/TimeExtrasTest.groovy | 49 +++ .../groovy/internal/LanguageUtilsTest.groovy | 153 -------- .../util/groovy/internal/PojoTestingFields.java | 28 -- .../util/groovy/internal/TimeExtrasTest.groovy | 51 --- 19 files changed, 733 insertions(+), 736 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java b/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java index 5e7f0a6..afad73f 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java @@ -21,7 +21,7 @@ package org.apache.brooklyn.util.core; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.brooklyn.core.internal.BrooklynInitialization; -import org.apache.brooklyn.util.groovy.internal.TimeExtras; +import org.apache.brooklyn.util.groovy.TimeExtras; /** @deprecated since 0.7.0 use {@link BrooklynInitialization} */ public class BrooklynLanguageExtensions { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java b/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java index bc54b6e..77d15c7 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java @@ -30,7 +30,7 @@ import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.flags.FlagUtils; import org.apache.brooklyn.util.core.flags.SetFromFlag; import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.groovy.internal.TimeExtras; +import org.apache.brooklyn.util.groovy.TimeExtras; import org.apache.brooklyn.util.time.Duration; import org.apache.brooklyn.util.time.Time; import org.slf4j.Logger; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy index 5888aa0..5eae3c9 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy +++ b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy @@ -25,8 +25,8 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit import org.testng.annotations.Test -import org.apache.brooklyn.util.core.internal.Repeater; -import org.apache.brooklyn.util.groovy.internal.TimeExtras; +import org.apache.brooklyn.util.core.internal.Repeater +import org.apache.brooklyn.util.groovy.TimeExtras; import org.apache.brooklyn.util.time.Duration; import com.google.common.base.Stopwatch http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy ---------------------------------------------------------------------- diff --git a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy index b283f2f..1e68c27 100644 --- a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy +++ b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy @@ -35,7 +35,7 @@ import org.apache.brooklyn.api.entity.Application import org.apache.brooklyn.core.entity.Entities import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation import org.apache.brooklyn.core.test.entity.TestApplicationImpl -import org.apache.brooklyn.util.groovy.internal.TimeExtras +import org.apache.brooklyn.util.groovy.TimeExtras; import org.apache.brooklyn.util.net.Networking import org.apache.brooklyn.util.repeat.Repeater http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java index a4382ce..2ecfac8 100644 --- a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java +++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java @@ -27,7 +27,7 @@ import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.entity.factory.ApplicationBuilder; import org.apache.brooklyn.core.test.entity.TestApplication; import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; -import org.apache.brooklyn.util.groovy.internal.TimeExtras; +import org.apache.brooklyn.util.groovy.TimeExtras; /** * CouchDB test framework for integration and live tests. http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy index 6bb41cf..c8747fa 100644 --- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy @@ -37,7 +37,7 @@ import org.apache.brooklyn.entity.webapp.jboss.JBoss7ServerImpl import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer import org.apache.brooklyn.entity.webapp.tomcat.TomcatServerImpl import org.apache.brooklyn.test.TestUtils -import org.apache.brooklyn.util.groovy.internal.TimeExtras +import org.apache.brooklyn.util.groovy.TimeExtras; import org.slf4j.Logger import org.slf4j.LoggerFactory import org.testng.annotations.AfterMethod http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java index a4dec8c..b05a747 100644 --- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java @@ -41,7 +41,7 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess; import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster; import org.apache.brooklyn.test.WebAppMonitor; import org.apache.brooklyn.test.support.TestResourceUnavailableException; -import org.apache.brooklyn.util.groovy.internal.TimeExtras; +import org.apache.brooklyn.util.groovy.TimeExtras; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.AfterMethod; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java ---------------------------------------------------------------------- diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java new file mode 100644 index 0000000..c9a51b5 --- /dev/null +++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java @@ -0,0 +1,30 @@ +/* + * 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.util.groovy; + +/** Maven Central requires javadoc to promote as a release. This seemed to happen when this was built by maven as a bundle, + * but now that it is built as a jar it does not. This class exists only to provide that javadoc. + * <p> + * Note the groovy code does javadoc but the maven build is not picking it up. It *is* generated as part of the site build. + */ +public class JavadocDummy { + + private JavadocDummy() {} + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy new file mode 100644 index 0000000..d4fe86c --- /dev/null +++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy @@ -0,0 +1,383 @@ +/* + * 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.util.groovy + +import java.lang.reflect.Field +import java.lang.reflect.Method; +import java.lang.reflect.Modifier +import java.util.Collection; +import java.util.concurrent.atomic.AtomicLong + +import org.apache.brooklyn.util.javalang.Reflections; +import org.apache.brooklyn.util.text.Identifiers + +import com.google.common.annotations.Beta +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +/** + * Useful Groovy utility methods. + * + * @deprecated since 0.5; requires thorough review for what will be kept. + * e.g. consider instead using guava's {@link com.google.common.collect.Multimap} instead of addToMapOfSets etc + */ +@Deprecated +@Beta +public class LanguageUtils { + // For unique identifiers + private static final AtomicLong seed = new AtomicLong(0L) + + public static <T> T getRequiredField(String name, Map<?,?> m) { + if (!m.containsKey(name)) + throw new IllegalArgumentException("a parameter '"+name+"' was required in the argument to this function") + m.get name + } + + public static <T> T getOptionalField(String name, Map<?,?> m, T defaultValue=null) { + m.get(name) ?: defaultValue + } + + public static <T> T getPropertySafe(Object target, String name, T defaultValue=null) { + target.hasProperty(name)?.getProperty(target) ?: defaultValue + } + + //TODO find with annotation + + public static byte[] serialize(Object orig) { + if (orig == null) return null; + + // Write the object out to a byte array + ByteArrayOutputStream fbos = [] + ObjectOutputStream out = new ObjectOutputStream(fbos); + out.writeObject(orig); + out.flush(); + out.close(); + return fbos.toByteArray(); + } + + public static <T> T deserialize(byte[] bytes, ClassLoader classLoader) { + if (bytes == null) return null; + + ObjectInputStream ins = + //new ObjectInputStreamWithLoader(new FastByteArrayInputStream(bytes, bytes.length), classLoader); + new ObjectInputStream(new ByteArrayInputStream(bytes)); + (T) ins.readObject(); + } + + /** + * @deprecated use Identifiers.makeRandomId(8) + */ + @Deprecated + public static String newUid() { Identifiers.makeRandomId(8) } + + public static Map setFieldsFromMap(Object target, Map fieldValues) { + Map unused = [:] + fieldValues.each { + // println "looking for "+it.key+" in "+target+": "+target.metaClass.hasProperty(it.key) + target.hasProperty(it.key) ? target.(it.key) = it.value : unused << it + } + unused + } + + /** + * Adds the given value to a collection in the map under the key. + * + * A collection (as {@link LinkedHashMap}) will be created if necessary, + * synchronized on map for map access/change and set for addition there + * + * @return the updated set (instance, not copy) + * + * @deprecated since 0.5; use {@link HashMultimap}, and {@link Multimaps#synchronizedSetMultimap(com.google.common.collect.SetMultimap)} + */ + @Deprecated + public static <K,V> Set<V> addToMapOfSets(Map<K,Set<V>> map, K key, V valueInCollection) { + Set<V> coll; + synchronized (map) { + coll = map.get(key) + if (coll==null) { + coll = new LinkedHashSet<V>() + map.put(key, coll) + } + if (coll.isEmpty()) { + synchronized (coll) { + coll.add(valueInCollection) + } + //if collection was empty then add to the collection while holding the map lock, to prevent removal + return coll + } + } + synchronized (coll) { + if (!coll.isEmpty()) { + coll.add(valueInCollection) + return coll; + } + } + //if was empty, recurse, because someone else might be removing the collection + return addToMapOfSets(map, key, valueInCollection); + } + + /** + * as {@link #addToMapOfSets(Map, Object, Object)} but for {@link ArrayList} + * + * @deprecated since 0.5; use {@link ArrayListMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)} + */ + @Deprecated + public static <K,V> List<V> addToMapOfLists(Map<K,List<V>> map, K key, V valueInCollection) { + List<V> coll; + synchronized (map) { + coll = map.get(key) + if (coll==null) { + coll = new ArrayList<V>() + map.put(key, coll) + } + if (coll.isEmpty()) { + synchronized (coll) { + coll.add(valueInCollection) + } + //if collection was empty then add to the collection while holding the map lock, to prevent removal + return coll + } + } + synchronized (coll) { + if (!coll.isEmpty()) { + coll.add(valueInCollection) + return coll; + } + } + //if was empty, recurse, because someone else might be removing the collection + return addToMapOfLists(map, key, valueInCollection); + } + + /** + * Removes the given value from a collection in the map under the key. + * + * @return the updated set (instance, not copy) + * + * @deprecated since 0.5; use {@link ArrayListMultimap} or {@link HashMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)} etc + */ + @Deprecated + public static <K,V> boolean removeFromMapOfCollections(Map<K,? extends Collection<V>> map, K key, V valueInCollection) { + Collection<V> coll; + synchronized (map) { + coll = map.get(key) + if (coll==null) return false; + } + boolean result; + synchronized (coll) { + result = coll.remove(valueInCollection) + } + if (coll.isEmpty()) { + synchronized (map) { + synchronized (coll) { + if (coll.isEmpty()) { + //only remove from the map if no one is adding to the collection or to the map, and the collection is still in the map + if (map.get(key)==coll) { + map.remove(key) + } + } + } + } + } + return result; + } + + /** + * Visits all fields of a given object, recursively. + * + * For collections, arrays, and maps it visits the items within, passing null for keys where it isn't a map. + */ + public static void visitFields(Object o, FieldVisitor fv, Collection<Object> objectsToSkip=([] as Set)) { + if (o == null || objectsToSkip.contains(o)) return + objectsToSkip << o + if (o in String) return + if (o in Map) { + o.each { key, value -> + fv.visit(o, key.toString(), value) + visitFields(value, fv, objectsToSkip) + } + } else if ((o in Collection) || (o.getClass().isArray())) { + o.each { + entry -> + fv.visit(o, null, entry) + visitFields(entry, fv, objectsToSkip) + } + } else { + o.getClass().getDeclaredFields().each { + Field field -> + if ((field.getModifiers() & Modifier.STATIC) || field.isSynthetic()) return; //skip static + field.setAccessible true + def v = field.get(o); + fv.visit(o, field.name, v) + visitFields(v, fv, objectsToSkip) + } + } + } + + public interface FieldVisitor { + /** Invoked by visitFields; fieldName will be null for collections */ + public void visit(Object parent, String fieldName, Object value) + } + + /** + * Iterates through two collections simultaneously, passing both args to code. + * + * <pre> + * a = ['a','b']; b=[1,2]; + * assert ['a1','b2'] == forboth(a,b) { x,y -> x+y } + * </pre> + */ + public static Collection forBoth(Collection l1, Collection l2, Closure code) { + def result=[] + l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) } + result + } + + public static Collection forBothWithIndex(Collection l1, Collection l2, Closure code) { + def result=[] + l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) } + result + } + + public static Collection forBoth(Object[] l1, Object[] l2, Closure code) { + def result=[] + l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) } + result + } + + public static Collection forBothWithIndex(Object[] l1, Object[] l2, Closure code) { + def result=[] + l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) } + result + } + + /** return value used to indicate that there is no such field */ + public static final Object NO_SUCH_FIELD = new Object(); + + /** + * Default field getter. + * + * Delegates to {@code object[field]} (which will invoke a getter if one exists, in groovy), + * unless field starts with {@literal @} in which case it looks up the actual java field (bypassing getter). + * <p> + * Can be extended as needed when passed to {@link #equals(Object, Object, Class, String[])} + */ + public static final Closure DEFAULT_FIELD_GETTER = { Object object, Object field -> + try { + if ((field in String) && field.startsWith("@")) { + return object.@"${field.substring(1)}" + } + return object[field] + } catch (Exception e) { + return NO_SUCH_FIELD + } + } + + /** + * Checks equality of o1 and o2 with respect to the named fields, optionally enforcing a common superclass + * and using a custom field-getter. + * + * Other types can be supplied if they are supported by {@code object[field]} (what the {@link #DEFAULT_FIELD_GETTER} does) + * or if the {@literal optionalGetter} handles it. Note that {@code object[field]} causes invocation of {@code object.getAt(field)} + * (which can be provided on the object for non-strings - this is preferred to an optionalGetter, generally) + * looking for {@code object.getXxx()}, where field is a string {@literal xxx}, then {@code object.xxx}. + * <p> + * One exception is that field names which start with {@literal @} get the field directly according to {@link #DEFAULT_FIELD_GETTER}, + * but use with care on private fields, as they must be on the object and not a superclass, and with groovy properties + * (formerly known as package-private, i.e. with no access modifiers) because they become private fields. + * <p> + * For example + * <pre> + * public class Foo { + * Object bar; + * public boolean equals(Object other) { LangaugeUtils.equals(this, other, Foo.class, ["bar"]); } + * public int hashCode() { LangaugeUtils.hashCode(this, ["bar"]); } + * } + * </pre> + * + * @param o1 one object to compare + * @param o2 other object to compare + * @param optionalCommonSuperClass if supplied, returns false unless both objects are instances of the given type; + * (if not supplied it effectively does duck typing, returning false if any field is not present) + * @param optionalGetter if supplied, a closure which takes (object, field) and returns the value of field on object; + * should return static {@link #NO_SUCH_FIELD} if none found; + * recommended to delegate to {@link #DEFAULT_FIELD_GETTER} at least for strings (or for anything) + * @param fields typically a list of strings being names of fields on the class to compare + * @return true if the two objects are equal in all indicated fields, and conform to the optionalCommonSuperClass if supplied + */ + public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Iterable<Object> fieldNames) { + if (o1==null) return o2==null; + if (o2==null) return false; + if (optionalCommonSuperClass) { + if (!(o1 in optionalCommonSuperClass) || !(o2 in optionalCommonSuperClass)) return false + } + Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER + for (it in fieldNames) { + def v1 = get.call(o1, it) + if (v1==NO_SUCH_FIELD) return false + if (v1!=get.call(o2, it)) return false + } + return true + } + + public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Object[] fieldNames) { + return equals(o1, o2, optionalCommonSuperClass, optionalGetter, Arrays.asList(fieldNames) ) + } + + /** + * Generates a hashcode for an object. + * + * Similar to {@link com.google.common.base.Objects#hashCode()} but taking field <em>names</em> and an optional getter, + * with the same rich groovy semantics as described in {@link #equals(Object, Object, Class)}. + */ + public static int hashCode(Object o, Closure optionalGetter=null, Collection<Object> fieldNames) { + if (o==null) return 0; + Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER + int result = 1; + for (it in fieldNames) { + def v1 = get.call(o, it) + if (v1==NO_SUCH_FIELD) + throw new NoSuchFieldError("Cannot access $it on "+o.getClass()); + result = 31 * result + (it == null ? 0 : it.hashCode()); + } + result + } + + public static int hashCode(Object o, Closure optionalGetter=null, Object[] fieldNames) { + hashCode(o, optionalGetter, Arrays.asList(fieldNames)) + } + + /** Default String representation is simplified name of class, together with selected fields. */ + public static String toString(Object o, Closure optionalGetter=null, Collection<? extends CharSequence> fieldNames) { + if (o==null) return null; + Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER + + StringBuilder result = new StringBuilder(); + result.append(o.getClass().getSimpleName()); + if (result.length() == 0) result.append(o.getClass().getName()); + List<Object> fieldVals = fieldNames.collect { + Object v = get.call(o, it); + return (v != null) ? it+"="+v : null; + } + result.append("[").append(Joiner.on(",").skipNulls().join(fieldVals)).append("]"); + return result.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy new file mode 100644 index 0000000..4bca76f --- /dev/null +++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy @@ -0,0 +1,83 @@ +/* + * 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.util.groovy + +import groovy.time.TimeDuration + +import java.util.concurrent.TimeUnit + +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +import org.apache.brooklyn.util.time.Time + + +/** + * Classloading this class will cause multiply/add to be made available on TimeDuration. + * For example, I could write: 2*TimeUnit.MINUTES+5*TimeUnit.SECONDS. + * + * That is why nothing seems to use this class, because the methods it defines are not + * on this class! + * + * @author alex + * + * @deprecated since 0.6.0 - just use brooklyn.util.time.Duration, simpler and easier to configure, and avoids language problems + */ +@Deprecated +class TimeExtras { + public static final Logger log = LoggerFactory.getLogger(TimeExtras.class); + + public static void init() { + Number.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) } + Number.metaClass.multiply << { TimeDuration t -> t.multiply(doubleValue()) } + Integer.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) } + + TimeDuration.metaClass.multiply << { Number n -> new TimeDuration( (int)(toMilliseconds()*n) ) } + TimeDuration.metaClass.constructor << { long millis -> + def shift = { int modulus -> int v=millis%modulus; millis/=modulus; v } + def l = [shift(1000), shift(60), shift(60), shift(24), (int)millis] + Collections.reverse(l) + l as TimeDuration + } + } + + static { init(); } + + /** creates a duration object + * <p> + * fix for irritating classloading/metaclass order + * where an int may get constructed too early and not have the multiply syntax available + * (because grail is invoked?; if e.g. 5*SECONDS throws an error, try duration(5, SECONDS) */ + public static TimeDuration duration(int value, TimeUnit unit) { + return new TimeDuration(0, 0, 0, (int)unit.toMillis(value)); + } + + public static final TimeDuration ONE_SECOND = duration(1, TimeUnit.SECONDS); + public static final TimeDuration FIVE_SECONDS = duration(5, TimeUnit.SECONDS); + public static final TimeDuration TEN_SECONDS = duration(10, TimeUnit.SECONDS); + public static final TimeDuration THIRTY_SECONDS = duration(30, TimeUnit.SECONDS); + public static final TimeDuration ONE_MINUTE = duration(1, TimeUnit.MINUTES); + public static final TimeDuration TWO_MINUTES = duration(2, TimeUnit.MINUTES); + public static final TimeDuration FIVE_MINUTES = duration(5, TimeUnit.MINUTES); + + public static void sleep(TimeDuration duration) { + Time.sleep(duration.toMilliseconds()); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java ---------------------------------------------------------------------- diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java deleted file mode 100644 index aceef9c..0000000 --- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java +++ /dev/null @@ -1,30 +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 org.apache.brooklyn.util.groovy.internal; - -/** Maven Central requires javadoc to promote as a release. This seemed to happen when this was built by maven as a bundle, - * but now that it is built as a jar it does not. This class exists only to provide that javadoc. - * <p> - * Note the groovy code does javadoc but the maven build is not picking it up. It *is* generated as part of the site build. - */ -public class JavadocDummy { - - private JavadocDummy() {} - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy deleted file mode 100644 index 08bc2fe..0000000 --- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy +++ /dev/null @@ -1,383 +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 org.apache.brooklyn.util.groovy.internal - -import java.lang.reflect.Field -import java.lang.reflect.Method; -import java.lang.reflect.Modifier -import java.util.Collection; -import java.util.concurrent.atomic.AtomicLong - -import org.apache.brooklyn.util.javalang.Reflections; -import org.apache.brooklyn.util.text.Identifiers - -import com.google.common.annotations.Beta -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; - -/** - * Useful Groovy utility methods. - * - * @deprecated since 0.5; requires thorough review for what will be kept. - * e.g. consider instead using guava's {@link com.google.common.collect.Multimap} instead of addToMapOfSets etc - */ -@Deprecated -@Beta -public class LanguageUtils { - // For unique identifiers - private static final AtomicLong seed = new AtomicLong(0L) - - public static <T> T getRequiredField(String name, Map<?,?> m) { - if (!m.containsKey(name)) - throw new IllegalArgumentException("a parameter '"+name+"' was required in the argument to this function") - m.get name - } - - public static <T> T getOptionalField(String name, Map<?,?> m, T defaultValue=null) { - m.get(name) ?: defaultValue - } - - public static <T> T getPropertySafe(Object target, String name, T defaultValue=null) { - target.hasProperty(name)?.getProperty(target) ?: defaultValue - } - - //TODO find with annotation - - public static byte[] serialize(Object orig) { - if (orig == null) return null; - - // Write the object out to a byte array - ByteArrayOutputStream fbos = [] - ObjectOutputStream out = new ObjectOutputStream(fbos); - out.writeObject(orig); - out.flush(); - out.close(); - return fbos.toByteArray(); - } - - public static <T> T deserialize(byte[] bytes, ClassLoader classLoader) { - if (bytes == null) return null; - - ObjectInputStream ins = - //new ObjectInputStreamWithLoader(new FastByteArrayInputStream(bytes, bytes.length), classLoader); - new ObjectInputStream(new ByteArrayInputStream(bytes)); - (T) ins.readObject(); - } - - /** - * @deprecated use Identifiers.makeRandomId(8) - */ - @Deprecated - public static String newUid() { Identifiers.makeRandomId(8) } - - public static Map setFieldsFromMap(Object target, Map fieldValues) { - Map unused = [:] - fieldValues.each { - // println "looking for "+it.key+" in "+target+": "+target.metaClass.hasProperty(it.key) - target.hasProperty(it.key) ? target.(it.key) = it.value : unused << it - } - unused - } - - /** - * Adds the given value to a collection in the map under the key. - * - * A collection (as {@link LinkedHashMap}) will be created if necessary, - * synchronized on map for map access/change and set for addition there - * - * @return the updated set (instance, not copy) - * - * @deprecated since 0.5; use {@link HashMultimap}, and {@link Multimaps#synchronizedSetMultimap(com.google.common.collect.SetMultimap)} - */ - @Deprecated - public static <K,V> Set<V> addToMapOfSets(Map<K,Set<V>> map, K key, V valueInCollection) { - Set<V> coll; - synchronized (map) { - coll = map.get(key) - if (coll==null) { - coll = new LinkedHashSet<V>() - map.put(key, coll) - } - if (coll.isEmpty()) { - synchronized (coll) { - coll.add(valueInCollection) - } - //if collection was empty then add to the collection while holding the map lock, to prevent removal - return coll - } - } - synchronized (coll) { - if (!coll.isEmpty()) { - coll.add(valueInCollection) - return coll; - } - } - //if was empty, recurse, because someone else might be removing the collection - return addToMapOfSets(map, key, valueInCollection); - } - - /** - * as {@link #addToMapOfSets(Map, Object, Object)} but for {@link ArrayList} - * - * @deprecated since 0.5; use {@link ArrayListMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)} - */ - @Deprecated - public static <K,V> List<V> addToMapOfLists(Map<K,List<V>> map, K key, V valueInCollection) { - List<V> coll; - synchronized (map) { - coll = map.get(key) - if (coll==null) { - coll = new ArrayList<V>() - map.put(key, coll) - } - if (coll.isEmpty()) { - synchronized (coll) { - coll.add(valueInCollection) - } - //if collection was empty then add to the collection while holding the map lock, to prevent removal - return coll - } - } - synchronized (coll) { - if (!coll.isEmpty()) { - coll.add(valueInCollection) - return coll; - } - } - //if was empty, recurse, because someone else might be removing the collection - return addToMapOfLists(map, key, valueInCollection); - } - - /** - * Removes the given value from a collection in the map under the key. - * - * @return the updated set (instance, not copy) - * - * @deprecated since 0.5; use {@link ArrayListMultimap} or {@link HashMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)} etc - */ - @Deprecated - public static <K,V> boolean removeFromMapOfCollections(Map<K,? extends Collection<V>> map, K key, V valueInCollection) { - Collection<V> coll; - synchronized (map) { - coll = map.get(key) - if (coll==null) return false; - } - boolean result; - synchronized (coll) { - result = coll.remove(valueInCollection) - } - if (coll.isEmpty()) { - synchronized (map) { - synchronized (coll) { - if (coll.isEmpty()) { - //only remove from the map if no one is adding to the collection or to the map, and the collection is still in the map - if (map.get(key)==coll) { - map.remove(key) - } - } - } - } - } - return result; - } - - /** - * Visits all fields of a given object, recursively. - * - * For collections, arrays, and maps it visits the items within, passing null for keys where it isn't a map. - */ - public static void visitFields(Object o, FieldVisitor fv, Collection<Object> objectsToSkip=([] as Set)) { - if (o == null || objectsToSkip.contains(o)) return - objectsToSkip << o - if (o in String) return - if (o in Map) { - o.each { key, value -> - fv.visit(o, key.toString(), value) - visitFields(value, fv, objectsToSkip) - } - } else if ((o in Collection) || (o.getClass().isArray())) { - o.each { - entry -> - fv.visit(o, null, entry) - visitFields(entry, fv, objectsToSkip) - } - } else { - o.getClass().getDeclaredFields().each { - Field field -> - if ((field.getModifiers() & Modifier.STATIC) || field.isSynthetic()) return; //skip static - field.setAccessible true - def v = field.get(o); - fv.visit(o, field.name, v) - visitFields(v, fv, objectsToSkip) - } - } - } - - public interface FieldVisitor { - /** Invoked by visitFields; fieldName will be null for collections */ - public void visit(Object parent, String fieldName, Object value) - } - - /** - * Iterates through two collections simultaneously, passing both args to code. - * - * <pre> - * a = ['a','b']; b=[1,2]; - * assert ['a1','b2'] == forboth(a,b) { x,y -> x+y } - * </pre> - */ - public static Collection forBoth(Collection l1, Collection l2, Closure code) { - def result=[] - l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) } - result - } - - public static Collection forBothWithIndex(Collection l1, Collection l2, Closure code) { - def result=[] - l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) } - result - } - - public static Collection forBoth(Object[] l1, Object[] l2, Closure code) { - def result=[] - l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) } - result - } - - public static Collection forBothWithIndex(Object[] l1, Object[] l2, Closure code) { - def result=[] - l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) } - result - } - - /** return value used to indicate that there is no such field */ - public static final Object NO_SUCH_FIELD = new Object(); - - /** - * Default field getter. - * - * Delegates to {@code object[field]} (which will invoke a getter if one exists, in groovy), - * unless field starts with {@literal @} in which case it looks up the actual java field (bypassing getter). - * <p> - * Can be extended as needed when passed to {@link #equals(Object, Object, Class, String[])} - */ - public static final Closure DEFAULT_FIELD_GETTER = { Object object, Object field -> - try { - if ((field in String) && field.startsWith("@")) { - return object.@"${field.substring(1)}" - } - return object[field] - } catch (Exception e) { - return NO_SUCH_FIELD - } - } - - /** - * Checks equality of o1 and o2 with respect to the named fields, optionally enforcing a common superclass - * and using a custom field-getter. - * - * Other types can be supplied if they are supported by {@code object[field]} (what the {@link #DEFAULT_FIELD_GETTER} does) - * or if the {@literal optionalGetter} handles it. Note that {@code object[field]} causes invocation of {@code object.getAt(field)} - * (which can be provided on the object for non-strings - this is preferred to an optionalGetter, generally) - * looking for {@code object.getXxx()}, where field is a string {@literal xxx}, then {@code object.xxx}. - * <p> - * One exception is that field names which start with {@literal @} get the field directly according to {@link #DEFAULT_FIELD_GETTER}, - * but use with care on private fields, as they must be on the object and not a superclass, and with groovy properties - * (formerly known as package-private, i.e. with no access modifiers) because they become private fields. - * <p> - * For example - * <pre> - * public class Foo { - * Object bar; - * public boolean equals(Object other) { LangaugeUtils.equals(this, other, Foo.class, ["bar"]); } - * public int hashCode() { LangaugeUtils.hashCode(this, ["bar"]); } - * } - * </pre> - * - * @param o1 one object to compare - * @param o2 other object to compare - * @param optionalCommonSuperClass if supplied, returns false unless both objects are instances of the given type; - * (if not supplied it effectively does duck typing, returning false if any field is not present) - * @param optionalGetter if supplied, a closure which takes (object, field) and returns the value of field on object; - * should return static {@link #NO_SUCH_FIELD} if none found; - * recommended to delegate to {@link #DEFAULT_FIELD_GETTER} at least for strings (or for anything) - * @param fields typically a list of strings being names of fields on the class to compare - * @return true if the two objects are equal in all indicated fields, and conform to the optionalCommonSuperClass if supplied - */ - public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Iterable<Object> fieldNames) { - if (o1==null) return o2==null; - if (o2==null) return false; - if (optionalCommonSuperClass) { - if (!(o1 in optionalCommonSuperClass) || !(o2 in optionalCommonSuperClass)) return false - } - Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER - for (it in fieldNames) { - def v1 = get.call(o1, it) - if (v1==NO_SUCH_FIELD) return false - if (v1!=get.call(o2, it)) return false - } - return true - } - - public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Object[] fieldNames) { - return equals(o1, o2, optionalCommonSuperClass, optionalGetter, Arrays.asList(fieldNames) ) - } - - /** - * Generates a hashcode for an object. - * - * Similar to {@link com.google.common.base.Objects#hashCode()} but taking field <em>names</em> and an optional getter, - * with the same rich groovy semantics as described in {@link #equals(Object, Object, Class)}. - */ - public static int hashCode(Object o, Closure optionalGetter=null, Collection<Object> fieldNames) { - if (o==null) return 0; - Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER - int result = 1; - for (it in fieldNames) { - def v1 = get.call(o, it) - if (v1==NO_SUCH_FIELD) - throw new NoSuchFieldError("Cannot access $it on "+o.getClass()); - result = 31 * result + (it == null ? 0 : it.hashCode()); - } - result - } - - public static int hashCode(Object o, Closure optionalGetter=null, Object[] fieldNames) { - hashCode(o, optionalGetter, Arrays.asList(fieldNames)) - } - - /** Default String representation is simplified name of class, together with selected fields. */ - public static String toString(Object o, Closure optionalGetter=null, Collection<? extends CharSequence> fieldNames) { - if (o==null) return null; - Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER - - StringBuilder result = new StringBuilder(); - result.append(o.getClass().getSimpleName()); - if (result.length() == 0) result.append(o.getClass().getName()); - List<Object> fieldVals = fieldNames.collect { - Object v = get.call(o, it); - return (v != null) ? it+"="+v : null; - } - result.append("[").append(Joiner.on(",").skipNulls().join(fieldVals)).append("]"); - return result.toString(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy deleted file mode 100644 index 9c6cdbd..0000000 --- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy +++ /dev/null @@ -1,83 +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 org.apache.brooklyn.util.groovy.internal - -import groovy.time.TimeDuration - -import java.util.concurrent.TimeUnit - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import org.apache.brooklyn.util.time.Time - - -/** - * Classloading this class will cause multiply/add to be made available on TimeDuration. - * For example, I could write: 2*TimeUnit.MINUTES+5*TimeUnit.SECONDS. - * - * That is why nothing seems to use this class, because the methods it defines are not - * on this class! - * - * @author alex - * - * @deprecated since 0.6.0 - just use brooklyn.util.time.Duration, simpler and easier to configure, and avoids language problems - */ -@Deprecated -class TimeExtras { - public static final Logger log = LoggerFactory.getLogger(TimeExtras.class); - - public static void init() { - Number.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) } - Number.metaClass.multiply << { TimeDuration t -> t.multiply(doubleValue()) } - Integer.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) } - - TimeDuration.metaClass.multiply << { Number n -> new TimeDuration( (int)(toMilliseconds()*n) ) } - TimeDuration.metaClass.constructor << { long millis -> - def shift = { int modulus -> int v=millis%modulus; millis/=modulus; v } - def l = [shift(1000), shift(60), shift(60), shift(24), (int)millis] - Collections.reverse(l) - l as TimeDuration - } - } - - static { init(); } - - /** creates a duration object - * <p> - * fix for irritating classloading/metaclass order - * where an int may get constructed too early and not have the multiply syntax available - * (because grail is invoked?; if e.g. 5*SECONDS throws an error, try duration(5, SECONDS) */ - public static TimeDuration duration(int value, TimeUnit unit) { - return new TimeDuration(0, 0, 0, (int)unit.toMillis(value)); - } - - public static final TimeDuration ONE_SECOND = duration(1, TimeUnit.SECONDS); - public static final TimeDuration FIVE_SECONDS = duration(5, TimeUnit.SECONDS); - public static final TimeDuration TEN_SECONDS = duration(10, TimeUnit.SECONDS); - public static final TimeDuration THIRTY_SECONDS = duration(30, TimeUnit.SECONDS); - public static final TimeDuration ONE_MINUTE = duration(1, TimeUnit.MINUTES); - public static final TimeDuration TWO_MINUTES = duration(2, TimeUnit.MINUTES); - public static final TimeDuration FIVE_MINUTES = duration(5, TimeUnit.MINUTES); - - public static void sleep(TimeDuration duration) { - Time.sleep(duration.toMilliseconds()); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy new file mode 100644 index 0000000..961db5d --- /dev/null +++ b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy @@ -0,0 +1,152 @@ +/* + * 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.util.groovy; + +import static org.testng.Assert.* + +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.testng.annotations.Test +import org.apache.brooklyn.util.groovy.LanguageUtils.FieldVisitor + + +/** + * Test the operation of the {@link LanguageUtils} utilities. + */ +public class LanguageUtilsTest { + private static final Logger log = LoggerFactory.getLogger(LanguageUtilsTest.class) + + @Test + public void testSetFieldsFromMap() { + A a = [] + Map unused = LanguageUtils.setFieldsFromMap(a, [num:1,mun:2]) + assertEquals(1, a.num); + assertEquals([mun:2], unused) + } + + @Test + public void testVisitingFieldsDeepNonLooping() { + BigUn b2 = new BigUn(name:"L'il Guy", num:10, dates:[ new Date() ]) +// b2.dates = [ new Date() ] as Date[] + BigUn b1 = new BigUn(name:"Big Guy", num:40) + b1.child = b2; + b1.children += b2 + b2.child = b1 + + int sum = 0; + FieldVisitor numSummer = { parent, name, value -> if ("num"==name) sum+=value } as FieldVisitor + LanguageUtils.visitFields(b1, numSummer) + + assertEquals(50, sum) + } + + private static class A { + int num; + } + + private static class BigUn { + String name; + int num; + BigUn child; + Set children = [] + Date[] dates; + } + + //test the default getter, and equals + static class TestingFieldA { + public int a = 6; + int getAt(A aa) { return aa.num * a; } + static A aa = [num:10]; + int x = -1; + } + static class TestingFields extends TestingFieldA { + int b = 7; + int getB() { -7 } + public int c = 8; + int getD() { 9 } + } + @Test + public void testSomeGet() { + TestingFields tf = [] + assertEquals( [6, -7, 7, 8, 9, 60], + ["a", "b", "@b", "c", "d", TestingFields.aa].collect { + LanguageUtils.DEFAULT_FIELD_GETTER.call(tf, it) + }) + } + + @Test + public void testEquals() { + //basic + TestingFields t1 = [], t2 = [] + assertTrue LanguageUtils.equals(t1, t2, null, ["a", "b"]) + assertTrue LanguageUtils.equals(t1, t2, TestingFields, ["a", "b"]) + assertFalse LanguageUtils.equals(t1, t2, String, ["a", "b"]) + assertFalse LanguageUtils.equals(t1, t2, null, ["z"]) + assertTrue LanguageUtils.equals(t1, t2, null, (["a", "b"] as String[])) + + //type hierarchy + TestingFieldA t1a = [] + assertTrue LanguageUtils.equals(t1, t1a, null, "a") + assertTrue LanguageUtils.equals(t1, t1a, TestingFieldA, "a") + assertFalse LanguageUtils.equals(t1, t1a, TestingFields, "a") + assertFalse LanguageUtils.equals(t1, t1a, null, "a", "b") + t1.b = 0 + assertTrue LanguageUtils.equals(t1, t1a, null, "a") + t1a.a = -6 + assertFalse LanguageUtils.equals(t1, t1a, null, "a") + + //direct access to field + assertTrue LanguageUtils.equals(t1, t2, null, "b") + assertFalse LanguageUtils.equals(t1, t2, null, "@b") + assertTrue LanguageUtils.equals(t1, t2, null, "@a") + + //and complex field + assertTrue LanguageUtils.equals(t1, t2, null, TestingFields.aa) + //because we changed t1a.a, and getAt(A) refers to int a + assertFalse LanguageUtils.equals(t1, t1a, null, TestingFields.aa) + + //test it works with POJO objects (non-groovy) + assertTrue LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(1), null, "privateInt") + assertFalse LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(2), null, "privateInt") + + //and a tricky one, because x is a groovy property, it is _private_ so we cannot see it as a field wrt t1 + assertFalse LanguageUtils.equals(t1, t1a, null, "@x") + //but in the context of t1a we can.. in short, be careful with fields + assertTrue LanguageUtils.equals(t1a, t1a, null, "@x") + } + + @Test + public void testHashCode() { + //basic + TestingFields t1 = [], t2 = [] + assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"]) + assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"]) + assertFalse LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "@b"]) + t2.b = 0; + assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"]) + assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"]) + assertEquals 0, LanguageUtils.hashCode(null, ["a", "@b"]) + } + + @Test + public void testToString() { + TestingFields t1 = []; + assertEquals(LanguageUtils.toString(t1, ["a", "b"]), "TestingFields[a=6,b=-7]"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java ---------------------------------------------------------------------- diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java new file mode 100644 index 0000000..9bbc3fb --- /dev/null +++ b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java @@ -0,0 +1,28 @@ +/* + * 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.util.groovy; + +public class PojoTestingFields { + private final int privateInt; + + public PojoTestingFields(int privateInt) { + this.privateInt = privateInt; + } +} + http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy new file mode 100644 index 0000000..11ae3d0 --- /dev/null +++ b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy @@ -0,0 +1,49 @@ +/* + * 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.util.groovy; + +import static java.util.concurrent.TimeUnit.* +import static org.testng.Assert.* + +import groovy.time.TimeDuration + +import org.testng.annotations.BeforeMethod +import org.testng.annotations.Test + +/** + * Test the operation of the {@link TimeExtras} class. + * + * TODO clarify test purpose + */ +public class TimeExtrasTest { + @BeforeMethod + public void setUp() throws Exception { + TimeExtras.init(); + } + + @Test + public void testMultiplyTimeDurations() { + assertEquals(new TimeDuration(6).toMilliseconds(), (new TimeDuration(3)*2).toMilliseconds()); + } + + @Test + public void testAddTimeDurations() { + assertEquals(new TimeDuration(0,2,5,0).toMilliseconds(), (5*SECONDS + 2*MINUTES).toMilliseconds()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy deleted file mode 100644 index 8c8d3d2..0000000 --- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy +++ /dev/null @@ -1,153 +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 org.apache.brooklyn.util.groovy.internal; - -import static org.testng.Assert.* - -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.testng.annotations.Test -import org.apache.brooklyn.util.groovy.internal.LanguageUtils; -import org.apache.brooklyn.util.groovy.internal.LanguageUtils.FieldVisitor - - -/** - * Test the operation of the {@link LanguageUtils} utilities. - */ -public class LanguageUtilsTest { - private static final Logger log = LoggerFactory.getLogger(LanguageUtilsTest.class) - - @Test - public void testSetFieldsFromMap() { - A a = [] - Map unused = LanguageUtils.setFieldsFromMap(a, [num:1,mun:2]) - assertEquals(1, a.num); - assertEquals([mun:2], unused) - } - - @Test - public void testVisitingFieldsDeepNonLooping() { - BigUn b2 = new BigUn(name:"L'il Guy", num:10, dates:[ new Date() ]) -// b2.dates = [ new Date() ] as Date[] - BigUn b1 = new BigUn(name:"Big Guy", num:40) - b1.child = b2; - b1.children += b2 - b2.child = b1 - - int sum = 0; - FieldVisitor numSummer = { parent, name, value -> if ("num"==name) sum+=value } as FieldVisitor - LanguageUtils.visitFields(b1, numSummer) - - assertEquals(50, sum) - } - - private static class A { - int num; - } - - private static class BigUn { - String name; - int num; - BigUn child; - Set children = [] - Date[] dates; - } - - //test the default getter, and equals - static class TestingFieldA { - public int a = 6; - int getAt(A aa) { return aa.num * a; } - static A aa = [num:10]; - int x = -1; - } - static class TestingFields extends TestingFieldA { - int b = 7; - int getB() { -7 } - public int c = 8; - int getD() { 9 } - } - @Test - public void testSomeGet() { - TestingFields tf = [] - assertEquals( [6, -7, 7, 8, 9, 60], - ["a", "b", "@b", "c", "d", TestingFields.aa].collect { - LanguageUtils.DEFAULT_FIELD_GETTER.call(tf, it) - }) - } - - @Test - public void testEquals() { - //basic - TestingFields t1 = [], t2 = [] - assertTrue LanguageUtils.equals(t1, t2, null, ["a", "b"]) - assertTrue LanguageUtils.equals(t1, t2, TestingFields, ["a", "b"]) - assertFalse LanguageUtils.equals(t1, t2, String, ["a", "b"]) - assertFalse LanguageUtils.equals(t1, t2, null, ["z"]) - assertTrue LanguageUtils.equals(t1, t2, null, (["a", "b"] as String[])) - - //type hierarchy - TestingFieldA t1a = [] - assertTrue LanguageUtils.equals(t1, t1a, null, "a") - assertTrue LanguageUtils.equals(t1, t1a, TestingFieldA, "a") - assertFalse LanguageUtils.equals(t1, t1a, TestingFields, "a") - assertFalse LanguageUtils.equals(t1, t1a, null, "a", "b") - t1.b = 0 - assertTrue LanguageUtils.equals(t1, t1a, null, "a") - t1a.a = -6 - assertFalse LanguageUtils.equals(t1, t1a, null, "a") - - //direct access to field - assertTrue LanguageUtils.equals(t1, t2, null, "b") - assertFalse LanguageUtils.equals(t1, t2, null, "@b") - assertTrue LanguageUtils.equals(t1, t2, null, "@a") - - //and complex field - assertTrue LanguageUtils.equals(t1, t2, null, TestingFields.aa) - //because we changed t1a.a, and getAt(A) refers to int a - assertFalse LanguageUtils.equals(t1, t1a, null, TestingFields.aa) - - //test it works with POJO objects (non-groovy) - assertTrue LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(1), null, "privateInt") - assertFalse LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(2), null, "privateInt") - - //and a tricky one, because x is a groovy property, it is _private_ so we cannot see it as a field wrt t1 - assertFalse LanguageUtils.equals(t1, t1a, null, "@x") - //but in the context of t1a we can.. in short, be careful with fields - assertTrue LanguageUtils.equals(t1a, t1a, null, "@x") - } - - @Test - public void testHashCode() { - //basic - TestingFields t1 = [], t2 = [] - assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"]) - assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"]) - assertFalse LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "@b"]) - t2.b = 0; - assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"]) - assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"]) - assertEquals 0, LanguageUtils.hashCode(null, ["a", "@b"]) - } - - @Test - public void testToString() { - TestingFields t1 = []; - assertEquals(LanguageUtils.toString(t1, ["a", "b"]), "TestingFields[a=6,b=-7]"); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java ---------------------------------------------------------------------- diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java deleted file mode 100644 index ae5b5a0..0000000 --- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java +++ /dev/null @@ -1,28 +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 org.apache.brooklyn.util.groovy.internal; - -public class PojoTestingFields { - private final int privateInt; - - public PojoTestingFields(int privateInt) { - this.privateInt = privateInt; - } -} - http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy ---------------------------------------------------------------------- diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy deleted file mode 100644 index a5aae79..0000000 --- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy +++ /dev/null @@ -1,51 +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 org.apache.brooklyn.util.groovy.internal; - -import static java.util.concurrent.TimeUnit.* -import static org.testng.Assert.* - -import org.apache.brooklyn.util.groovy.internal.TimeExtras; - -import groovy.time.TimeDuration - -import org.testng.annotations.BeforeMethod -import org.testng.annotations.Test - -/** - * Test the operation of the {@link TimeExtras} class. - * - * TODO clarify test purpose - */ -public class TimeExtrasTest { - @BeforeMethod - public void setUp() throws Exception { - TimeExtras.init(); - } - - @Test - public void testMultiplyTimeDurations() { - assertEquals(new TimeDuration(6).toMilliseconds(), (new TimeDuration(3)*2).toMilliseconds()); - } - - @Test - public void testAddTimeDurations() { - assertEquals(new TimeDuration(0,2,5,0).toMilliseconds(), (5*SECONDS + 2*MINUTES).toMilliseconds()); - } -}
