You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2005/10/03 16:10:51 UTC

svn commit: r293356 - in /cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms: formmodel/AbstractContainerWidget.java formmodel/WidgetList.java util/ContainerWidgetAsMap.java util/RepeaterAsList.java

Author: sylvain
Date: Mon Oct  3 07:10:45 2005
New Revision: 293356

URL: http://svn.apache.org/viewcvs?rev=293356&view=rev
Log:
Add Map and List wrappers around widgets to ease binding with JDBI

Added:
    cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/ContainerWidgetAsMap.java   (with props)
    cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/RepeaterAsList.java   (with props)
Modified:
    cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerWidget.java
    cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/WidgetList.java

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerWidget.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerWidget.java?rev=293356&r1=293355&r2=293356&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerWidget.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerWidget.java Mon Oct  3 07:10:45 2005
@@ -79,7 +79,11 @@
     public Iterator getChildren() {
         return widgets.iterator();
     }
-
+    
+    public int getSize() {
+        return widgets.getWidgetList().size();
+    }
+    
     /**
      * Delegates the readFromRequest() down to the contained child-widgets.
      *
@@ -131,6 +135,5 @@
         if (getCombinedState().isDisplayingValues()) {
             widgets.generateSaxFragment(contentHandler, locale);
         }
-    }    
-    
+    }
 }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/WidgetList.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/WidgetList.java?rev=293356&r1=293355&r2=293356&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/WidgetList.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/WidgetList.java Mon Oct  3 07:10:45 2005
@@ -16,6 +16,7 @@
 package org.apache.cocoon.forms.formmodel;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -59,6 +60,24 @@
     public WidgetList() {
         widgets = new ArrayList();
         widgetsById = new HashMap();
+    }
+
+    /**
+     * Get the (unmodifiable) list of widgets
+     * 
+     * @return the widget list
+     */
+    public List getWidgetList() {
+        return Collections.unmodifiableList(this.widgets);
+    }
+    
+    /**
+     * Get the (unmodifiable) map of widgets
+     * 
+     * @return the widget map
+     */
+    public Map getWidgetMap() {
+        return Collections.unmodifiableMap(this.widgetsById);
     }
 
     /** 

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/ContainerWidgetAsMap.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/ContainerWidgetAsMap.java?rev=293356&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/ContainerWidgetAsMap.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/ContainerWidgetAsMap.java Mon Oct  3 07:10:45 2005
@@ -0,0 +1,172 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.cocoon.forms.util;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cocoon.forms.formmodel.AbstractContainerWidget;
+import org.apache.cocoon.forms.formmodel.Repeater;
+import org.apache.cocoon.forms.formmodel.Widget;
+import org.apache.commons.collections.iterators.AbstractIteratorDecorator;
+
+/**
+ * A <code>Map</code> view of a container widget, keys being children names and values either
+ * maps (for container children), objects (for terminal children) or lists (for repeaters).
+ * <p>
+ * The returned map is non-modifiable, except using the <code>put()</code> method, which much
+ * refer to an existing child widget, and <code>putAll(Map)</code> that will silently ignore keys
+ * that don't refer to existing child widgets.
+ * 
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class ContainerWidgetAsMap extends AbstractMap {
+    private AbstractContainerWidget container;
+    private boolean lowerCase;
+
+    /**
+     * Wraps a container widget in a <code>Map</code>.
+     * <p>
+     * The <code>keysToLowerCase</code> argument specifies if input keys given in <code>get()</code>,
+     * <code>put()</code> and <code>putAll()</code> should be converted to lower case before searching for
+     * the corresponding widget. This feature allows to directly feed widgets with <code>Map</code>s coming
+     * from JDBC resultset rows where keys are uppercase (see <a href="http://jdbi.codehaus.org">JDBI</a>).
+     * 
+     * @param container the container to wrap
+     * @param keysToLowerCase should we convert keys to lower case?
+     */
+    public ContainerWidgetAsMap(AbstractContainerWidget container, boolean keysToLowerCase) {
+        this.container = container;
+        this.lowerCase = keysToLowerCase;
+    }
+
+    /**
+     * Same as <code>ContainerWidgetAsMap(container, true)</code>
+     */
+    public ContainerWidgetAsMap(AbstractContainerWidget container) {
+        this(container, true);
+    }
+
+    public Object put(Object key, Object value) {
+        String name = (String)key;
+        if (lowerCase) name = name.toLowerCase();
+        
+        Widget w = container.getChild(name);
+        if (w != null) {
+            Object result = w.getValue();
+            setValue(w, value);
+            return result;
+        } else {
+            throw new UnsupportedOperationException(container + " has no child named '" + key + "'");
+        }
+    }
+    
+    public void putAll(Map map) {
+        Iterator iter = map.entrySet().iterator();
+        while(iter.hasNext()) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            String name = (String)entry.getKey();
+            if (lowerCase) name = name.toLowerCase();
+            Widget w = container.getChild(name);
+            if (w != null) {
+                setValue(w, entry.getValue());
+            }
+        }
+    }
+    
+    public Object get(Object key) {
+        String name = (String)key;
+        if (lowerCase) name = name.toLowerCase();
+        Widget w = container.getChild(name);
+        return w == null ? null : asValueOrMap(w);
+    }
+
+    public Set entrySet() {
+        return new ContainerEntrySet();
+    }
+    
+    private Object asValueOrMap(Widget w) {
+        if (w instanceof Repeater) {
+            return new RepeaterAsList((Repeater)w, lowerCase);
+        } else if (w instanceof AbstractContainerWidget) {
+            return new ContainerWidgetAsMap((AbstractContainerWidget)w, lowerCase);
+        } else {
+            return w.getValue();
+        }
+    }
+    
+    private void setValue(Widget w, Object value) {
+        if (w instanceof Repeater) {
+            // Must be a collection
+            if (!(value instanceof Collection)) {
+                throw new IllegalArgumentException("A repeater cannot be filled with " + value);
+            }
+            new RepeaterAsList((Repeater)w, lowerCase).addAll((Collection)value);
+
+        } else if (w instanceof AbstractContainerWidget) {
+            // Must be a map
+            if (!(value instanceof Map)) {
+                throw new IllegalArgumentException("A container cannot be filled with " + value);
+            }
+            new ContainerWidgetAsMap((AbstractContainerWidget)w).putAll((Map)value);
+        } else {
+            w.setValue(value);
+        }
+    }
+    
+    private class ContainerEntrySet extends AbstractSet {
+        public Iterator iterator() {
+            return new ContainerEntryIterator();
+        }
+
+        public int size() {
+            return container.getSize();
+        }
+    }
+    
+    private class ContainerEntryIterator extends AbstractIteratorDecorator {
+        public ContainerEntryIterator() {
+            super(container.getChildren());
+        }
+
+        public Object next() {
+            return new ContainerEntry((Widget)super.next());
+        }
+    }
+    
+    private class ContainerEntry implements Map.Entry {
+        Widget widget;
+        public ContainerEntry(Widget w) {
+            widget = w;
+        }
+        public Object getKey() {
+            return widget.getName();
+        }
+        public Object getValue() {
+            return asValueOrMap(widget);
+        }
+        public Object setValue(Object value) {
+            Object result = asValueOrMap(widget);
+            ContainerWidgetAsMap.this.setValue(widget, value);
+            return result;
+        }
+    }
+}
\ No newline at end of file

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/ContainerWidgetAsMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/ContainerWidgetAsMap.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/RepeaterAsList.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/RepeaterAsList.java?rev=293356&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/RepeaterAsList.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/RepeaterAsList.java Mon Oct  3 07:10:45 2005
@@ -0,0 +1,104 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.cocoon.forms.util;
+
+import java.util.AbstractList;
+import java.util.Map;
+
+import org.apache.cocoon.forms.formmodel.Repeater;
+
+/**
+ * A <code>List</code> view of a {@link Repeater}, each element of the list being a <code>Map</code>
+ * wrapping a repeater row, as defined by {@link ContainerWidgetAsMap}.
+ * <p>
+ * This implementation of list supports all methods, with the following restrictions:
+ * <ul>
+ * <li>values stored in the list must be <code>Map</code>s, that will be used with {@link ContainerWidgetAsMap#putAll(Map)}
+ *     on the <code>Map</code> representation of the repeater rows,</li>
+ * <li>operations that involve testing equality with the list contents (e.g. <code>contains(Object)</code>) will
+ *     not function properly, the <code>Map</code> wrapping the rows being created on demand.</li>
+ * </ul>
+ * 
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class RepeaterAsList extends AbstractList {
+    
+    private Repeater repeater;
+    private boolean lowerCase = true;
+
+    /**
+     * Create a <code>List<code> view around a repeater. The <code>keysToLowerCase</code> parameter
+     * specifies if <code>Map</code>s wrapping rows should convert input keys to lower case, as
+     * specified by {@link ContainerWidgetAsMap#ContainerWidgetAsMap(AbstractContainerWidget, boolean)}.
+     * 
+     * @param repeater the repeater to wrap
+     * @param keysToLowerCase should we convert input keys to lower case?
+     */
+    public RepeaterAsList(Repeater repeater, boolean keysToLowerCase) {
+        this.repeater = repeater;
+        this.lowerCase = keysToLowerCase;
+    }
+    
+    /**
+     * Same as <code>RepeaterAsList(repeater, true)</code>.
+     */
+    public RepeaterAsList(Repeater repeater) {
+        this(repeater, true);
+    }
+
+    public Object get(int index) {
+        return new ContainerWidgetAsMap(repeater.getRow(index), lowerCase);
+    }
+
+    public int size() {
+        return repeater.getSize();
+    }
+    
+    public Object set(int index, Object o) {
+        if (o == null) {
+            throw new NullPointerException("Cannot set null to a repeater");
+        }
+        if (!(o instanceof Map)) {
+            throw new IllegalArgumentException("Cannot set a '" + o.getClass().toString() + "' to a repeater");
+        }
+        Map result = new ContainerWidgetAsMap(repeater.getRow(index));
+        result.putAll((Map)o);
+        return result;
+    }
+    
+    public void add(int index, Object o) {
+        if (o == null) {
+            throw new NullPointerException("Cannot add null to a repeater");
+        }
+        if (!(o instanceof Map)) {
+            throw new IllegalArgumentException("Cannot add a '" + o.getClass().toString() + "' to a repeater");
+        }
+        Repeater.RepeaterRow row = repeater.addRow(index);
+        new ContainerWidgetAsMap(row).putAll((Map)o);
+    }
+    
+    public Object remove(int index) {
+        Map result = new ContainerWidgetAsMap(repeater.getRow(index));
+        repeater.removeRow(index);
+        return result;
+    }
+    
+    // Not mandated by the abstract class, but will speed up things
+    public void clear() {
+        repeater.clear();
+    }
+}
\ No newline at end of file

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/RepeaterAsList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/RepeaterAsList.java
------------------------------------------------------------------------------
    svn:keywords = Id