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/09/16 15:48:35 UTC

svn commit: r289538 [3/8] - in /cocoon: blocks/forms/trunk/WEB-INF/xconf/ blocks/forms/trunk/conf/ blocks/forms/trunk/java/org/apache/cocoon/forms/ blocks/forms/trunk/java/org/apache/cocoon/forms/binding/ blocks/forms/trunk/java/org/apache/cocoon/forms...

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/Library.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/Library.java?rev=289538&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/Library.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/Library.java Fri Sep 16 06:46:22 2005
@@ -0,0 +1,197 @@
+/*
+ * Copyright 1999-2005 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.binding.library;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.forms.binding.Binding;
+import org.apache.cocoon.forms.binding.BindingManager;
+import org.apache.cocoon.forms.binding.JXPathBindingManager;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.cocoon.util.location.LocationAttributes;
+import org.w3c.dom.Element;
+
+/**
+ * @version $Id$
+ *
+ */
+public class Library {
+
+	public static final String SEPARATOR = ":";
+	
+	// own references
+	protected LibraryManager manager = null;
+	
+	// own instances
+	protected Map definitions = new HashMap();
+	protected Map inclusions = new HashMap();
+	
+	// shared object with dependencies
+	protected Object shared = new Object();
+	
+	protected String sourceURI = null;
+	protected JXPathBindingManager.Assistant assistant = null;
+	
+	public Library(ServiceManager sm) {
+		try {
+			manager = (LibraryManager)sm.lookup(LibraryManager.ROLE);
+		} catch(ServiceException e) {
+			throw new RuntimeException("Could not initialize Library, LibraryManager not found!",e);
+		}
+	}
+	
+	public Library(LibraryManager lm) {
+		manager = lm;
+	}
+	
+	public void setAssistant(JXPathBindingManager.Assistant assistant) {
+		this.assistant = assistant;
+	}
+	
+	public void setSourceURI(String uri) {
+		sourceURI = uri;
+	}
+	public String getSourceURI() {
+		return sourceURI;
+	}
+	
+	public boolean dependenciesHaveChanged() throws Exception {
+		
+		Iterator it = this.inclusions.values().iterator();
+		while(it.hasNext()) {
+			Dependency dep = (Dependency)it.next();
+			if(!dep.isValid())
+				return true;
+		}
+		
+		return false;
+	}
+	
+	/**
+	 * "Registers" a library to be referenced later under a certain key or prefix.
+	 * Definitions will be accessible locally through prefixing: "prefix:definitionid"
+	 * 
+	 * @param key the key 
+	 * @param librarysource the source of the library to be know as "key"
+	 * @return true if there was no such key used before, false otherwise
+	 */
+	public boolean includeAs(String key, String librarysource)
+		throws LibraryException 
+	{
+		try {
+			// library keys may not contain ":"!
+			if( (!inclusions.containsKey(key) || key.indexOf(SEPARATOR)>-1) 
+					&& manager.getLibrary(librarysource, sourceURI)!=null) {
+				inclusions.put(key,new Dependency(librarysource));
+				return true;
+			}
+			return false;
+		} catch(Exception e) {
+			throw new LibraryException("Could not include library '"+librarysource+"'",e);
+		}
+		
+	}
+	
+	public Binding getBinding(String key) throws LibraryException {
+		
+		String librarykey = null;
+		String definitionkey = key;
+		
+		if(key.indexOf(":")>-1) {
+			String[] parts = key.split(SEPARATOR);
+			librarykey = parts[0];
+			definitionkey = parts[1];
+			for(int i=2; i<parts.length; i++) {
+				definitionkey += SEPARATOR+parts[i];
+			}
+		}
+		
+		if(librarykey!=null) {
+			if(inclusions.containsKey(librarykey)) {
+				try {
+					return manager.getLibrary(((Dependency)inclusions.get(librarykey)).dependencySourceURI, sourceURI).getBinding(definitionkey);
+				} catch(Exception e) {
+					throw new LibraryException("Couldn't get Library key='"+librarykey+"' source='"+inclusions.get(librarykey)+"",e);
+				}
+			} else {
+				throw new LibraryException("Library '"+librarykey+"' does not exist! (lookup: '"+key+"')");
+			}
+		} else {
+			return (Binding)definitions.get(definitionkey);
+		}
+	}
+	
+	public void buildLibrary(Element libraryElement) throws Exception {
+		sourceURI = LocationAttributes.getURI(libraryElement);
+		this.assistant.getContext().setLocalLibrary(this);
+        Element[] bindingElements = DomHelper.getChildElements(libraryElement, BindingManager.NAMESPACE);
+        for (int i = 0; i < bindingElements.length; i++) {
+            Element bindingElement = bindingElements[i];
+            Binding  binding = this.assistant.getBindingForConfigurationElement(bindingElement);
+            addBinding(binding);
+        }
+	}
+	
+	public void addBinding(Binding binding) throws LibraryException {
+		if(definitions.containsKey(binding.getId()))
+			throw new LibraryException("Library already contains a binding with this ID!");
+		
+		definitions.put(binding.getId(),binding);
+		manager.debug(this+": Put binding with id: "+binding.getId());
+	}
+	
+	
+	/**
+	 * Encapsulates a uri to designate an import plus a timestamp so previously reloaded 
+	 * 
+	 * @author Max Pfingsthorn (mpfingsthorn@hippo.nl)
+	 *
+	 */
+	public class Dependency {
+		
+		private String dependencySourceURI;
+		private Object shared;
+		
+		public Dependency(String dependencySourceURI) throws Exception {
+			this.dependencySourceURI = dependencySourceURI;
+			
+			Library lib = manager.getLibrary(this.dependencySourceURI,sourceURI);
+			this.shared = lib.shared;
+		}
+		
+		public boolean isValid() throws LibraryException {
+			try {
+				
+				if(manager.libraryInCache(dependencySourceURI,sourceURI)) {
+					Library lib = manager.getLibrary(dependencySourceURI,sourceURI);
+					
+					if(this.shared == lib.shared)
+						return true;
+				}
+				
+				return false;
+			} catch(Exception forward) {
+				throw new LibraryException("Exception occured while checking dependency validity!",forward);
+			}
+			
+		}
+	}
+	
+}

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/Library.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/Library.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryException.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryException.java?rev=289538&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryException.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryException.java Fri Sep 16 06:46:22 2005
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2005 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.binding.library;
+
+import org.apache.avalon.framework.CascadingException;
+
+/**
+ * This exception is thrown when something specific to the library system goes wrong.
+ * 
+ * @version $Id$
+ * 
+ */
+public class LibraryException extends CascadingException {
+    public LibraryException(String message) {
+        super(message);
+    }
+
+    public LibraryException(String message, Exception e) {
+        super(message, e);
+    }
+}

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryException.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManager.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManager.java?rev=289538&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManager.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManager.java Fri Sep 16 06:46:22 2005
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1999-2005 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.binding.library;
+
+
+
+/**
+ * The work interface for the LibraryManager, the class that
+ * manages all used library definitions so they can be shared between
+ * forms.
+ * 
+ * @version $Id$
+ *
+ */
+public interface LibraryManager {
+
+	String ROLE = LibraryManager.class.getName();
+	
+	Library getLibrary(String librarysource) throws Exception;
+	Library getLibrary(String librarysource, String relative) throws Exception;
+	Library getNewLibrary();
+	
+	boolean libraryInCache(String librarysource) throws Exception;
+	boolean libraryInCache(String librarysource, String relative) throws Exception;
+	
+	void debug(String msg);
+}

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManager.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManagerImpl.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManagerImpl.java?rev=289538&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManagerImpl.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManagerImpl.java Fri Sep 16 06:46:22 2005
@@ -0,0 +1,198 @@
+/*
+ * Copyright 1999-2005 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.binding.library;
+
+import org.apache.avalon.framework.CascadingException;
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.forms.CacheManager;
+import org.apache.cocoon.forms.binding.JXPathBindingManager;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+
+/**
+ * @version $Id$
+ *
+ */
+public class LibraryManagerImpl extends AbstractLogEnabled implements LibraryManager, ThreadSafe, Serviceable,
+Configurable, Initializable, Disposable {
+
+	protected static final String PREFIX = "CocoonFormBindingLibrary:";
+	
+	private ServiceManager serviceManager;
+    private Configuration configuration;
+    private CacheManager cacheManager;
+    
+    private JXPathBindingManager bindingManager;
+
+    public void configure(Configuration configuration) throws ConfigurationException {
+        this.configuration = configuration;
+        getLogger().debug("Gotten a config: top level element: "+this.configuration);
+    }
+
+    public void service(ServiceManager serviceManager) throws ServiceException {
+        this.serviceManager = serviceManager;
+        this.cacheManager = (CacheManager)serviceManager.lookup(CacheManager.ROLE);
+    }
+    
+    public void setBindingManager(JXPathBindingManager bindingManager) {
+    	this.bindingManager = bindingManager;
+    }
+    
+    public void initialize() throws Exception {
+    	
+        // read config to "preload" libraries
+    }
+    
+    public boolean libraryInCache(String librarysource) throws Exception {
+    	return libraryInCache(librarysource,null);
+    }
+    
+    public boolean libraryInCache(String librarysource, String relative) throws Exception {
+    	SourceResolver sourceResolver = null;
+        Source source = null;
+        
+        if(getLogger().isDebugEnabled())
+        	getLogger().debug("Checking if library is in cache: '"+librarysource+"' relative to '"+relative+"'");
+
+        Library lib = null;
+        boolean result = false;
+        
+        try {
+            sourceResolver = (SourceResolver)serviceManager.lookup(SourceResolver.ROLE);
+            source = sourceResolver.resolveURI(librarysource, relative, null);
+            
+            lib = (Library)this.cacheManager.get(source, PREFIX);
+            
+            if( lib != null && lib.dependenciesHaveChanged() ) {
+            	result = false;
+            	this.cacheManager.set(null,source,PREFIX); //evict?
+            }
+            else if( lib == null )
+            	result = false;
+            else
+            	result = true;
+        } catch(Exception e) {
+        	if(getLogger().isErrorEnabled())
+            	getLogger().error("Problem getting library '"+librarysource+"' relative to '"+relative+"'!",e);
+        	throw e;
+        } finally {
+            if (source != null)
+                sourceResolver.release(source);
+            if (sourceResolver != null)
+            	serviceManager.release(sourceResolver);
+        }
+
+        if(getLogger().isDebugEnabled()) {
+        	if(result)
+        		getLogger().debug("Library IS in cache : '"+librarysource+"' relative to '"+relative+"'");
+        	else
+        		getLogger().debug("Library IS NOT in cache : '"+librarysource+"' relative to '"+relative+"'");
+        }
+        
+        return result;
+    }
+    
+    public Library getLibrary(String librarysource) throws Exception {
+    	return getLibrary(librarysource,null);
+    }
+    
+	public Library getLibrary(String librarysource, String relative) throws Exception {
+		SourceResolver sourceResolver = null;
+        Source source = null;
+        Document libraryDocument = null;
+
+        Library lib = null;
+        
+        if(getLogger().isDebugEnabled())
+        	getLogger().debug("Getting library instance: '"+librarysource+"' relative to '"+relative+"'");
+        
+        try {
+            sourceResolver = (SourceResolver)serviceManager.lookup(SourceResolver.ROLE);
+            source = sourceResolver.resolveURI(librarysource, relative, null);
+            
+            lib = (Library)this.cacheManager.get(source, PREFIX);
+            
+            if( lib != null && lib.dependenciesHaveChanged() ) {
+            	if(getLogger().isDebugEnabled())
+                	getLogger().debug("Library dependencies changed, invalidating!");
+            	
+            	lib = null;
+            }
+            
+            if( lib == null ) {
+            	if(getLogger().isDebugEnabled())
+                	getLogger().debug("Library not in cache, creating!");
+            	
+            	try {
+                    InputSource inputSource = new InputSource(source.getInputStream());
+                    inputSource.setSystemId(source.getURI());
+                    libraryDocument = DomHelper.parse(inputSource, this.serviceManager);
+                    
+                    lib = getNewLibrary();
+                    lib.buildLibrary(libraryDocument.getDocumentElement());
+                    
+                    this.cacheManager.set(lib,source,PREFIX);
+                    
+                } catch (Exception e) {
+                    throw new CascadingException("Could not parse form definition from " +
+                                                 source.getURI(), e);
+                }
+            }
+        } finally {
+            if (source != null)
+                sourceResolver.release(source);
+            if (sourceResolver != null)
+            	serviceManager.release(sourceResolver);
+        }
+
+        return lib;
+	}
+	
+	public Library getNewLibrary() {
+		Library lib = new Library(this);
+		lib.setAssistant(this.bindingManager.getBuilderAssistant());
+        
+        if(getLogger().isDebugEnabled())
+        	getLogger().debug("Created new library! "+lib);
+        
+        return lib;
+	}
+
+	public void dispose() {
+		this.serviceManager.release(this.cacheManager);
+	    this.cacheManager = null;
+	    this.serviceManager = null;
+	}
+	
+	public void debug(String msg) {
+		if(getLogger().isDebugEnabled()) {
+			getLogger().debug(msg);
+		}
+	}
+	
+}

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManagerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/binding/library/LibraryManagerImpl.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DefaultSelectionListBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DefaultSelectionListBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DefaultSelectionListBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DefaultSelectionListBuilder.java Fri Sep 16 06:46:22 2005
@@ -19,6 +19,9 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.Node;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
@@ -27,6 +30,7 @@
 import org.apache.cocoon.forms.datatype.convertor.DefaultFormatCache;
 import org.apache.cocoon.forms.datatype.convertor.ConversionResult;
 import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.cocoon.util.Deprecation;
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.excalibur.xml.sax.XMLizable;
@@ -45,9 +49,14 @@
  *
  * @version $Id$
  */
-public class DefaultSelectionListBuilder implements SelectionListBuilder, Serviceable {
+public class DefaultSelectionListBuilder implements SelectionListBuilder, Serviceable, Contextualizable {
 
     private ServiceManager serviceManager;
+    private Context context;
+
+    public void contextualize(Context context) throws ContextException {
+        this.context = context;
+    }
 
     public void service(ServiceManager manager) throws ServiceException {
         this.serviceManager = manager;
@@ -57,18 +66,35 @@
         SelectionList selectionList;
         String src = selectionListElement.getAttribute("src");
         if (src.length() > 0) {
-            boolean dynamic = DomHelper.getAttributeAsBoolean(selectionListElement, "dynamic", false);
-            if (!dynamic) {
-                selectionListElement = readSelectionList(src);
-                selectionList = buildStaticList(selectionListElement, datatype);
+            boolean dynamic = false;
+            boolean usePerRequestCache = false;
+            String cacheType = DomHelper.getAttribute(selectionListElement, "cache", null);
+
+            // Read @cache 
+            if ("request".equals(cacheType)) { // Dynamic SelectionList cached per request
+                dynamic = true;
+                usePerRequestCache = true;
+            } else if ("none".equals(cacheType)){ // Dynamic SelectionList non cached
+                dynamic = true;
+            } else if ("static".equals(cacheType)) {
+                // Static SelectionList (default values)
+            } else { // Checking for deprecated @dynamic
+                if (DomHelper.getAttribute(selectionListElement, "dynamic", null) != null) {
+                    Deprecation.logger.warn("'@dynamic' is deprecated in <fd:selection-list> and replaced by '@cache' at " + DomHelper.getLocation(selectionListElement));                    
+                }
+                dynamic = DomHelper.getAttributeAsBoolean(selectionListElement, "dynamic", false);
+            }
+            // Create SelectionList
+            if (dynamic) {
+                selectionList = new DynamicSelectionList(datatype, src, usePerRequestCache, serviceManager, context);
             } else {
-                selectionList = new DynamicSelectionList(datatype, src, serviceManager);
+                selectionListElement = readSelectionList(src);
+                selectionList = buildStaticList(selectionListElement, datatype);                
             }
         } else {
             // selection list is defined inline
             selectionList = buildStaticList(selectionListElement, datatype);
         }
-
         return selectionList;
     }
 

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DynamicSelectionList.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DynamicSelectionList.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DynamicSelectionList.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/DynamicSelectionList.java Fri Sep 16 06:46:22 2005
@@ -18,22 +18,28 @@
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.Attributes;
+import org.apache.avalon.framework.context.Context;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.excalibur.source.Source;
 import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.ContextHelper;
 import org.apache.cocoon.components.source.SourceUtil;
+import org.apache.cocoon.environment.Request;
 import org.apache.cocoon.forms.Constants;
 import org.apache.cocoon.forms.datatype.convertor.Convertor;
 import org.apache.cocoon.forms.datatype.convertor.DefaultFormatCache;
 import org.apache.cocoon.forms.datatype.convertor.ConversionResult;
 import org.apache.cocoon.xml.AttributesImpl;
 import org.apache.cocoon.xml.AbstractXMLPipe;
+import org.apache.cocoon.xml.SaxBuffer;
 import org.apache.cocoon.xml.XMLUtils;
 import org.apache.cocoon.xml.dom.DOMBuilder;
 import org.w3c.dom.Element;
 
 import java.io.IOException;
+import java.rmi.server.UID;
+import java.util.Enumeration;
 import java.util.Locale;
 
 /**
@@ -48,10 +54,35 @@
  */
 public class DynamicSelectionList implements SelectionList {
     private String src;
+    private boolean usePerRequestCache;
     private Datatype datatype;
     private ServiceManager serviceManager;
+    private Context context;
 
+    /**
+     * @param datatype
+     * @param src
+     * @param usePerRequestCache 
+     * @param serviceManager
+     * @param context
+     */
+    public DynamicSelectionList(Datatype datatype, String src, boolean usePerRequestCache, ServiceManager serviceManager, Context context) {
+        this.datatype = datatype;
+        this.src = src;
+        this.serviceManager = serviceManager;
+        this.usePerRequestCache = usePerRequestCache;
+        this.context = context;
+    }
+
+    /**
+     * Creates a DynamicSelectionList without caching
+     * @param datatype - 
+     * @param src - 
+     * @param serviceManager -
+     */
     public DynamicSelectionList(Datatype datatype, String src, ServiceManager serviceManager) {
+        this.usePerRequestCache = false;
+        this.context = null;
         this.datatype = datatype;
         this.src = src;
         this.serviceManager = serviceManager;
@@ -71,8 +102,11 @@
         handler.setContentHandler(contentHandler);
         SourceUtil.toSAX(serviceManager, source, null, handler);
     }
-
-    public void generateSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {
+    
+    /*
+     * This method generate SaxFragment directly from source.
+     */
+    private void generateSaxFragmentFromSrc(ContentHandler contentHandler, Locale locale) throws SAXException {
         SourceResolver sourceResolver = null;
         Source source = null;
         try {
@@ -85,10 +119,43 @@
             throw new SAXException("Error while generating selection list: " + e.getMessage(), e);
         } finally {
             if (sourceResolver != null) {
-                if (source != null)
+                if (source != null) {
                     try { sourceResolver.release(source); } catch (Exception e) {}
+                }
                 serviceManager.release(sourceResolver);
             }
+        }
+    }
+
+    public void generateSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {
+
+        if (usePerRequestCache) {
+            // Search the cacheID in request attributes
+            Request request = ContextHelper.getRequest(this.context);
+            Enumeration enumeration = request.getAttributeNames();
+            boolean cacheFound = false;
+            String name = null;
+            while (enumeration.hasMoreElements()) {
+                name = (String)enumeration.nextElement();
+                if (name.startsWith(src)) {
+                    cacheFound = true;
+                    break;
+                }
+            }
+            SaxBuffer saxBuffer;
+            if (cacheFound) {
+                saxBuffer = (SaxBuffer)request.getAttribute(name);
+            } else {
+                // Generate the usePerRequestCache and store in a request attribute.
+                saxBuffer = new SaxBuffer();
+                generateSaxFragmentFromSrc(saxBuffer, locale);
+                String cacheID = (new UID()).toString();
+                request.setAttribute(src + cacheID, saxBuffer);
+            }
+            // Output the stored saxBuffer to the contentHandler
+            saxBuffer.toSAX(contentHandler);
+        } else { // We don't use usePerRequestCache => re-read from the source.
+            generateSaxFragmentFromSrc(contentHandler, locale);
         }
     }
 

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/FlowJXPathSelectionListBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/FlowJXPathSelectionListBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/FlowJXPathSelectionListBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/datatype/FlowJXPathSelectionListBuilder.java Fri Sep 16 06:46:22 2005
@@ -61,7 +61,13 @@
         String listPath = DomHelper.getAttribute(selectionListElement, "list-path");
         String valuePath = DomHelper.getAttribute(selectionListElement, "value-path");
         Map nspfx = DomHelper.getInheritedNSDeclarations(selectionListElement);
-        String i18nPfx = (String)nspfx.get( Constants.I18N_NS );
+        String i18nPfx = Constants.I18N_PREFIX;
+        if (nspfx != null) {
+            i18nPfx = (String)nspfx.get( Constants.I18N_NS );
+            if (i18nPfx == null ) {
+                i18nPfx = Constants.I18N_PREFIX;
+            }
+        }
         String labelPath = DomHelper.getAttribute(selectionListElement, "label-path", null);
         boolean labelIsI18nKey = false;
         if( labelPath == null )

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/event/ImageMapEvent.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/event/ImageMapEvent.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/event/ImageMapEvent.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/event/ImageMapEvent.java Fri Sep 16 06:46:22 2005
@@ -17,8 +17,6 @@
 
 import org.apache.cocoon.forms.formmodel.Widget;
 import org.apache.cocoon.forms.formmodel.ImageMap;
-import org.apache.cocoon.environment.Request;
-import org.apache.cocoon.forms.FormContext;
 
 /**
  * Currently this event originates from a {@link org.apache.cocoon.forms.formmodel.ImageMap}

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/expression/DefaultExpressionManager.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/expression/DefaultExpressionManager.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/expression/DefaultExpressionManager.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/expression/DefaultExpressionManager.java Fri Sep 16 06:46:22 2005
@@ -16,6 +16,7 @@
 
 package org.apache.cocoon.forms.expression;
 
+import org.apache.avalon.framework.component.Component;
 import org.apache.avalon.framework.configuration.Configurable;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
@@ -38,8 +39,9 @@
  * @version $Id$
  */
 public class DefaultExpressionManager
-        implements ExpressionManager, Configurable, ThreadSafe {
-    
+        implements ExpressionManager, Component, Configurable, ThreadSafe {
+// FIXME: Component is there to allow this block to also run in the 2.1 branch
+
     private DefaultFunctionFactory factory;
     
     public void configure(Configuration config) throws ConfigurationException {

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/ScriptableWidget.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/ScriptableWidget.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/ScriptableWidget.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/ScriptableWidget.java Fri Sep 16 06:46:22 2005
@@ -30,6 +30,8 @@
 import org.mozilla.javascript.Undefined;
 import org.mozilla.javascript.Wrapper;
 
+import java.util.Collection;
+
 /**
  * @version $Id$
  * 
@@ -256,6 +258,8 @@
                     }
                 } else if (value instanceof Object[]) {
                     values = (Object[])value;
+                } else if (value instanceof Collection ) {
+                    values = ((Collection)value).toArray();
                 }
                 field.setValues(values);
             } else {

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinition.java Fri Sep 16 06:46:22 2005
@@ -16,6 +16,7 @@
 package org.apache.cocoon.forms.formmodel;
 
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -37,6 +38,35 @@
 
     public void createWidgets(Widget parent) {
         definitions.createWidgets(parent);
+    }
+    
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	super.initializeFrom(definition);
+    	
+    	if(definition instanceof AbstractContainerDefinition) {
+    		AbstractContainerDefinition other = (AbstractContainerDefinition)definition;
+    		
+    		Iterator otherwidgets = other.definitions.getWidgetDefinitions().iterator();
+    		while(otherwidgets.hasNext()) {
+    			try {
+    				WidgetDefinition def = (WidgetDefinition)otherwidgets.next();
+    				this.definitions.addWidgetDefinition(def);
+    			} catch(DuplicateIdException ignore) {}
+    		}
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
+    
+    /**
+     * checks completeness of this definition
+     */
+    public void checkCompleteness() throws IncompletenessException {
+        super.checkCompleteness();
+        this.definitions.checkCompleteness();
     }
 
     public void addWidgetDefinition(WidgetDefinition definition) throws Exception, DuplicateIdException {

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinitionBuilder.java?rev=289538&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinitionBuilder.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractContainerDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999-2005 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.formmodel;
+
+import org.apache.cocoon.forms.Constants;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.w3c.dom.Element;
+
+/**
+ * Abstract base class for container widget builders.
+ * 
+ * @version $Id$
+ */
+
+public abstract class AbstractContainerDefinitionBuilder extends AbstractWidgetDefinitionBuilder {
+
+    protected void setupContainer(Element element, String widgetsElementName, AbstractContainerDefinition definition) throws Exception {
+
+        Element widgetsElement = DomHelper.getChildElement(element, Constants.DEFINITION_NS, widgetsElementName, false);
+
+        // if its not there, ignore it. Just means that there are no new widgets
+        if (widgetsElement == null)
+            return;
+
+        // All child elements of the widgets element are widgets
+        Element[] widgetElements = DomHelper.getChildElements(widgetsElement, Constants.DEFINITION_NS);
+        WidgetDefinitionBuilderContext oldContext = this.context;
+
+        for (int i = 0; i < widgetElements.length; i++) {
+            Element widgetElement = widgetElements[i];
+
+            this.context = new WidgetDefinitionBuilderContext(oldContext);
+
+            String newId = DomHelper.getAttribute(widgetElement, "extends", null);
+            WidgetDefinition def = null;
+            if (newId != null) {
+                if ((def = this.context.getLocalLibrary().getDefinition(newId)) != null)
+                    this.context.setSuperDefinition(def);
+                else if ((def = definition.getWidgetDefinition(newId)) != null)
+                    this.context.setSuperDefinition(def);
+                else
+                    this.context.setSuperDefinition(null);
+                // throw new Exception("Widget to inherit from ("+newId+") not
+                // found! (at "+DomHelper.getLocation(element)+")");
+            }
+
+            WidgetDefinition widgetDefinition = buildAnotherWidgetDefinition(widgetElement);
+
+            if (widgetDefinition != null)
+                definition.addWidgetDefinition(widgetDefinition);
+
+        }
+
+        this.context = oldContext;
+    }
+}

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

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

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinition.java Fri Sep 16 06:46:22 2005
@@ -42,6 +42,37 @@
         checkMutable();
         this.manager = manager;
     }
+    
+    /**
+     * checks 
+     * @return
+     */
+    public void checkCompleteness() throws IncompletenessException {
+    	super.checkCompleteness();
+    	
+    	if(this.datatype==null)
+    		throw new IncompletenessException("A datatype element is required!",this);
+    	
+    }
+    
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	super.initializeFrom(definition);
+    	
+    	if(definition instanceof AbstractDatatypeWidgetDefinition) {
+    		AbstractDatatypeWidgetDefinition other = (AbstractDatatypeWidgetDefinition)definition;
+    		
+    		this.datatype = other.datatype;
+    		this.initialValue = other.initialValue;
+    		this.selectionList = other.selectionList;
+    		this.listener = other.listener;
+    		
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
 
     public Datatype getDatatype() {
         return datatype;

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -49,29 +49,27 @@
         
         //---- parse "datatype"
         Element datatypeElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, "datatype");
-        if (datatypeElement == null) {
-            throw new Exception("A nested datatype element is required for the widget " 
-                                + widgetElement.getTagName() + " at " + DomHelper.getLocation(widgetElement));
-        }
-
-        Datatype datatype = datatypeManager.createDatatype(datatypeElement, false);
-        
-        //---- parse "initial-value"
-        Object initialValue = null;
-        Element initialValueElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, "initial-value", false);
-        if (initialValueElement != null) {
-            String localeValue = DomHelper.getAttribute(initialValueElement, "locale", null);
-            Locale locale = localeValue == null ? null : I18nUtils.parseLocale(localeValue);
-            String value = DomHelper.getElementText(initialValueElement);
-            ConversionResult result = datatype.convertFromString(value, locale);
-            if (!result.isSuccessful()) {
-                throw new Exception("Cannot parse initial value '" + value + "' at " +
-                        DomHelper.getLocation(initialValueElement));
+        if (datatypeElement != null) {
+        	Datatype datatype = datatypeManager.createDatatype(datatypeElement, false);
+        	
+        	// ---- parse "initial-value"
+            Object initialValue = null;
+            Element initialValueElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, "initial-value", false);
+            if (initialValueElement != null) {
+                String localeValue = DomHelper.getAttribute(initialValueElement, "locale", null);
+                Locale locale = localeValue == null ? null : I18nUtils.parseLocale(localeValue);
+                String value = DomHelper.getElementText(initialValueElement);
+                ConversionResult result = datatype.convertFromString(value, locale);
+                if (!result.isSuccessful()) {
+                    throw new Exception("Cannot parse initial value '" + value + "' at " +
+                            DomHelper.getLocation(initialValueElement));
+                }
+                initialValue = result.getResult();
             }
-            initialValue = result.getResult();
+            
+            definition.setDatatype(datatype, initialValue);
         }
         
-        definition.setDatatype(datatype, initialValue);
         
         //---- parse "selection-list"
         // FIXME: pass the manager to the definition as a side effect. Should be removed
@@ -79,6 +77,10 @@
         definition.service(this.serviceManager);
 
         Element selectionListElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, "selection-list");
+        
+        if(selectionListElement != null && definition.getDatatype() == null)
+        	throw new Exception("A widget with a selection list always requires a datatype as well! (at "+DomHelper.getLocation(selectionListElement)+" )");
+        
         if (selectionListElement != null) {
             // Get an appropriate list builder
             ServiceSelector builderSelector = (ServiceSelector)this.serviceManager.lookup(SelectionListBuilder.ROLE + "Selector");

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java Fri Sep 16 06:46:22 2005
@@ -27,6 +27,7 @@
 import org.apache.cocoon.forms.event.WidgetEvent;
 import org.apache.cocoon.forms.validation.ValidationErrorAware;
 import org.apache.cocoon.forms.validation.WidgetValidator;
+import org.apache.cocoon.util.location.Location;
 import org.apache.cocoon.xml.AttributesImpl;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
@@ -114,7 +115,7 @@
      * @return the location-information (file, line and column) where this widget was
      * configured.
      */
-    public String getLocation() {
+    public Location getLocation() {
         return getDefinition().getLocation();
     }
 

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinition.java Fri Sep 16 06:46:22 2005
@@ -16,6 +16,7 @@
 package org.apache.cocoon.forms.formmodel;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -25,6 +26,7 @@
 import org.apache.cocoon.forms.event.CreateListener;
 import org.apache.cocoon.forms.event.WidgetEventMulticaster;
 import org.apache.cocoon.forms.validation.WidgetValidator;
+import org.apache.cocoon.util.location.Location;
 import org.apache.cocoon.xml.XMLUtils;
 import org.apache.excalibur.xml.sax.XMLizable;
 import org.xml.sax.ContentHandler;
@@ -40,7 +42,7 @@
     protected WidgetDefinition parent;
 
     //TODO consider final on these
-    private String location = null;
+    private Location location = Location.UNKNOWN;
     private String id;
     /** the definition is mutable when being built */
     private boolean mutable = true;
@@ -64,6 +66,66 @@
     }
     
     /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	if(definition instanceof AbstractWidgetDefinition) {
+    		AbstractWidgetDefinition other = (AbstractWidgetDefinition)definition;
+    		
+    		this.state = other.state;
+    		this.createListener = other.createListener; // this works, we don't really remove listeners, right?
+    		
+    		this.validators = new ArrayList();
+    		if(other.validators!=null) {
+    			for(int i=0; i<other.validators.size(); i++)
+    				this.validators.add(other.validators.get(i));
+    		}
+    		
+    		if(other.attributes!=null) {
+    			if(attributes==null)
+    				attributes = new HashMap();
+    	    	copyMap(attributes,other.attributes);
+    		}
+    		if(other.displayData!=null) {
+    			if(displayData==null)
+    				displayData = new HashMap();
+    	    	copyMap(displayData,other.displayData);
+    		}
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
+    
+    /**
+     * helper to copy a map
+     * 
+     * @param dest destination map
+     * @param src source map
+     */
+    protected void copyMap(Map dest, Map src) {
+    	dest.clear();
+    	Iterator it = src.entrySet().iterator();
+    	while(it.hasNext()) {
+    		Map.Entry entry = (Map.Entry)it.next();
+    		dest.put(entry.getKey(),entry.getValue());
+    	}
+    }
+    
+    /**
+     * Checks if this definition is complete or not.
+     */
+    public void checkCompleteness() throws IncompletenessException
+    {
+    	// FormDefinition is the only one allowed not to have an ID
+    	if( (id==null || "".equals(id) && !(this instanceof FormDefinition) ))
+    		throw new IncompletenessException("Widget found without an ID! "+this,this);
+    	
+    	
+    	// TODO: don't know what else to check now
+    }
+    
+    
+    /**
      * Locks this definition so that it becomes immutable.
      */
     public void makeImmutable() {
@@ -105,12 +167,12 @@
         this.state = state;
     }
 
-    protected void setLocation(String location) {
+    public void setLocation(Location location) {
         checkMutable();
         this.location = location;
     }
 
-    public String getLocation() {
+    public Location getLocation() {
         return location;
     }
 
@@ -125,7 +187,22 @@
 
     protected void setAttributes(Map attributes) {
         checkMutable();
-        this.attributes = attributes;   
+        //this.attributes = attributes;
+        if(this.attributes==null) {
+        	this.attributes = attributes;
+        	return;
+        }
+        if(attributes==null)
+        	return;
+        
+        // merge attribute lists
+        Iterator entries = attributes.entrySet().iterator();
+        while(entries.hasNext()) {
+        	Map.Entry entry = (Map.Entry)entries.next();
+        	Object key = entry.getKey();
+        	Object value = entry.getValue();
+        	this.attributes.put(key,value);
+        }
     }
     
     public Object getAttribute(String name) {
@@ -137,6 +214,7 @@
 
     protected void addCreateListener(CreateListener listener) {
         checkMutable();
+        // Event listener daisy-chain
         this.createListener = WidgetEventMulticaster.add(this.createListener, listener);
     }
     
@@ -169,7 +247,24 @@
      */
     public void setDisplayData(Map displayData) {
         checkMutable();
-        this.displayData = displayData;
+        //this.displayData = displayData;
+        
+        if(this.displayData==null) {
+        	this.displayData = displayData;
+        	return;
+        }
+        if(displayData==null)
+        	return;
+        
+        // merge displayData lists
+        Iterator entries = displayData.entrySet().iterator();
+        while(entries.hasNext()) {
+        	Map.Entry entry = (Map.Entry)entries.next();
+        	Object key = entry.getKey();
+        	Object value = entry.getValue();
+        	if(value!=null || !this.displayData.containsKey(key))
+        		this.displayData.put(key,value);
+        }
     }
 
     public void addValidator(WidgetValidator validator) {

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidgetDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -54,6 +54,24 @@
     protected DatatypeManager datatypeManager;
     protected ExpressionManager expressionManager;
     protected ServiceManager serviceManager;
+    
+    protected WidgetDefinitionBuilderContext context = null;
+    
+    public WidgetDefinition buildWidgetDefinition(Element widgetElement, WidgetDefinitionBuilderContext context) throws Exception {
+    	// so changes don't pollute upper levels
+    	this.context = new WidgetDefinitionBuilderContext(context);
+    	
+    	
+    	WidgetDefinition def = buildWidgetDefinition(widgetElement);
+    	
+    	// register this class with the local library, if any.
+        if(DomHelper.getAttributeAsBoolean(widgetElement,"register",false) && this.context!=null && this.context.getLocalLibrary()!=null) {
+        	this.context.getLocalLibrary().addDefinition(def);
+        }
+        
+    	this.context = null;
+    	return def;
+    }
 
     public void service(ServiceManager serviceManager) throws ServiceException {
         this.serviceManager = serviceManager;
@@ -65,15 +83,21 @@
     }
     
     protected void setupDefinition(Element widgetElement, AbstractWidgetDefinition definition) throws Exception {
+    	
+    	// location
+    	definition.setLocation(DomHelper.getLocationObject(widgetElement));
+    	
+    	
+    	if(this.context.getSuperDefinition()!=null) 
+    		definition.initializeFrom(this.context.getSuperDefinition());
+    	
         setCommonProperties(widgetElement, definition);
         setValidators(widgetElement, definition);
         setCreateListeners(widgetElement, definition);
     }
 
     private void setCommonProperties(Element widgetElement, AbstractWidgetDefinition widgetDefinition) throws Exception {
-        // location
-        widgetDefinition.setLocation(DomHelper.getLocation(widgetElement));
-
+        
         // id
         if (widgetDefinition instanceof FormDefinition) {
             // FormDefinition is the *only* kind of widget that has an optional id
@@ -123,7 +147,9 @@
             throw new CascadingException("Unknown kind of widget '" + widgetName + "' at " +
                                          DomHelper.getLocation(widgetDefinition), e);
         }
-        return builder.buildWidgetDefinition(widgetDefinition);
+        
+        
+        return builder.buildWidgetDefinition(widgetDefinition, this.context);
     }
 
     protected List buildEventListeners(Element widgetElement, String elementName, Class listenerClass) throws Exception {

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ActionDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ActionDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ActionDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ActionDefinition.java Fri Sep 16 06:46:22 2005
@@ -31,6 +31,23 @@
     public void setActionCommand(String actionCommand) {
         this.actionCommand = actionCommand;
     }
+    
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	super.initializeFrom(definition);
+    	
+    	if(definition instanceof ActionDefinition) {
+    		ActionDefinition other = (ActionDefinition)definition;
+    		
+    		this.actionCommand = other.actionCommand;
+    		this.listener = other.listener;
+    		
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
 
     public String getActionCommand() {
         return actionCommand;

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinition.java Fri Sep 16 06:46:22 2005
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2005 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.
@@ -21,8 +21,11 @@
 import org.outerj.expression.Expression;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 /**
  * The {@link WidgetDefinition} part of a AggregateField widget, see {@link AggregateField} for more information.
@@ -58,17 +61,78 @@
      * a group (paren) from the regular expression and corresponding field id.
      */
     private List splitMappings = new ArrayList();
+    
+    /**
+     * Set containing widgets mapped to groups to find out if a specific widget has been mapped already
+     */
+    private Set mappedFields = new HashSet();
 
     /**
      *
      */
     private WidgetDefinitionList container = new WidgetDefinitionList(this);
 
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	super.initializeFrom(definition);
+    	
+    	if(definition instanceof AggregateFieldDefinition) {
+    		AggregateFieldDefinition other = (AggregateFieldDefinition)definition;
+    		
+    		this.combineExpr = other.combineExpr;
+    		this.splitRegexp = other.splitRegexp;
+    		this.splitPattern = other.splitPattern;
+    		this.splitFailMessage = other.splitFailMessage;
+    		
+    		Iterator defs = other.container.getWidgetDefinitions().iterator();
+    		while(defs.hasNext()) {
+    			container.addWidgetDefinition((WidgetDefinition)defs.next());
+    		}
+    		
+    		Collections.copy(this.splitMappings,other.splitMappings);
+    		
+    		Iterator fields = other.mappedFields.iterator();
+    		while(fields.hasNext()) {
+    			this.mappedFields.add(fields.next());
+    		}
+    		
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
 
     public void addWidgetDefinition(WidgetDefinition widgetDefinition) throws DuplicateIdException {
         checkMutable();
         container.addWidgetDefinition(widgetDefinition);
     }
+    
+    /**
+     * checks completeness of this definition
+     */
+    public void checkCompleteness() throws IncompletenessException {
+    	super.checkCompleteness();
+    	
+    	if(this.container.size()==0)
+    		throw new IncompletenessException("AggregateField doesn't have any child widgets!",this);
+    	
+    	if(this.combineExpr==null)
+    		throw new IncompletenessException("AggregateField requires a combine expression!",this);
+    	
+    	if(this.splitPattern==null)
+    		throw new IncompletenessException("AggregateField requires a split regular expression!",this);
+    	
+    	if(this.splitMappings.size()==0)
+    		throw new IncompletenessException("AggregateField requires at least one group to field mapping!",this);
+    	
+    	// now check children's completeness
+    	List defs = container.getWidgetDefinitions();
+    	Iterator it = defs.iterator();
+    	while(it.hasNext()) {
+    		((WidgetDefinition)it.next()).checkCompleteness();
+    	}
+    }
 
     public boolean hasWidget(String id) {
         return container.hasWidget(id);
@@ -108,6 +172,12 @@
 
     protected void addSplitMapping(int group, String fieldId) {
         checkMutable();
+        
+        if(mappedFields.contains(fieldId))
+        	throw new RuntimeException("Field '"+fieldId+"' is already mapped to another group!");
+        
+        mappedFields.add(fieldId);
+        
         splitMappings.add(new SplitMapping(group, fieldId));
     }
 

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AggregateFieldDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -15,8 +15,6 @@
  */
 package org.apache.cocoon.forms.formmodel;
 
-import java.util.HashSet;
-
 import org.apache.cocoon.forms.Constants;
 import org.apache.cocoon.forms.util.DomHelper;
 import org.apache.excalibur.xml.sax.XMLizable;
@@ -55,33 +53,36 @@
 
         // compile splitpattern
         Element splitElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, "split", true);
-        String patternString = DomHelper.getAttribute(splitElement, "pattern");
-        Perl5Compiler compiler = new Perl5Compiler();
-        Pattern pattern = null;
-        try {
-            pattern = compiler.compile(patternString, Perl5Compiler.READ_ONLY_MASK);
-        } catch (MalformedPatternException e) {
-            throw new Exception("Invalid regular expression at " + DomHelper.getLocation(splitElement) + ": " + e.getMessage());
+        if(splitElement!=null) {
+	        String patternString = DomHelper.getAttribute(splitElement, "pattern");
+	        Perl5Compiler compiler = new Perl5Compiler();
+	        Pattern pattern = null;
+	        try {
+	            pattern = compiler.compile(patternString, Perl5Compiler.READ_ONLY_MASK);
+	        } catch (MalformedPatternException e) {
+	            throw new Exception("Invalid regular expression at " + DomHelper.getLocation(splitElement) + ": " + e.getMessage());
+	        }
+	        definition.setSplitPattern(pattern, patternString);
         }
-        definition.setSplitPattern(pattern, patternString);
 
         // read split mappings
         Element[] mapElements = DomHelper.getChildElements(splitElement, Constants.DEFINITION_NS, "map");
-        HashSet encounteredFieldMappings = new HashSet();
         for (int i = 0; i < mapElements.length; i++) {
             int group = DomHelper.getAttributeAsInteger(mapElements[i], "group");
             String field = DomHelper.getAttribute(mapElements[i], "field");
             // check that this field exists
             if (!definition.hasWidget(field)) {
-                throw new Exception("Unkwon widget id \"" + field + "\", at " +
+                throw new Exception("Unknown widget id \"" + field + "\", at " +
                                     DomHelper.getLocation(mapElements[i]));
             }
-            if (encounteredFieldMappings.contains(field)) {
-                throw new Exception("Two groups are mapped to the same widget id \"" + field + "\", at " +
-                                    DomHelper.getLocation(mapElements[i]));
+            
+            try {
+            	definition.addSplitMapping(group, field);
+            	System.out.println("Aggregate: addSplitMapping("+group+","+field+")");
+            } catch(RuntimeException e) {
+            	throw new Exception("Two groups are mapped to the same widget id \"" + field + "\", at " +
+                        DomHelper.getLocation(mapElements[i]));
             }
-            encounteredFieldMappings.add(field);
-            definition.addSplitMapping(group, field);
         }
 
         // read split fail message (if any)
@@ -93,19 +94,21 @@
 
         // compile combine expression
         Element combineElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, "combine", true);
-        String combineExprString = DomHelper.getAttribute(combineElement, "expression");
-        Expression combineExpr = null;
-        try {
-            combineExpr = expressionManager.parse(combineExprString);
-        } catch (Exception e) {
-            throw new Exception("Problem with combine expression defined at " +
-                                DomHelper.getLocation(combineElement) + ": " + e.getMessage());
-        }
-        Class clazz = definition.getDatatype().getTypeClass();
-        if (combineExpr.getResultType() != null && !clazz.isAssignableFrom(combineExpr.getResultType())) {
-            throw new Exception("The result of the combine expression should be " + clazz.getName() + ", at " +
-                                DomHelper.getLocation(combineElement));
+        if(combineElement!=null) {
+        	String combineExprString = DomHelper.getAttribute(combineElement, "expression");
+            Expression combineExpr = null;
+            try {
+                combineExpr = expressionManager.parse(combineExprString);
+            } catch (Exception e) {
+                throw new Exception("Problem with combine expression defined at " +
+                                    DomHelper.getLocation(combineElement) + ": " + e.getMessage());
+            }
+            Class clazz = definition.getDatatype().getTypeClass();
+            if (combineExpr.getResultType() != null && !clazz.isAssignableFrom(combineExpr.getResultType())) {
+                throw new Exception("The result of the combine expression should be " + clazz.getName() + ", at " +
+                                    DomHelper.getLocation(combineElement));
+            }
+            definition.setCombineExpression(combineExpr);
         }
-        definition.setCombineExpression(combineExpr);
     }
 }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinition.java Fri Sep 16 06:46:22 2005
@@ -35,6 +35,24 @@
         return new BooleanField(this);
     }
     
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	super.initializeFrom(definition);
+    	
+    	if(definition instanceof BooleanFieldDefinition) {
+    		BooleanFieldDefinition other = (BooleanFieldDefinition)definition;
+    		
+    		this.listener = other.listener;
+    		this.initialValue = other.initialValue;
+    		this.trueParamValue = other.trueParamValue;
+    		
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
+    
     public void setInitialValue(Boolean value) {
         checkMutable();
         this.initialValue = value;

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/BooleanFieldDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -32,7 +32,7 @@
         
         BooleanFieldDefinition definition = new BooleanFieldDefinition();
         
-        super.setupDefinition(widgetElement, definition);
+        setupDefinition(widgetElement, definition);
         setDisplayData(widgetElement, definition);
         Iterator iter = buildEventListeners(widgetElement, "on-value-changed", ValueChangedListener.class).iterator();
         while (iter.hasNext()) {

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ButtonDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ButtonDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ButtonDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ButtonDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -24,7 +24,7 @@
  * 
  * @version $Id$
  */
-public class ButtonDefinitionBuilder implements WidgetDefinitionBuilder {
+public class ButtonDefinitionBuilder extends AbstractWidgetDefinitionBuilder {
     public WidgetDefinition buildWidgetDefinition(Element widgetElement) throws Exception {
         throw new Exception("The button widget has been renamed to action. Please update your form definition files. Found at " + DomHelper.getLocation(widgetElement));
     }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/CaptchaFieldDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/CaptchaFieldDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/CaptchaFieldDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/CaptchaFieldDefinition.java Fri Sep 16 06:46:22 2005
@@ -31,6 +31,22 @@
     public CaptchaFieldDefinition(Context avalonContext) {
         this.avalonContext = avalonContext;
     }
+    
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	super.initializeFrom(definition);
+    	
+    	if(definition instanceof CaptchaFieldDefinition) {
+    		CaptchaFieldDefinition other = (CaptchaFieldDefinition)definition;
+    		
+    		this.length = other.length;
+    		
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
 
     public Widget createInstance() {
         CaptchaField field = new CaptchaField(this, avalonContext);

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ClassDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ClassDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ClassDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ClassDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -15,8 +15,6 @@
  */
 package org.apache.cocoon.forms.formmodel;
 
-import org.apache.cocoon.forms.Constants;
-import org.apache.cocoon.forms.util.DomHelper;
 import org.w3c.dom.Element;
 
 /**
@@ -24,7 +22,7 @@
  *
  * @version $Id$
  */
-public final class ClassDefinitionBuilder extends AbstractWidgetDefinitionBuilder {
+public final class ClassDefinitionBuilder extends AbstractContainerDefinitionBuilder {
 
     public WidgetDefinition buildWidgetDefinition(Element element) throws Exception {
         ClassDefinition definition = new ClassDefinition();
@@ -32,16 +30,10 @@
         super.setupDefinition(element, definition);
         setDisplayData(element, definition);
 
-        Element widgetsElement = DomHelper.getChildElement(element, Constants.DEFINITION_NS, "widgets", true);
-        // All child elements of the widgets element are widgets
-        Element[] widgetElements = DomHelper.getChildElements(widgetsElement, Constants.DEFINITION_NS);
-        for (int i = 0; i < widgetElements.length; i++) {
-            Element widgetElement = widgetElements[i];
-            WidgetDefinition widgetDefinition = buildAnotherWidgetDefinition(widgetElement);
-            definition.addWidgetDefinition(widgetDefinition);
-        }
+        setupContainer(element,"widgets",definition);
 
         definition.makeImmutable();
+        
         return definition;
     }
 }

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java?rev=289538&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -0,0 +1,38 @@
+/*
+ * 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.formmodel;
+
+import org.apache.cocoon.forms.util.DomHelper;
+import org.w3c.dom.Element;
+
+/**
+ * Builds definitions by using library definitions.
+ *
+ * @version $Id$
+ */
+public class ExpandDefinitionBuilder extends AbstractWidgetDefinitionBuilder {
+
+    public WidgetDefinition buildWidgetDefinition(Element element) throws Exception {
+        String id = DomHelper.getAttribute(element, "id");
+        
+        WidgetDefinition definition = context.getLocalLibrary().getDefinition(id);
+        
+        if(definition == null)
+        	throw new Exception("Widget '"+id+"' not found! (at "+DomHelper.getLocation(element)+")");
+        
+        return definition;
+    }
+}

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

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

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java Fri Sep 16 06:46:22 2005
@@ -27,6 +27,22 @@
         Field field = new Field(this);
         return field;
     }
+    
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+    	super.initializeFrom(definition);
+    	
+    	if(definition instanceof FieldDefinition) {
+    		FieldDefinition other = (FieldDefinition)definition;
+    		
+    		this.required = other.required;
+    		
+    	} else {
+    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+    	}
+    }
 
     public boolean isRequired() {
         return required;

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -36,7 +36,7 @@
         super.setupDefinition(widgetElement, definition);
         
         // parse "@required"
-        boolean required = DomHelper.getAttributeAsBoolean(widgetElement, "required", false);
-        definition.setRequired(required);
+        if(widgetElement.hasAttribute("required"))
+            definition.setRequired(DomHelper.getAttributeAsBoolean(widgetElement, "required", false));
     }
 }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinition.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinition.java Fri Sep 16 06:46:22 2005
@@ -21,6 +21,8 @@
 import org.apache.cocoon.forms.event.ProcessingPhaseEvent;
 import org.apache.cocoon.forms.event.ProcessingPhaseListener;
 import org.apache.cocoon.forms.event.WidgetEventMulticaster;
+import org.apache.cocoon.forms.formmodel.library.Library;
+import org.apache.cocoon.forms.formmodel.library.LibraryManager;
 
 /**
  * The {@link WidgetDefinition} part of a Form widget, see {@link Form} for more information.
@@ -29,15 +31,25 @@
  */
 public class FormDefinition extends AbstractContainerDefinition {
     private ProcessingPhaseListener listener;
+    
+    private Library localLibrary = null;
 
-    public FormDefinition() {
+    public FormDefinition(LibraryManager libraryManager) {
         super();
+        localLibrary = libraryManager.getNewLibrary();
+    }
+    
+    public Library getLocalLibrary() {
+    	return localLibrary;
     }
 
     public void resolve() throws Exception {
         List parents = new ArrayList();
         parents.add(this);
         resolve(parents, this);
+        
+        // TODO: test if this actually gets called!
+        checkCompleteness();
     }
 
     public Widget createInstance() {

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -15,8 +15,10 @@
  */
 package org.apache.cocoon.forms.formmodel;
 
-import org.apache.cocoon.forms.Constants;
-import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.forms.formmodel.library.LibraryManager;
+import org.apache.cocoon.util.location.LocationAttributes;
 import org.w3c.dom.Element;
 
 /**
@@ -24,26 +26,38 @@
  * 
  * @version $Id$
  */
-public final class FormDefinitionBuilder extends AbstractWidgetDefinitionBuilder {
+public final class FormDefinitionBuilder extends AbstractContainerDefinitionBuilder {
 
+	protected LibraryManager libraryManager;
+	
+	public void service(ServiceManager manager) throws ServiceException {
+		super.service(manager);
+		
+		libraryManager = (LibraryManager) serviceManager.lookup(LibraryManager.ROLE);
+	}
+	
+	public WidgetDefinition buildWidgetDefinition(Element widgetElement, WidgetDefinitionBuilderContext context) throws Exception {
+    	throw new UnsupportedOperationException("Please use the other signature without WidgetDefinitionBuilderContext!");
+    }
+	
     public WidgetDefinition buildWidgetDefinition(Element formElement) throws Exception {
-        FormDefinition formDefinition = new FormDefinition();
+        FormDefinition formDefinition = new FormDefinition(libraryManager);
+        this.context = new WidgetDefinitionBuilderContext();
+        this.context.setLocalLibrary(formDefinition.getLocalLibrary());
+        
+        // set local URI
+        formDefinition.getLocalLibrary().setSourceURI(LocationAttributes.getURI(formElement));
         
         super.setupDefinition(formElement, formDefinition);
         setDisplayData(formElement, formDefinition);
 
-        Element widgetsElement = DomHelper.getChildElement(formElement, Constants.DEFINITION_NS, "widgets", true);
-        // All child elements of the widgets element are widgets
-        Element[] widgetElements = DomHelper.getChildElements(widgetsElement, Constants.DEFINITION_NS);
-        for (int i = 0; i < widgetElements.length; i++) {
-            Element widgetElement = widgetElements[i];
-            WidgetDefinition widgetDefinition = buildAnotherWidgetDefinition(widgetElement);
-            formDefinition.addWidgetDefinition(widgetDefinition);
-        }
+        setupContainer(formElement,"widgets",formDefinition);
 
         formDefinition.resolve();
 
         formDefinition.makeImmutable();
+        
+        this.context = null;
         return formDefinition;
     }
 }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -16,15 +16,13 @@
 package org.apache.cocoon.forms.formmodel;
 
 import org.w3c.dom.Element;
-import org.apache.cocoon.forms.Constants;
-import org.apache.cocoon.forms.util.DomHelper;
 
 /**
  * Builds {GroupDefinition}s.
  *
  * @version $Id$
  */
-public final class GroupDefinitionBuilder extends AbstractWidgetDefinitionBuilder {
+public final class GroupDefinitionBuilder extends AbstractContainerDefinitionBuilder {
 
     public WidgetDefinition buildWidgetDefinition(Element element) throws Exception {
         GroupDefinition definition = new GroupDefinition();
@@ -32,15 +30,8 @@
         super.setupDefinition(element, definition);
         setDisplayData(element, definition);
 
-        Element widgetsElement = DomHelper.getChildElement(element, Constants.DEFINITION_NS, "widgets", true);
-        // All child elements of the widgets element are widgets
-        Element[] widgetElements = DomHelper.getChildElements(widgetsElement, Constants.DEFINITION_NS);
-        for (int i = 0; i < widgetElements.length; i++) {
-            Element widgetElement = widgetElements[i];
-            WidgetDefinition widgetDefinition = buildAnotherWidgetDefinition(widgetElement);
-            definition.addWidgetDefinition(widgetDefinition);
-        }
-
+        setupContainer(element,"widgets",definition);
+        
         definition.makeImmutable();
         return definition;
     }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMap.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMap.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMap.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMap.java Fri Sep 16 06:46:22 2005
@@ -24,7 +24,7 @@
  * on the server side, which will be handled by either the event handlers defined in the
  * form definition, and/or by the {@link org.apache.cocoon.forms.event.FormHandler FormHandler}
  * registered with the form, if any. An ImageMap widget is basically an Action widget
- * displayed as an image and with mouse coordinates stored uòon clicking.
+ * displayed as an image and with mouse coordinates stored upon clicking.
  * The image's URI can be set or get, or bind via the binding framework, mouse coordinates
  * can be either retrieved from the ImageMapEvent triggered or from the widget itself.
  * 

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMapDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMapDefinitionBuilder.java?rev=289538&r1=289537&r2=289538&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMapDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/ImageMapDefinitionBuilder.java Fri Sep 16 06:46:22 2005
@@ -20,7 +20,6 @@
 import org.apache.cocoon.forms.Constants;
 import org.apache.cocoon.forms.event.ActionListener;
 import org.apache.cocoon.forms.util.DomHelper;
-import org.apache.cocoon.util.Deprecation;
 import org.w3c.dom.Element;
 
 /**