http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/NodePrinter.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/NodePrinter.java b/src/main/groovy/util/NodePrinter.java deleted file mode 100644 index ca93bc7..0000000 --- a/src/main/groovy/util/NodePrinter.java +++ /dev/null @@ -1,130 +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 groovy.util; - -import org.codehaus.groovy.runtime.InvokerHelper; - -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.util.List; -import java.util.Map; - -/** - * A helper class for creating nested trees of data - * - * @author <a href="mailto:[email protected]">James Strachan</a> - * @author Christian Stein - */ -public class NodePrinter { - - protected final IndentPrinter out; - - public NodePrinter() { - this(new IndentPrinter(new PrintWriter(new OutputStreamWriter(System.out)))); - } - - public NodePrinter(PrintWriter out) { - this(new IndentPrinter(out)); - } - - public NodePrinter(IndentPrinter out) { - if (out == null) { - throw new NullPointerException("IndentPrinter 'out' must not be null!"); - } - this.out = out; - } - - public void print(Node node) { - out.printIndent(); - printName(node); - Map attributes = node.attributes(); - boolean hasAttributes = attributes != null && !attributes.isEmpty(); - if (hasAttributes) { - printAttributes(attributes); - } - Object value = node.value(); - if (value instanceof List) { - if (!hasAttributes) { - out.print("()"); - } - printList((List) value); - } else { - if (value instanceof String) { - out.print("('"); - out.print((String) value); - out.println("')"); - } else { - out.println("()"); - } - } - out.flush(); - } - - protected void printName(Node node) { - Object name = node.name(); - if (name != null) { - out.print(name.toString()); - } else { - out.print("null"); - } - } - - protected void printList(List list) { - if (list.isEmpty()) { - out.println(""); - } else { - out.println(" {"); - out.incrementIndent(); - for (Object value : list) { - if (value instanceof Node) { - print((Node) value); - } else { - out.printIndent(); - out.println(InvokerHelper.toString(value)); - } - } - out.decrementIndent(); - out.printIndent(); - out.println("}"); - } - } - - - protected void printAttributes(Map attributes) { - out.print("("); - boolean first = true; - for (Object o : attributes.entrySet()) { - Map.Entry entry = (Map.Entry) o; - if (first) { - first = false; - } else { - out.print(", "); - } - out.print(entry.getKey().toString()); - out.print(":"); - if (entry.getValue() instanceof String) { - out.print("'" + entry.getValue() + "'"); - } else { - out.print(InvokerHelper.toString(entry.getValue())); - } - } - out.print(")"); - } - -}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/ObjectGraphBuilder.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/ObjectGraphBuilder.java b/src/main/groovy/util/ObjectGraphBuilder.java deleted file mode 100644 index 7ba0089..0000000 --- a/src/main/groovy/util/ObjectGraphBuilder.java +++ /dev/null @@ -1,857 +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 groovy.util; - -import groovy.lang.Closure; -import groovy.lang.GString; -import groovy.lang.MetaProperty; -import groovy.lang.MissingPropertyException; -import org.codehaus.groovy.runtime.InvokerHelper; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * A builder for creating object graphs.<br> - * Each node defines the class to be created and the property on its parent (if - * any) at the same time. - * - * @author Scott Vlaminck (http://refactr.com) - * @author <a href="mailto:[email protected]">Andres Almiray</a> - */ -public class ObjectGraphBuilder extends FactoryBuilderSupport { - public static final String NODE_CLASS = "_NODE_CLASS_"; - public static final String NODE_NAME = "_NODE_NAME_"; - public static final String OBJECT_ID = "_OBJECT_ID_"; - public static final String LAZY_REF = "_LAZY_REF_"; - - public static final String CLASSNAME_RESOLVER_KEY = "name"; - public static final String CLASSNAME_RESOLVER_REFLECTION = "reflection"; - public static final String CLASSNAME_RESOLVER_REFLECTION_ROOT = "root"; - - // Regular expression pattern used to identify words ending in 'y' preceded by a consonant - private static final Pattern PLURAL_IES_PATTERN = Pattern.compile(".*[^aeiouy]y", Pattern.CASE_INSENSITIVE); - - private ChildPropertySetter childPropertySetter; - private ClassNameResolver classNameResolver; - private IdentifierResolver identifierResolver; - private NewInstanceResolver newInstanceResolver; - private final ObjectFactory objectFactory = new ObjectFactory(); - private final ObjectBeanFactory objectBeanFactory = new ObjectBeanFactory(); - private final ObjectRefFactory objectRefFactory = new ObjectRefFactory(); - private ReferenceResolver referenceResolver; - private RelationNameResolver relationNameResolver; - private final Map<String, Class> resolvedClasses = new HashMap<String, Class>(); - private ClassLoader classLoader; - private boolean lazyReferencesAllowed = true; - private final List<NodeReference> lazyReferences = new ArrayList<NodeReference>(); - private String beanFactoryName = "bean"; - - public ObjectGraphBuilder() { - classNameResolver = new DefaultClassNameResolver(); - newInstanceResolver = new DefaultNewInstanceResolver(); - relationNameResolver = new DefaultRelationNameResolver(); - childPropertySetter = new DefaultChildPropertySetter(); - identifierResolver = new DefaultIdentifierResolver(); - referenceResolver = new DefaultReferenceResolver(); - - addPostNodeCompletionDelegate(new Closure(this, this) { - public void doCall(ObjectGraphBuilder builder, Object parent, Object node) { - if (parent == null) { - builder.resolveLazyReferences(); - builder.dispose(); - } - } - }); - } - - /** - * Returns the current name of the 'bean' node. - */ - public String getBeanFactoryName() { - return beanFactoryName; - } - - /** - * Returns the current ChildPropertySetter. - */ - public ChildPropertySetter getChildPropertySetter() { - return childPropertySetter; - } - - /** - * Returns the classLoader used to load a node's class. - */ - public ClassLoader getClassLoader() { - return classLoader; - } - - /** - * Returns the current ClassNameResolver. - */ - public ClassNameResolver getClassNameResolver() { - return classNameResolver; - } - - /** - * Returns the current NewInstanceResolver. - */ - public NewInstanceResolver getNewInstanceResolver() { - return newInstanceResolver; - } - - /** - * Returns the current RelationNameResolver. - */ - public RelationNameResolver getRelationNameResolver() { - return relationNameResolver; - } - - /** - * Returns true if references can be resolved lazily - */ - public boolean isLazyReferencesAllowed() { - return lazyReferencesAllowed; - } - - /** - * Sets the name for the 'bean' node. - */ - public void setBeanFactoryName(String beanFactoryName) { - this.beanFactoryName = beanFactoryName; - } - - /** - * Sets the current ChildPropertySetter.<br> - * It will assign DefaultChildPropertySetter if null.<br> - * It accepts a ChildPropertySetter instance or a Closure. - */ - public void setChildPropertySetter(final Object childPropertySetter) { - if (childPropertySetter instanceof ChildPropertySetter) { - this.childPropertySetter = (ChildPropertySetter) childPropertySetter; - } else if (childPropertySetter instanceof Closure) { - final ObjectGraphBuilder self = this; - this.childPropertySetter = new ChildPropertySetter() { - public void setChild(Object parent, Object child, String parentName, - String propertyName) { - Closure cls = (Closure) childPropertySetter; - cls.setDelegate(self); - cls.call(new Object[]{parent, child, parentName, propertyName}); - } - }; - } else { - this.childPropertySetter = new DefaultChildPropertySetter(); - } - } - - /** - * Sets the classLoader used to load a node's class. - */ - public void setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - /** - * Sets the current ClassNameResolver.<br> - * It will assign DefaultClassNameResolver if null.<br> - * It accepts a ClassNameResolver instance, a String, a Closure or a Map. - */ - public void setClassNameResolver(final Object classNameResolver) { - if (classNameResolver instanceof ClassNameResolver) { - this.classNameResolver = (ClassNameResolver) classNameResolver; - } else if (classNameResolver instanceof String) { - this.classNameResolver = new ClassNameResolver() { - public String resolveClassname(String classname) { - return makeClassName((String) classNameResolver, classname); - } - }; - } else if (classNameResolver instanceof Closure) { - final ObjectGraphBuilder self = this; - this.classNameResolver = new ClassNameResolver() { - public String resolveClassname(String classname) { - Closure cls = (Closure) classNameResolver; - cls.setDelegate(self); - return (String) cls.call(new Object[]{classname}); - } - }; - } else if (classNameResolver instanceof Map) { - Map classNameResolverOptions = (Map) classNameResolver; - - String resolverName = (String) classNameResolverOptions.get(CLASSNAME_RESOLVER_KEY); - - if (resolverName == null) { - throw new RuntimeException("key '" + CLASSNAME_RESOLVER_KEY + "' not defined"); - } - - if (CLASSNAME_RESOLVER_REFLECTION.equals(resolverName)) { - String root = (String) classNameResolverOptions.get(CLASSNAME_RESOLVER_REFLECTION_ROOT); - - if (root == null) { - throw new RuntimeException("key '" + CLASSNAME_RESOLVER_REFLECTION_ROOT + "' not defined"); - } - - this.classNameResolver = new ReflectionClassNameResolver(root); - } else { - throw new RuntimeException("unknown class name resolver " + resolverName); - } - } else { - this.classNameResolver = new DefaultClassNameResolver(); - } - } - - /** - * Sets the current IdentifierResolver.<br> - * It will assign DefaultIdentifierResolver if null.<br> - * It accepts a IdentifierResolver instance, a String or a Closure. - */ - public void setIdentifierResolver(final Object identifierResolver) { - if (identifierResolver instanceof IdentifierResolver) { - this.identifierResolver = (IdentifierResolver) identifierResolver; - } else if (identifierResolver instanceof String) { - this.identifierResolver = new IdentifierResolver() { - public String getIdentifierFor(String nodeName) { - return (String) identifierResolver; - } - }; - } else if (identifierResolver instanceof Closure) { - final ObjectGraphBuilder self = this; - this.identifierResolver = new IdentifierResolver() { - public String getIdentifierFor(String nodeName) { - Closure cls = (Closure) identifierResolver; - cls.setDelegate(self); - return (String) cls.call(new Object[]{nodeName}); - } - }; - } else { - this.identifierResolver = new DefaultIdentifierResolver(); - } - } - - /** - * Sets whether references can be resolved lazily or not. - */ - public void setLazyReferencesAllowed(boolean lazyReferencesAllowed) { - this.lazyReferencesAllowed = lazyReferencesAllowed; - } - - /** - * Sets the current NewInstanceResolver.<br> - * It will assign DefaultNewInstanceResolver if null.<br> - * It accepts a NewInstanceResolver instance or a Closure. - */ - public void setNewInstanceResolver(final Object newInstanceResolver) { - if (newInstanceResolver instanceof NewInstanceResolver) { - this.newInstanceResolver = (NewInstanceResolver) newInstanceResolver; - } else if (newInstanceResolver instanceof Closure) { - final ObjectGraphBuilder self = this; - this.newInstanceResolver = new NewInstanceResolver() { - public Object newInstance(Class klass, Map attributes) - throws InstantiationException, IllegalAccessException { - Closure cls = (Closure) newInstanceResolver; - cls.setDelegate(self); - return cls.call(new Object[]{klass, attributes}); - } - }; - } else { - this.newInstanceResolver = new DefaultNewInstanceResolver(); - } - } - - /** - * Sets the current ReferenceResolver.<br> - * It will assign DefaultReferenceResolver if null.<br> - * It accepts a ReferenceResolver instance, a String or a Closure. - */ - public void setReferenceResolver(final Object referenceResolver) { - if (referenceResolver instanceof ReferenceResolver) { - this.referenceResolver = (ReferenceResolver) referenceResolver; - } else if (referenceResolver instanceof String) { - this.referenceResolver = new ReferenceResolver() { - public String getReferenceFor(String nodeName) { - return (String) referenceResolver; - } - }; - } else if (referenceResolver instanceof Closure) { - final ObjectGraphBuilder self = this; - this.referenceResolver = new ReferenceResolver() { - public String getReferenceFor(String nodeName) { - Closure cls = (Closure) referenceResolver; - cls.setDelegate(self); - return (String) cls.call(new Object[]{nodeName}); - } - }; - } else { - this.referenceResolver = new DefaultReferenceResolver(); - } - } - - /** - * Sets the current RelationNameResolver.<br> - * It will assign DefaultRelationNameResolver if null. - */ - public void setRelationNameResolver(RelationNameResolver relationNameResolver) { - this.relationNameResolver = relationNameResolver != null ? relationNameResolver - : new DefaultRelationNameResolver(); - } - - protected void postInstantiate(Object name, Map attributes, Object node) { - super.postInstantiate(name, attributes, node); - Map context = getContext(); - String objectId = (String) context.get(OBJECT_ID); - if (objectId != null && node != null) { - setVariable(objectId, node); - } - } - - protected void preInstantiate(Object name, Map attributes, Object value) { - super.preInstantiate(name, attributes, value); - Map context = getContext(); - context.put(OBJECT_ID, - attributes.remove(identifierResolver.getIdentifierFor((String) name))); - } - - protected Factory resolveFactory(Object name, Map attributes, Object value) { - // let custom factories be resolved first - Factory factory = super.resolveFactory(name, attributes, value); - if (factory != null) { - return factory; - } - if (attributes.get(referenceResolver.getReferenceFor((String) name)) != null) { - return objectRefFactory; - } - if (beanFactoryName != null && beanFactoryName.equals((String) name)) { - return objectBeanFactory; - } - return objectFactory; - } - - /** - * Strategy for setting a child node on its parent.<br> - * Useful for handling Lists/Arrays vs normal properties. - */ - public interface ChildPropertySetter { - /** - * @param parent the parent's node value - * @param child the child's node value - * @param parentName the name of the parent node - * @param propertyName the resolved relation name of the child - */ - void setChild(Object parent, Object child, String parentName, String propertyName); - } - - /** - * Strategy for resolving a classname. - */ - public interface ClassNameResolver { - /** - * @param classname the node name as written on the building code - */ - String resolveClassname(String classname); - } - - /** - * Default impl that calls parent.propertyName = child<br> - * If parent.propertyName is a Collection it will try to add child to the - * collection. - */ - public static class DefaultChildPropertySetter implements ChildPropertySetter { - public void setChild(Object parent, Object child, String parentName, String propertyName) { - try { - Object property = InvokerHelper.getProperty(parent, propertyName); - if (property != null && Collection.class.isAssignableFrom(property.getClass())) { - ((Collection) property).add(child); - } else { - InvokerHelper.setProperty(parent, propertyName, child); - } - } catch (MissingPropertyException mpe) { - // ignore - } - } - } - - /** - * Default impl that capitalizes the classname. - */ - public static class DefaultClassNameResolver implements ClassNameResolver { - public String resolveClassname(String classname) { - if (classname.length() == 1) { - return classname.toUpperCase(); - } - return classname.substring(0, 1) - .toUpperCase() + classname.substring(1); - } - } - - /** - * Build objects using reflection to resolve class names. - */ - public class ReflectionClassNameResolver implements ClassNameResolver { - private final String root; - - /** - * @param root package where the graph root class is located - */ - public ReflectionClassNameResolver(String root) { - this.root = root; - } - - public String resolveClassname(String classname) { - Object currentNode = getContext().get(CURRENT_NODE); - - if (currentNode == null) { - return makeClassName(root, classname); - } else { - try { - Class klass = currentNode.getClass().getDeclaredField(classname).getType(); - - if (Collection.class.isAssignableFrom(klass)) { - Type type = currentNode.getClass().getDeclaredField(classname).getGenericType(); - if (type instanceof ParameterizedType) { - ParameterizedType ptype = (ParameterizedType) type; - Type[] actualTypeArguments = ptype.getActualTypeArguments(); - if (actualTypeArguments.length != 1) { - throw new RuntimeException("can't determine class name for collection field " + classname + " with multiple generics"); - } - - Type typeArgument = actualTypeArguments[0]; - if (typeArgument instanceof Class) { - klass = (Class) actualTypeArguments[0]; - } else { - throw new RuntimeException("can't instantiate collection field " + classname + " elements as they aren't a class"); - } - } else { - throw new RuntimeException("collection field " + classname + " must be genericised"); - } - } - - return klass.getName(); - } catch (NoSuchFieldException e) { - throw new RuntimeException("can't find field " + classname + " for node class " + currentNode.getClass().getName(), e); - } - } - } - } - - /** - * Default impl, always returns 'id' - */ - public static class DefaultIdentifierResolver implements IdentifierResolver { - public String getIdentifierFor(String nodeName) { - return "id"; - } - } - - /** - * Default impl that calls Class.newInstance() - */ - public static class DefaultNewInstanceResolver implements NewInstanceResolver { - public Object newInstance(Class klass, Map attributes) throws InstantiationException, - IllegalAccessException { - return klass.newInstance(); - } - } - - /** - * Default impl, always returns 'refId' - */ - public static class DefaultReferenceResolver implements ReferenceResolver { - public String getReferenceFor(String nodeName) { - return "refId"; - } - } - - /** - * Default impl that returns parentName and childName accordingly. - */ - public static class DefaultRelationNameResolver implements RelationNameResolver { - /** - * Handles the common English regular plurals with the following rules. - * <ul> - * <li>If childName ends in {consonant}y, replace 'y' with "ies". For example, allergy to allergies.</li> - * <li>Otherwise, append 's'. For example, monkey to monkeys; employee to employees.</li> - * </ul> - * If the property does not exist then it will return childName unchanged. - * - * @see <a href="http://en.wikipedia.org/wiki/English_plural">English_plural</a> - */ - public String resolveChildRelationName(String parentName, Object parent, String childName, - Object child) { - boolean matchesIESRule = PLURAL_IES_PATTERN.matcher(childName).matches(); - String childNamePlural = matchesIESRule ? childName.substring(0, childName.length() - 1) + "ies" : childName + "s"; - - MetaProperty metaProperty = InvokerHelper.getMetaClass(parent) - .hasProperty(parent, childNamePlural); - - return metaProperty != null ? childNamePlural : childName; - } - - /** - * Follow the most conventional pattern, returns the parentName - * unchanged. - */ - public String resolveParentRelationName(String parentName, Object parent, - String childName, Object child) { - return parentName; - } - } - - /** - * Strategy for picking the correct synthetic identifier. - */ - public interface IdentifierResolver { - /** - * Returns the name of the property that will identify the node.<br> - * - * @param nodeName the name of the node - */ - String getIdentifierFor(String nodeName); - } - - /** - * Strategy for creating new instances of a class.<br> - * Useful for plug-in calls to non-default constructors. - */ - public interface NewInstanceResolver { - /** - * Create a new instance of Class klass. - * - * @param klass the resolved class name - * @param attributes the attribute Map available for the node - */ - Object newInstance(Class klass, Map attributes) throws InstantiationException, - IllegalAccessException; - } - - /** - * Strategy for picking the correct synthetic reference identifier. - */ - public interface ReferenceResolver { - /** - * Returns the name of the property that references another node.<br> - * - * @param nodeName the name of the node - */ - String getReferenceFor(String nodeName); - } - - /** - * Strategy for resolving a relationship property name. - */ - public interface RelationNameResolver { - /** - * Returns the mapping name of child -> parent - * - * @param parentName the name of the parent node - * @param parent the parent node - * @param childName the name of the child node - * @param child the child node - */ - String resolveChildRelationName(String parentName, Object parent, String childName, - Object child); - - /** - * Returns the mapping name of parent -> child - * - * @param parentName the name of the parent node - * @param parent the parent node - * @param childName the name of the child node - * @param child the child node - */ - String resolveParentRelationName(String parentName, Object parent, String childName, - Object child); - } - - private void resolveLazyReferences() { - if (!lazyReferencesAllowed) return; - for (NodeReference ref : lazyReferences) { - if (ref.parent == null) continue; - - Object child = null; - try { - child = getProperty(ref.refId); - } catch (MissingPropertyException mpe) { - // ignore - } - if (child == null) { - throw new IllegalArgumentException("There is no valid node for reference " - + ref.parentName + "." + ref.childName + "=" + ref.refId); - } - - // set child first - childPropertySetter.setChild(ref.parent, child, ref.parentName, - relationNameResolver.resolveChildRelationName(ref.parentName, - ref.parent, ref.childName, child)); - - // set parent afterwards - String propertyName = relationNameResolver.resolveParentRelationName(ref.parentName, - ref.parent, ref.childName, child); - MetaProperty metaProperty = InvokerHelper.getMetaClass(child) - .hasProperty(child, propertyName); - if (metaProperty != null) { - metaProperty.setProperty(child, ref.parent); - } - } - } - - private static String makeClassName(String root, String name) { - return root + "." + name.substring(0, 1).toUpperCase() + name.substring(1); - } - - private static class ObjectFactory extends AbstractFactory { - public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, - Map properties) throws InstantiationException, IllegalAccessException { - ObjectGraphBuilder ogbuilder = (ObjectGraphBuilder) builder; - String classname = ogbuilder.classNameResolver.resolveClassname((String) name); - Class klass = resolveClass(builder, classname, name, value, properties); - Map context = builder.getContext(); - context.put(ObjectGraphBuilder.NODE_NAME, name); - context.put(ObjectGraphBuilder.NODE_CLASS, klass); - return resolveInstance(builder, name, value, klass, properties); - } - - protected Class resolveClass(FactoryBuilderSupport builder, String classname, Object name, Object value, - Map properties) { - ObjectGraphBuilder ogbuilder = (ObjectGraphBuilder) builder; - Class klass = ogbuilder.resolvedClasses.get(classname); - if (klass == null) { - klass = loadClass(ogbuilder.classLoader, classname); - if (klass == null) { - klass = loadClass(ogbuilder.getClass().getClassLoader(), classname); - } - if (klass == null) { - try { - klass = Class.forName(classname); - } catch (ClassNotFoundException e) { - // ignore - } - } - if (klass == null) { - klass = loadClass(Thread.currentThread().getContextClassLoader(), classname); - } - if (klass == null) { - throw new RuntimeException(new ClassNotFoundException(classname)); - } - ogbuilder.resolvedClasses.put(classname, klass); - } - - return klass; - } - - protected Object resolveInstance(FactoryBuilderSupport builder, Object name, Object value, Class klass, - Map properties) throws InstantiationException, IllegalAccessException { - ObjectGraphBuilder ogbuilder = (ObjectGraphBuilder) builder; - if (value != null && klass.isAssignableFrom(value.getClass())) { - return value; - } - - return ogbuilder.newInstanceResolver.newInstance(klass, properties); - } - - public void setChild(FactoryBuilderSupport builder, Object parent, Object child) { - if (child == null) return; - - ObjectGraphBuilder ogbuilder = (ObjectGraphBuilder) builder; - if (parent != null) { - Map context = ogbuilder.getContext(); - Map parentContext = ogbuilder.getParentContext(); - - String parentName = null; - String childName = (String) context.get(NODE_NAME); - if (parentContext != null) { - parentName = (String) parentContext.get(NODE_NAME); - } - - String propertyName = ogbuilder.relationNameResolver.resolveParentRelationName( - parentName, parent, childName, child); - MetaProperty metaProperty = InvokerHelper.getMetaClass(child) - .hasProperty(child, propertyName); - if (metaProperty != null) { - metaProperty.setProperty(child, parent); - } - } - } - - public void setParent(FactoryBuilderSupport builder, Object parent, Object child) { - if (child == null) return; - - ObjectGraphBuilder ogbuilder = (ObjectGraphBuilder) builder; - if (parent != null) { - Map context = ogbuilder.getContext(); - Map parentContext = ogbuilder.getParentContext(); - - String parentName = null; - String childName = (String) context.get(NODE_NAME); - if (parentContext != null) { - parentName = (String) parentContext.get(NODE_NAME); - } - - ogbuilder.childPropertySetter.setChild(parent, child, parentName, - ogbuilder.relationNameResolver.resolveChildRelationName(parentName, - parent, childName, child)); - } - } - - protected Class loadClass(ClassLoader classLoader, String classname) { - if (classLoader == null || classname == null) { - return null; - } - try { - return classLoader.loadClass(classname); - } catch (ClassNotFoundException e) { - return null; - } - } - } - - private static class ObjectBeanFactory extends ObjectFactory { - public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, - Map properties) throws InstantiationException, IllegalAccessException { - if(value == null) return super.newInstance(builder, name, value, properties); - - Object bean = null; - Class klass = null; - Map context = builder.getContext(); - if(value instanceof String || value instanceof GString) { - /* - String classname = value.toString(); - klass = resolveClass(builder, classname, name, value, properties); - bean = resolveInstance(builder, name, value, klass, properties); - */ - throw new IllegalArgumentException("ObjectGraphBuilder."+((ObjectGraphBuilder)builder).getBeanFactoryName()+"() does not accept String nor GString as value."); - } else if(value instanceof Class) { - klass = (Class) value; - bean = resolveInstance(builder, name, value, klass, properties); - } else { - klass = value.getClass(); - bean = value; - } - - String nodename = klass.getSimpleName(); - if(nodename.length() > 1) { - nodename = nodename.substring(0, 1).toLowerCase() + nodename.substring(1); - } else { - nodename = nodename.toLowerCase(); - } - context.put(ObjectGraphBuilder.NODE_NAME, nodename); - context.put(ObjectGraphBuilder.NODE_CLASS, klass); - return bean; - } - } - - private static class ObjectRefFactory extends ObjectFactory { - public boolean isLeaf() { - return true; - } - - public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, - Map properties) throws InstantiationException, IllegalAccessException { - ObjectGraphBuilder ogbuilder = (ObjectGraphBuilder) builder; - String refProperty = ogbuilder.referenceResolver.getReferenceFor((String) name); - Object refId = properties.remove(refProperty); - - Object object = null; - Boolean lazy = Boolean.FALSE; - if (refId instanceof String) { - try { - object = ogbuilder.getProperty((String) refId); - } catch (MissingPropertyException mpe) { - // ignore, will try lazy reference - } - if (object == null) { - if (ogbuilder.isLazyReferencesAllowed()) { - lazy = Boolean.TRUE; - } else { - throw new IllegalArgumentException("There is no previous node with " - + ogbuilder.identifierResolver.getIdentifierFor((String) name) + "=" - + refId); - } - } - } else { - // assume we got a true reference to the object - object = refId; - } - - if (!properties.isEmpty()) { - throw new IllegalArgumentException( - "You can not modify the properties of a referenced object."); - } - - Map context = ogbuilder.getContext(); - context.put(ObjectGraphBuilder.NODE_NAME, name); - context.put(ObjectGraphBuilder.LAZY_REF, lazy); - - if (lazy.booleanValue()) { - Map parentContext = ogbuilder.getParentContext(); - - Object parent = null; - String parentName = null; - String childName = (String) name; - if (parentContext != null) { - parent = context.get(CURRENT_NODE); - parentName = (String) parentContext.get(NODE_NAME); - } - ogbuilder.lazyReferences.add(new NodeReference(parent, - parentName, - childName, - (String) refId)); - } else { - context.put(ObjectGraphBuilder.NODE_CLASS, object.getClass()); - } - - return object; - } - - public void setChild(FactoryBuilderSupport builder, Object parent, Object child) { - Boolean lazy = (Boolean) builder.getContext().get(ObjectGraphBuilder.LAZY_REF); - if (!lazy.booleanValue()) super.setChild(builder, parent, child); - } - - public void setParent(FactoryBuilderSupport builder, Object parent, Object child) { - Boolean lazy = (Boolean) builder.getContext().get(ObjectGraphBuilder.LAZY_REF); - if (!lazy.booleanValue()) super.setParent(builder, parent, child); - } - } - - private static final class NodeReference { - private final Object parent; - private final String parentName; - private final String childName; - private final String refId; - - private NodeReference(Object parent, String parentName, String childName, String refId) { - this.parent = parent; - this.parentName = parentName; - this.childName = childName; - this.refId = refId; - } - - public String toString() { - return new StringBuilder().append("[parentName=").append(parentName) - .append(", childName=").append(childName) - .append(", refId=").append(refId) - .append("]").toString(); - } - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/ObservableList.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/ObservableList.java b/src/main/groovy/util/ObservableList.java deleted file mode 100644 index 31b5745..0000000 --- a/src/main/groovy/util/ObservableList.java +++ /dev/null @@ -1,570 +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 groovy.util; - -import groovy.lang.Closure; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; - -/** - * List decorator that will trigger PropertyChangeEvents when a value changes.<br> - * An optional Closure may be specified and will work as a filter, if it returns true the property - * will trigger an event (if the value indeed changed), otherwise it won't. The Closure may receive - * 1 or 2 parameters, the single one being the value, the other one both the key and value, for - * example: - * <pre> - * // skip all properties whose value is a closure - * def map = new ObservableList( {!(it instanceof Closure)} ) - * - * // skip all properties whose name matches a regex - * def map = new ObservableList( { name, value -> !(name =˜ /[A-Z+]/) } ) - * </pre> - * The current implementation will trigger specialized events in the following scenarios, you need - * not register a different listener as those events extend from PropertyChangeEvent - * <ul> - * <li>ObservableList.ElementAddedEvent - a new element is added to the list</li> - * <li>ObservableList.ElementRemovedEvent - an element is removed from the list</li> - * <li>ObservableList.ElementUpdatedEvent - an element changes value (same as regular - * PropertyChangeEvent)</li> - * <li>ObservableList.ElementClearedEvent - all elements have been removed from the list</li> - * <li>ObservableList.MultiElementAddedEvent - triggered by calling list.addAll()</li> - * <li>ObservableList.MultiElementRemovedEvent - triggered by calling - * list.removeAll()/list.retainAll()</li> - * </ul> - * <p> - * <strong>Bound properties</strong> - * <ul> - * <li><tt>content</tt> - read-only.</li> - * <li><tt>size</tt> - read-only.</li> - * </ul> - * - * @author <a href="mailto:[email protected]">Andres Almiray</a> - */ -public class ObservableList implements List { - private final List delegate; - private final PropertyChangeSupport pcs; - private final Closure test; - - public static final String SIZE_PROPERTY = "size"; - public static final String CONTENT_PROPERTY = "content"; - - public ObservableList() { - this(new ArrayList(), null); - } - - public ObservableList(List delegate) { - this(delegate, null); - } - - public ObservableList(Closure test) { - this(new ArrayList(), test); - } - - public ObservableList(List delegate, Closure test) { - this.delegate = delegate; - this.test = test; - pcs = new PropertyChangeSupport(this); - } - - public List getContent() { - return Collections.unmodifiableList(delegate); - } - - protected List getDelegateList() { - return delegate; - } - - protected Closure getTest() { - return test; - } - - protected void fireElementAddedEvent(int index, Object element) { - fireElementEvent(new ElementAddedEvent(this, element, index)); - } - - protected void fireMultiElementAddedEvent(int index, List values) { - fireElementEvent(new MultiElementAddedEvent(this, index, values)); - } - - protected void fireElementClearedEvent(List values) { - fireElementEvent(new ElementClearedEvent(this, values)); - } - - protected void fireElementRemovedEvent(int index, Object element) { - fireElementEvent(new ElementRemovedEvent(this, element, index)); - } - - protected void fireMultiElementRemovedEvent(List values) { - fireElementEvent(new MultiElementRemovedEvent(this, values)); - } - - protected void fireElementUpdatedEvent(int index, Object oldValue, Object newValue) { - fireElementEvent(new ElementUpdatedEvent(this, oldValue, newValue, index)); - } - - protected void fireElementEvent(ElementEvent event) { - pcs.firePropertyChange(event); - } - - protected void fireSizeChangedEvent(int oldValue, int newValue) { - pcs.firePropertyChange(new PropertyChangeEvent(this, SIZE_PROPERTY, oldValue, newValue)); - } - - public void add(int index, Object element) { - int oldSize = size(); - delegate.add(index, element); - fireAddWithTest(element, index, oldSize); - } - - public boolean add(Object o) { - int oldSize = size(); - boolean success = delegate.add(o); - if (success) { - fireAddWithTest(o, oldSize, oldSize); - } - return success; - } - - private void fireAddWithTest(Object element, int index, int oldSize) { - if (test != null) { - Object result = test.call(element); - if (result != null && result instanceof Boolean && (Boolean) result) { - fireElementAddedEvent(index, element); - fireSizeChangedEvent(oldSize, size()); - } - } else { - fireElementAddedEvent(index, element); - fireSizeChangedEvent(oldSize, size()); - } - } - - public boolean addAll(Collection c) { - return addAll(size(), c); - } - - public boolean addAll(int index, Collection c) { - int oldSize = size(); - boolean success = delegate.addAll(index, c); - - if (success && c != null) { - List values = new ArrayList(); - for (Object element : c) { - if (test != null) { - Object result = test.call(element); - if (result != null && result instanceof Boolean && (Boolean) result) { - values.add(element); - } - } else { - values.add(element); - } - } - if (!values.isEmpty()) { - fireMultiElementAddedEvent(index, values); - fireSizeChangedEvent(oldSize, size()); - } - } - - return success; - } - - public void clear() { - int oldSize = size(); - List values = new ArrayList(); - values.addAll(delegate); - delegate.clear(); - if (!values.isEmpty()) { - fireElementClearedEvent(values); - } - fireSizeChangedEvent(oldSize, size()); - } - - public boolean contains(Object o) { - return delegate.contains(o); - } - - public boolean containsAll(Collection c) { - return delegate.containsAll(c); - } - - public boolean equals(Object o) { - return delegate.equals(o); - } - - public Object get(int index) { - return delegate.get(index); - } - - public int hashCode() { - return delegate.hashCode(); - } - - public int indexOf(Object o) { - return delegate.indexOf(o); - } - - public boolean isEmpty() { - return delegate.isEmpty(); - } - - public Iterator iterator() { - return new ObservableIterator(delegate.iterator()); - } - - public int lastIndexOf(Object o) { - return delegate.lastIndexOf(o); - } - - public ListIterator listIterator() { - return new ObservableListIterator(delegate.listIterator(), 0); - } - - public ListIterator listIterator(int index) { - return new ObservableListIterator(delegate.listIterator(index), index); - } - - public Object remove(int index) { - int oldSize = size(); - Object element = delegate.remove(index); - fireElementRemovedEvent(index, element); - fireSizeChangedEvent(oldSize, size()); - return element; - } - - public boolean remove(Object o) { - int oldSize = size(); - int index = delegate.indexOf(o); - boolean success = delegate.remove(o); - if (success) { - fireElementRemovedEvent(index, o); - fireSizeChangedEvent(oldSize, size()); - } - return success; - } - - public boolean removeAll(Collection c) { - if (c == null) { - return false; - } - - List values = new ArrayList(); - // GROOVY-7783 use Sets for O(1) performance for contains - Set delegateSet = new HashSet<Object>(delegate); - if (!(c instanceof Set)) { - c = new HashSet<Object>(c); - } - for (Object element : c) { - if (delegateSet.contains(element)) { - values.add(element); - } - } - - int oldSize = size(); - boolean success = delegate.removeAll(c); - if (success && !values.isEmpty()) { - fireMultiElementRemovedEvent(values); - fireSizeChangedEvent(oldSize, size()); - } - - return success; - } - - public boolean retainAll(Collection c) { - if (c == null) { - return false; - } - - List values = new ArrayList(); - // GROOVY-7783 use Set for O(1) performance for contains - if (!(c instanceof Set)) { - c = new HashSet<Object>(c); - } - for (Object element : delegate) { - if (!c.contains(element)) { - values.add(element); - } - } - - int oldSize = size(); - boolean success = delegate.retainAll(c); - if (success && !values.isEmpty()) { - fireMultiElementRemovedEvent(values); - fireSizeChangedEvent(oldSize, size()); - } - - return success; - } - - public Object set(int index, Object element) { - Object oldValue = delegate.set(index, element); - if (test != null) { - Object result = test.call(element); - if (result != null && result instanceof Boolean && ((Boolean) result).booleanValue()) { - fireElementUpdatedEvent(index, oldValue, element); - } - } else { - fireElementUpdatedEvent(index, oldValue, element); - } - return oldValue; - } - - public int size() { - return delegate.size(); - } - - public int getSize() { - return size(); - } - - public List subList(int fromIndex, int toIndex) { - return delegate.subList(fromIndex, toIndex); - } - - public Object[] toArray() { - return delegate.toArray(); - } - - public Object[] toArray(Object[] a) { - return delegate.toArray(a); - } - - protected class ObservableIterator implements Iterator { - private final Iterator iterDelegate; - protected int cursor = -1 ; - - public ObservableIterator(Iterator iterDelegate) { - this.iterDelegate = iterDelegate; - } - - public Iterator getDelegate() { - return iterDelegate; - } - - public boolean hasNext() { - return iterDelegate.hasNext(); - } - - public Object next() { - cursor++; - return iterDelegate.next(); - } - - public void remove() { - int oldSize = ObservableList.this.size(); - Object element = ObservableList.this.get(cursor); - iterDelegate.remove(); - fireElementRemovedEvent(cursor, element); - fireSizeChangedEvent(oldSize, size()); - cursor--; - } - } - - protected class ObservableListIterator extends ObservableIterator implements ListIterator { - public ObservableListIterator(ListIterator iterDelegate, int index) { - super(iterDelegate); - cursor = index - 1; - } - - public ListIterator getListIterator() { - return (ListIterator) getDelegate(); - } - - public void add(Object o) { - ObservableList.this.add(o); - cursor++; - } - - public boolean hasPrevious() { - return getListIterator().hasPrevious(); - } - - public int nextIndex() { - return getListIterator().nextIndex(); - } - - public Object previous() { - return getListIterator().previous(); - } - - public int previousIndex() { - return getListIterator().previousIndex(); - } - - public void set(Object o) { - ObservableList.this.set(cursor, o); - } - } - - // observable interface - - public void addPropertyChangeListener(PropertyChangeListener listener) { - pcs.addPropertyChangeListener(listener); - } - - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.addPropertyChangeListener(propertyName, listener); - } - - public PropertyChangeListener[] getPropertyChangeListeners() { - return pcs.getPropertyChangeListeners(); - } - - public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { - return pcs.getPropertyChangeListeners(propertyName); - } - - public void removePropertyChangeListener(PropertyChangeListener listener) { - pcs.removePropertyChangeListener(listener); - } - - public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.removePropertyChangeListener(propertyName, listener); - } - - public boolean hasListeners(String propertyName) { - return pcs.hasListeners(propertyName); - } - - public enum ChangeType { - ADDED, UPDATED, REMOVED, CLEARED, MULTI_ADD, MULTI_REMOVE, NONE; - - public static final Object oldValue = new Object(); - public static final Object newValue = new Object(); - - public static ChangeType resolve(int ordinal) { - switch (ordinal) { - case 0: - return ADDED; - case 2: - return REMOVED; - case 3: - return CLEARED; - case 4: - return MULTI_ADD; - case 5: - return MULTI_REMOVE; - case 6: - return NONE; - case 1: - default: - return UPDATED; - } - } - } - - public abstract static class ElementEvent extends PropertyChangeEvent { - - private final ChangeType type; - private final int index; - - public ElementEvent(Object source, Object oldValue, Object newValue, int index, ChangeType type) { - super(source, ObservableList.CONTENT_PROPERTY, oldValue, newValue); - this.type = type; - this.index = index; - } - - public int getIndex() { - return index; - } - - public int getType() { - return type.ordinal(); - } - - public ChangeType getChangeType() { - return type; - } - - public String getTypeAsString() { - return type.name().toUpperCase(); - } - } - - public static class ElementAddedEvent extends ElementEvent { - public ElementAddedEvent(Object source, Object newValue, int index) { - super(source, null, newValue, index, ChangeType.ADDED); - } - } - - public static class ElementUpdatedEvent extends ElementEvent { - public ElementUpdatedEvent(Object source, Object oldValue, Object newValue, int index) { - super(source, oldValue, newValue, index, ChangeType.UPDATED); - } - } - - public static class ElementRemovedEvent extends ElementEvent { - public ElementRemovedEvent(Object source, Object value, int index) { - super(source, value, null, index, ChangeType.REMOVED); - } - } - - public static class ElementClearedEvent extends ElementEvent { - private final List values = new ArrayList(); - - public ElementClearedEvent(Object source, List values) { - super(source, ChangeType.oldValue, ChangeType.newValue, 0, ChangeType.CLEARED); - if (values != null) { - this.values.addAll(values); - } - } - - public List getValues() { - return Collections.unmodifiableList(values); - } - } - - public static class MultiElementAddedEvent extends ElementEvent { - private final List values = new ArrayList(); - - public MultiElementAddedEvent(Object source, int index, List values) { - super(source, ChangeType.oldValue, ChangeType.newValue, index, ChangeType.MULTI_ADD); - if (values != null) { - this.values.addAll(values); - } - } - - public List getValues() { - return Collections.unmodifiableList(values); - } - } - - public static class MultiElementRemovedEvent extends ElementEvent { - private final List values = new ArrayList(); - - public MultiElementRemovedEvent(Object source, List values) { - super(source, ChangeType.oldValue, ChangeType.newValue, 0, ChangeType.MULTI_REMOVE); - if (values != null) { - this.values.addAll(values); - } - } - - public List getValues() { - return Collections.unmodifiableList(values); - } - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/ObservableMap.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/ObservableMap.java b/src/main/groovy/util/ObservableMap.java deleted file mode 100644 index 43dc7a0..0000000 --- a/src/main/groovy/util/ObservableMap.java +++ /dev/null @@ -1,410 +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 groovy.util; - -import groovy.lang.Closure; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Map decorator that will trigger PropertyChangeEvents when a value changes.<br> - * An optional Closure may be specified and will work as a filter, if it returns - * true the property will trigger an event (if the value indeed changed), - * otherwise it won't. The Closure may receive 1 or 2 parameters, the single one - * being the value, the other one both the key and value, for example: - * <pre> - * // skip all properties whose value is a closure - * def map = new ObservableMap( {!(it instanceof Closure)} ) - * - * // skip all properties whose name matches a regex - * def map = new ObservableMap( { name, value -> !(name =~ /[A-Z+]/) } ) - * </pre> - * The current implementation will trigger specialized events in the following scenarios, - * you need not register a different listener as those events extend from PropertyChangeEvent - * <ul> - * <li>ObservableMap.PropertyAddedEvent - a new property is added to the map</li> - * <li>ObservableMap.PropertyRemovedEvent - a property is removed from the map</li> - * <li>ObservableMap.PropertyUpdatedEvent - a property changes value (same as regular PropertyChangeEvent)</li> - * <li>ObservableMap.PropertyClearedEvent - all properties have been removed from the map</li> - * <li>ObservableMap.MultiPropertyEvent - triggered by calling map.putAll(), contains Added|Updated events</li> - * </ul> - * <p> - * <strong>Bound properties</strong> - * <ul> - * <li><tt>content</tt> - read-only.</li> - * <li><tt>size</tt> - read-only.</li> - * </ul> - * - * @author <a href="mailto:[email protected]">Andres Almiray</a> - */ -public class ObservableMap implements Map { - private final Map delegate; - private final PropertyChangeSupport pcs; - private final Closure test; - - public static final String SIZE_PROPERTY = "size"; - public static final String CONTENT_PROPERTY = "content"; - public static final String CLEARED_PROPERTY = "cleared"; - - public ObservableMap() { - this(new LinkedHashMap(), null); - } - - public ObservableMap(Closure test) { - this(new LinkedHashMap(), test); - } - - public ObservableMap(Map delegate) { - this(delegate, null); - } - - public ObservableMap(Map delegate, Closure test) { - this.delegate = delegate; - this.test = test; - pcs = new PropertyChangeSupport(this); - } - - protected Map getMapDelegate() { - return delegate; - } - - protected Closure getTest() { - return test; - } - - public Map getContent() { - return Collections.unmodifiableMap(delegate); - } - - protected void firePropertyClearedEvent(Map values) { - firePropertyEvent(new PropertyClearedEvent(this, values)); - } - - protected void firePropertyAddedEvent(Object key, Object value) { - firePropertyEvent(new PropertyAddedEvent(this, String.valueOf(key), value)); - } - - protected void firePropertyUpdatedEvent(Object key, Object oldValue, Object newValue) { - firePropertyEvent(new PropertyUpdatedEvent(this, String.valueOf(key), oldValue, newValue)); - } - - protected void fireMultiPropertyEvent(List<PropertyEvent> events) { - firePropertyEvent(new MultiPropertyEvent(this, (PropertyEvent[]) events.toArray(new PropertyEvent[events.size()]))); - } - - protected void fireMultiPropertyEvent(PropertyEvent[] events) { - firePropertyEvent(new MultiPropertyEvent(this, events)); - } - - protected void firePropertyRemovedEvent(Object key, Object value) { - firePropertyEvent(new PropertyRemovedEvent(this, String.valueOf(key), value)); - } - - protected void firePropertyEvent(PropertyEvent event) { - pcs.firePropertyChange(event); - } - - protected void fireSizeChangedEvent(int oldValue, int newValue) { - pcs.firePropertyChange(new PropertyChangeEvent(this, SIZE_PROPERTY, oldValue, newValue)); - } - - // Map interface - - public void clear() { - int oldSize = size(); - Map values = new HashMap(); - if (!delegate.isEmpty()) { - values.putAll(delegate); - } - delegate.clear(); - firePropertyClearedEvent(values); - fireSizeChangedEvent(oldSize, size()); - } - - public boolean containsKey(Object key) { - return delegate.containsKey(key); - } - - public boolean containsValue(Object value) { - return delegate.containsValue(value); - } - - public Set entrySet() { - return delegate.entrySet(); - } - - public boolean equals(Object o) { - return delegate.equals(o); - } - - public Object get(Object key) { - return delegate.get(key); - } - - public int hashCode() { - return delegate.hashCode(); - } - - public boolean isEmpty() { - return delegate.isEmpty(); - } - - public Set keySet() { - return delegate.keySet(); - } - - public Object put(Object key, Object value) { - int oldSize = size(); - Object oldValue = null; - boolean newKey = !delegate.containsKey(key); - if (test != null) { - oldValue = delegate.put(key, value); - Object result = null; - if (test.getMaximumNumberOfParameters() == 2) { - result = test.call(new Object[]{key, value}); - } else { - result = test.call(value); - } - if (result != null && result instanceof Boolean && (Boolean) result) { - if (newKey) { - firePropertyAddedEvent(key, value); - fireSizeChangedEvent(oldSize, size()); - } else if (oldValue != value) { - firePropertyUpdatedEvent(key, oldValue, value); - } - } - } else { - oldValue = delegate.put(key, value); - if (newKey) { - firePropertyAddedEvent(key, value); - fireSizeChangedEvent(oldSize, size()); - } else if (oldValue != value) { - firePropertyUpdatedEvent(key, oldValue, value); - } - } - return oldValue; - } - - public void putAll(Map map) { - int oldSize = size(); - if (map != null) { - List<PropertyEvent> events = new ArrayList<PropertyEvent>(); - for (Object o : map.entrySet()) { - Entry entry = (Entry) o; - - String key = String.valueOf(entry.getKey()); - Object newValue = entry.getValue(); - Object oldValue = null; - - boolean newKey = !delegate.containsKey(key); - if (test != null) { - oldValue = delegate.put(key, newValue); - Object result = null; - if (test.getMaximumNumberOfParameters() == 2) { - result = test.call(new Object[]{key, newValue}); - } else { - result = test.call(newValue); - } - if (result != null && result instanceof Boolean && (Boolean) result) { - if (newKey) { - events.add(new PropertyAddedEvent(this, key, newValue)); - } else if (oldValue != newValue) { - events.add(new PropertyUpdatedEvent(this, key, oldValue, newValue)); - } - } - } else { - oldValue = delegate.put(key, newValue); - if (newKey) { - events.add(new PropertyAddedEvent(this, key, newValue)); - } else if (oldValue != newValue) { - events.add(new PropertyUpdatedEvent(this, key, oldValue, newValue)); - } - } - } - if (!events.isEmpty()) { - fireMultiPropertyEvent(events); - fireSizeChangedEvent(oldSize, size()); - } - } - } - - public Object remove(Object key) { - int oldSize = size(); - Object result = delegate.remove(key); - if (key != null) { - firePropertyRemovedEvent(key, result); - fireSizeChangedEvent(oldSize, size()); - } - return result; - } - - public int size() { - return delegate.size(); - } - - public int getSize() { - return size(); - } - - public Collection values() { - return delegate.values(); - } - - // observable interface - - public void addPropertyChangeListener(PropertyChangeListener listener) { - pcs.addPropertyChangeListener(listener); - } - - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.addPropertyChangeListener(propertyName, listener); - } - - public PropertyChangeListener[] getPropertyChangeListeners() { - return pcs.getPropertyChangeListeners(); - } - - public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { - return pcs.getPropertyChangeListeners(propertyName); - } - - public void removePropertyChangeListener(PropertyChangeListener listener) { - pcs.removePropertyChangeListener(listener); - } - - public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.removePropertyChangeListener(propertyName, listener); - } - - public boolean hasListeners(String propertyName) { - return pcs.hasListeners(propertyName); - } - - public enum ChangeType { - ADDED, UPDATED, REMOVED, CLEARED, MULTI, NONE; - - public static final Object oldValue = new Object(); - public static final Object newValue = new Object(); - - public static ChangeType resolve(int ordinal) { - switch (ordinal) { - case 0: - return ADDED; - case 2: - return REMOVED; - case 3: - return CLEARED; - case 4: - return MULTI; - case 5: - return NONE; - case 1: - default: - return UPDATED; - } - } - } - - public abstract static class PropertyEvent extends PropertyChangeEvent { - private final ChangeType type; - - public PropertyEvent(Object source, String propertyName, Object oldValue, Object newValue, ChangeType type) { - super(source, propertyName, oldValue, newValue); - this.type = type; - } - - public int getType() { - return type.ordinal(); - } - - public ChangeType getChangeType() { - return type; - } - - public String getTypeAsString() { - return type.name().toUpperCase(); - } - } - - public static class PropertyAddedEvent extends PropertyEvent { - public PropertyAddedEvent(Object source, String propertyName, Object newValue) { - super(source, propertyName, null, newValue, ChangeType.ADDED); - } - } - - public static class PropertyUpdatedEvent extends PropertyEvent { - public PropertyUpdatedEvent(Object source, String propertyName, Object oldValue, Object newValue) { - super(source, propertyName, oldValue, newValue, ChangeType.UPDATED); - } - } - - public static class PropertyRemovedEvent extends PropertyEvent { - public PropertyRemovedEvent(Object source, String propertyName, Object oldValue) { - super(source, propertyName, oldValue, null, ChangeType.REMOVED); - } - } - - public static class PropertyClearedEvent extends PropertyEvent { - private final Map values = new HashMap(); - - public PropertyClearedEvent(Object source, Map values) { - super(source, ObservableMap.CLEARED_PROPERTY, values, null, ChangeType.CLEARED); - if (values != null) { - this.values.putAll(values); - } - } - - public Map getValues() { - return Collections.unmodifiableMap(values); - } - } - - public static class MultiPropertyEvent extends PropertyEvent { - public static final String MULTI_PROPERTY = "groovy_util_ObservableMap_MultiPropertyEvent_MULTI"; - private static final PropertyEvent[] EMPTY_PROPERTY_EVENTS = new PropertyEvent[0]; - - private final PropertyEvent[] events; - - public MultiPropertyEvent(Object source, PropertyEvent[] events) { - super(source, MULTI_PROPERTY, ChangeType.oldValue, ChangeType.newValue, ChangeType.MULTI); - if (events != null && events.length > 0) { - this.events = new PropertyEvent[events.length]; - System.arraycopy(events, 0, this.events, 0, events.length); - } else { - this.events = EMPTY_PROPERTY_EVENTS; - } - } - - public PropertyEvent[] getEvents() { - PropertyEvent[] copy = new PropertyEvent[events.length]; - System.arraycopy(events, 0, copy, 0, events.length); - return copy; - } - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/ObservableSet.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/ObservableSet.java b/src/main/groovy/util/ObservableSet.java deleted file mode 100644 index b794436..0000000 --- a/src/main/groovy/util/ObservableSet.java +++ /dev/null @@ -1,427 +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 groovy.util; - -import groovy.lang.Closure; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.Stack; - -/** - * Set decorator that will trigger PropertyChangeEvents when a value changes.<br> - * An optional Closure may be specified and will work as a filter, if it returns true the property - * will trigger an event (if the value indeed changed), otherwise it won't. The Closure may receive - * 1 or 2 parameters, the single one being the value, the other one both the key and value, for - * example: - * <pre> - * // skip all properties whose value is a closure - * def set = new ObservableSet( {!(it instanceof Closure)} ) - * <p/> - * // skip all properties whose name matches a regex - * def set = new ObservableSet( { name, value -> !(name =˜ /[A-Z+]/) } ) - * </pre> - * The current implementation will trigger specialized events in the following scenarios, you need - * not register a different listener as those events extend from PropertyChangeEvent - * <ul> - * <li>ObservableSet.ElementAddedEvent - a new element is added to the set</li> - * <li>ObservableSet.ElementRemovedEvent - an element is removed from the set</li> - * <li>ObservableSet.ElementUpdatedEvent - an element changes value (same as regular - * PropertyChangeEvent)</li> - * <li>ObservableSet.ElementClearedEvent - all elements have been removed from the list</li> - * <li>ObservableSet.MultiElementAddedEvent - triggered by calling set.addAll()</li> - * <li>ObservableSet.MultiElementRemovedEvent - triggered by calling - * set.removeAll()/set.retainAll()</li> - * </ul> - * - * <p> - * <strong>Bound properties</strong> - * <ul> - * <li><tt>content</tt> - read-only.</li> - * <li><tt>size</tt> - read-only.</li> - * </ul> - * - * @author <a href="mailto:[email protected]">Andres Almiray</a> - */ -public class ObservableSet<E> implements Set<E> { - private final Set<E> delegate; - private final PropertyChangeSupport pcs; - private final Closure test; - - public static final String SIZE_PROPERTY = "size"; - public static final String CONTENT_PROPERTY = "content"; - - public ObservableSet() { - this(new HashSet<E>(), null); - } - - public ObservableSet(Set<E> delegate) { - this(delegate, null); - } - - public ObservableSet(Closure test) { - this(new HashSet<E>(), test); - } - - public ObservableSet(Set<E> delegate, Closure test) { - this.delegate = delegate; - this.test = test; - this.pcs = new PropertyChangeSupport(this); - } - - public Set<E> getContent() { - return Collections.unmodifiableSet(delegate); - } - - protected Set<E> getDelegateSet() { - return delegate; - } - - protected Closure getTest() { - return test; - } - - protected void fireElementAddedEvent(Object element) { - fireElementEvent(new ElementAddedEvent(this, element)); - } - - protected void fireMultiElementAddedEvent(List values) { - fireElementEvent(new MultiElementAddedEvent(this, values)); - } - - protected void fireElementClearedEvent(List values) { - fireElementEvent(new ElementClearedEvent(this, values)); - } - - protected void fireElementRemovedEvent(Object element) { - fireElementEvent(new ElementRemovedEvent(this, element)); - } - - protected void fireMultiElementRemovedEvent(List values) { - fireElementEvent(new MultiElementRemovedEvent(this, values)); - } - - protected void fireElementEvent(ElementEvent event) { - pcs.firePropertyChange(event); - } - - protected void fireSizeChangedEvent(int oldValue, int newValue) { - pcs.firePropertyChange(new PropertyChangeEvent(this, SIZE_PROPERTY, oldValue, newValue)); - } - - // observable interface - - public void addPropertyChangeListener(PropertyChangeListener listener) { - pcs.addPropertyChangeListener(listener); - } - - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.addPropertyChangeListener(propertyName, listener); - } - - public PropertyChangeListener[] getPropertyChangeListeners() { - return pcs.getPropertyChangeListeners(); - } - - public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { - return pcs.getPropertyChangeListeners(propertyName); - } - - public void removePropertyChangeListener(PropertyChangeListener listener) { - pcs.removePropertyChangeListener(listener); - } - - public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.removePropertyChangeListener(propertyName, listener); - } - - public boolean hasListeners(String propertyName) { - return pcs.hasListeners(propertyName); - } - - public int size() { - return delegate.size(); - } - - public boolean isEmpty() { - return delegate.isEmpty(); - } - - public boolean contains(Object o) { - return delegate.contains(o); - } - - public Iterator<E> iterator() { - return new ObservableIterator<E>(delegate.iterator()); - } - - public Object[] toArray() { - return delegate.toArray(); - } - - public <T> T[] toArray(T[] ts) { - return (T[]) delegate.toArray(ts); - } - - public boolean add(E e) { - int oldSize = size(); - boolean success = delegate.add(e); - if (success) { - if (test != null) { - Object result = test.call(e); - if (result != null && result instanceof Boolean && (Boolean) result) { - fireElementAddedEvent(e); - fireSizeChangedEvent(oldSize, size()); - } - } else { - fireElementAddedEvent(e); - fireSizeChangedEvent(oldSize, size()); - } - } - return success; - } - - public boolean remove(Object o) { - int oldSize = size(); - boolean success = delegate.remove(o); - if (success) { - fireElementRemovedEvent(o); - fireSizeChangedEvent(oldSize, size()); - } - return success; - } - - public boolean containsAll(Collection<?> objects) { - return delegate.containsAll(objects); - } - - public boolean addAll(Collection<? extends E> c) { - Set<E> duplicates = new HashSet<E>(); - if (null != c) { - for (E e : c) { - if (!delegate.contains(e)) continue; - duplicates.add(e); - } - } - - int oldSize = size(); - boolean success = delegate.addAll(c); - - if (success && c != null) { - List<E> values = new ArrayList<E>(); - for (E element : c) { - if (test != null) { - Object result = test.call(element); - if (result != null && result instanceof Boolean && (Boolean) result && !duplicates.contains(element)) { - values.add(element); - } - } else if (!duplicates.contains(element)) { - values.add(element); - } - } - if (!values.isEmpty()) { - fireMultiElementAddedEvent(values); - fireSizeChangedEvent(oldSize, size()); - } - } - - return success; - } - - public boolean retainAll(Collection<?> c) { - if (c == null) { - return false; - } - - List values = new ArrayList(); - // GROOVY-7822 use Set for O(1) performance for contains - if (!(c instanceof Set)) { - c = new HashSet<Object>(c); - } - for (Object element : delegate) { - if (!c.contains(element)) { - values.add(element); - } - } - - int oldSize = size(); - boolean success = delegate.retainAll(c); - if (success && !values.isEmpty()) { - fireMultiElementRemovedEvent(values); - fireSizeChangedEvent(oldSize, size()); - } - - return success; - } - - public boolean removeAll(Collection<?> c) { - if (c == null) { - return false; - } - - List values = new ArrayList(); - for (Object element : c) { - if (delegate.contains(element)) { - values.add(element); - } - } - - int oldSize = size(); - boolean success = delegate.removeAll(c); - if (success && !values.isEmpty()) { - fireMultiElementRemovedEvent(values); - fireSizeChangedEvent(oldSize, size()); - } - - return success; - } - - public void clear() { - int oldSize = size(); - List<E> values = new ArrayList<E>(); - values.addAll(delegate); - delegate.clear(); - if (!values.isEmpty()) { - fireElementClearedEvent(values); - } - fireSizeChangedEvent(oldSize, size()); - } - - protected class ObservableIterator<E> implements Iterator<E> { - private final Iterator<E> iterDelegate; - private final Stack<E> stack = new Stack<E>(); - - public ObservableIterator(Iterator<E> iterDelegate) { - this.iterDelegate = iterDelegate; - } - - public Iterator<E> getDelegate() { - return iterDelegate; - } - - public boolean hasNext() { - return iterDelegate.hasNext(); - } - - public E next() { - stack.push(iterDelegate.next()); - return stack.peek(); - } - - public void remove() { - int oldSize = ObservableSet.this.size(); - iterDelegate.remove(); - fireElementRemovedEvent(stack.pop()); - fireSizeChangedEvent(oldSize, size()); - } - } - - public enum ChangeType { - ADDED, REMOVED, CLEARED, MULTI_ADD, MULTI_REMOVE, NONE; - - public static final Object oldValue = new Object(); - public static final Object newValue = new Object(); - } - - public abstract static class ElementEvent extends PropertyChangeEvent { - private final ChangeType type; - - public ElementEvent(Object source, Object oldValue, Object newValue, ChangeType type) { - super(source, ObservableSet.CONTENT_PROPERTY, oldValue, newValue); - this.type = type; - } - - public int getType() { - return type.ordinal(); - } - - public ChangeType getChangeType() { - return type; - } - - public String getTypeAsString() { - return type.name().toUpperCase(); - } - } - - public static class ElementAddedEvent extends ElementEvent { - public ElementAddedEvent(Object source, Object newValue) { - super(source, null, newValue, ChangeType.ADDED); - } - } - - public static class ElementRemovedEvent extends ElementEvent { - public ElementRemovedEvent(Object source, Object value) { - super(source, value, null, ChangeType.REMOVED); - } - } - - public static class ElementClearedEvent extends ElementEvent { - private final List values = new ArrayList(); - - public ElementClearedEvent(Object source, List values) { - super(source, ChangeType.oldValue, ChangeType.newValue, ChangeType.CLEARED); - if (values != null) { - this.values.addAll(values); - } - } - - public List getValues() { - return Collections.unmodifiableList(values); - } - } - - public static class MultiElementAddedEvent extends ElementEvent { - private final List values = new ArrayList(); - - public MultiElementAddedEvent(Object source, List values) { - super(source, ChangeType.oldValue, ChangeType.newValue, ChangeType.MULTI_ADD); - if (values != null) { - this.values.addAll(values); - } - } - - public List getValues() { - return Collections.unmodifiableList(values); - } - } - - public static class MultiElementRemovedEvent extends ElementEvent { - private final List values = new ArrayList(); - - public MultiElementRemovedEvent(Object source, List values) { - super(source, ChangeType.oldValue, ChangeType.newValue, ChangeType.MULTI_REMOVE); - if (values != null) { - this.values.addAll(values); - } - } - - public List getValues() { - return Collections.unmodifiableList(values); - } - } -}
