You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by jh...@apache.org on 2005/11/03 15:00:48 UTC
svn commit: r330548 [86/132] - in
/cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/
cocoon-ajax-block/api/ cocoon-ajax-block/api/src/
cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/
cocoon-ajax-block/api/src/main/...
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingBuilderBase.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingBuilderBase.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingBuilderBase.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingBuilderBase.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,242 @@
+/*
+ * 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.binding;
+
+import java.util.Map;
+
+import org.apache.avalon.framework.logger.LogEnabled;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.commons.lang.BooleanUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Abstract base class enabling logging and supporting the intrepretation of
+ * common configuration settings on all specific implementations of
+ * {@link org.apache.cocoon.forms.binding.JXPathBindingBase}.
+ *
+ * Common supported configurations: {@link #getCommonAttributes(Element)}
+ * <ul>
+ * <li>Attribute direction="load|save|both": defaults to 'both'</li>
+ * <li>Attribute lenient="true|false|[undefined]": defaults to [undefined]
+ * which means: "continue in same leniency-mode as parent" </li>
+ * </ul>
+ *
+ * @version $Id: JXPathBindingBuilderBase.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public abstract class JXPathBindingBuilderBase implements LogEnabled {
+
+ private Logger logger;
+
+ /**
+ * Receives the Avalon logger to use.
+ */
+ public void enableLogging(Logger logger) {
+ this.logger = logger;
+ if (logger.isDebugEnabled()) {
+ logger.debug("JXPathBindingBuilderBase got logger...");
+ }
+ }
+
+
+ /**
+ * Makes the logger available to the subclasses.
+ * @return Logger
+ */
+ protected Logger getLogger() {
+ return this.logger;
+ }
+
+ /**
+ * Builds a configured binding object based on the configuration as
+ * described in the bindingElement. The BuilderMap can be used to
+ * find appropriate builders for possible subBinders.
+ *
+ * @param bindingElm
+ * @param assistant
+ * @return JXPathBindingBase
+ */
+ public abstract JXPathBindingBase buildBinding(
+ Element bindingElm,
+ JXPathBindingManager.Assistant assistant) throws BindingException;
+
+ /**
+ * Helper method for interpreting the common attributes which are supported
+ * on each of the Bindings. These are
+ * <br>
+ * <code>@direction</code> can hold one of the following values:
+ * <ol><li><code>'load'</code>: This binding will only load.</li>
+ * <li><code>'save'</code>: This binding will only save.</li>
+ * <li><code>'both'</code>: This binding will perform both operations.</li>
+ * </ol>
+ * <br>
+ * <code>@lenient</code> can either be:
+ * <ol><li><code>'true'</code>: This binding will set the jxpath context to
+ * be lenient towards the usage of inexisting paths on the back-end model.</li>
+ * <li><code>'false'</code>: This binding will set the jxpath context to be
+ * strict and throwing exceptions for the usage of inexisting paths on the
+ * back-end model.</li>
+ * <li><code>(unset)</code>: This binding will not change the leniency behaviour
+ * on the jxpath this binding receives from his parent binding.</li>
+ * </ol>
+ * @param bindingElm
+ * @return an instance of CommonAttributes
+ * @throws BindingException
+ */
+ protected static CommonAttributes getCommonAttributes(Element bindingElm) throws BindingException {
+ try {
+ String location = DomHelper.getLocation(bindingElm);
+ //TODO: should we eventually remove this?
+ //throw an error if people are still using the old-style @read-only or @readonly
+ if (DomHelper.getAttributeAsBoolean(bindingElm, "readonly", false)) {
+ throw new BindingException("Error in binding file " + location
+ + "\nThe usage of the attribute @readonly has been deprecated in favour of @direction.");
+ }
+ if (DomHelper.getAttributeAsBoolean(bindingElm, "read-only", false)) {
+ throw new BindingException("Error in binding file " + location
+ + "\nThe usage of the attribute @read-only has been deprecated in favour of @direction.");
+ }
+
+ String direction = DomHelper.getAttribute(bindingElm, "direction", "both");
+
+ String leniency = DomHelper.getAttribute(bindingElm, "lenient", null);
+
+ //TODO: current jxpath is not inheriting registered namespaces over to
+ // child-relative jxpath contexts --> because of that we can't just
+ // remember the getLocalNSDeclarations but need the full set from
+ // getInheritedNSDeclarations
+ // IMPORTANT NOTE: if jxpath would change this behaviour we would however
+ // still need to be able to unregister namespace-declarations
+ // (in a smart way: unhide what is possably available from your parent.
+ // So both changes to jxpath need to be available before changing the below.
+ Map nsDeclarationMap = DomHelper.getInheritedNSDeclarations(bindingElm);
+ // we (actually jxpath) doesn't support un-prefixed namespace-declarations:
+ // so we decide to break on those above silently ignoring them
+ if (nsDeclarationMap != null && nsDeclarationMap.values().contains(null))
+ throw new BindingException("Error in binding file " + location
+ + "\nBinding doesn't support having namespace-declarations without explicit prefixes.");
+
+ return new CommonAttributes(location, direction, leniency, nsDeclarationMap);
+ } catch (BindingException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new BindingException("Error building binding defined at " + DomHelper.getLocation(bindingElm), e);
+ }
+ }
+
+ public static CommonAttributes mergeCommonAttributes(CommonAttributes existing, CommonAttributes extra) {
+
+ if (extra == null)
+ return existing;
+
+ Boolean leniency = null;
+ if(existing.leniency==null)
+ leniency = extra.leniency;
+ else
+ leniency = existing.leniency;
+
+ String strLeniency = null;
+ if(leniency != null)
+ strLeniency = leniency.toString();
+
+ String direction = existing.direction;
+ if(extra.direction!=null) // was defined
+ direction = extra.direction;
+
+
+ return new CommonAttributes(extra.location,direction,strLeniency,extra.nsDeclarations);
+ }
+
+ /**
+ * CommonAttributes is a simple helper class for holding the distinct data
+ * member fields indicating the activity of the sepearate load and save
+ * actions of a given binding.
+ */
+ protected static class CommonAttributes{
+
+ /**
+ * store direction (load/save enabledness) too for easier merging
+ */
+ String direction;
+ /**
+ * Source location of this binding.
+ */
+ final String location;
+ /**
+ * Flag which controls whether a binding is active during loading.
+ */
+ final boolean loadEnabled;
+ /**
+ * Flag which controls whether a binding is active during saving.
+ */
+ final boolean saveEnabled;
+ /**
+ * Flag which controls whether the jxpath context used by this binding
+ * should be operating in lenient mode or not
+ */
+ final Boolean leniency;
+ /**
+ * Array of namespace-declarations (prefix-uri pairs) that need to be set on the jxpath
+ */
+ final Map nsDeclarations;
+
+ final static CommonAttributes DEFAULT = new CommonAttributes("location unknown", true, true, null, null);
+
+ CommonAttributes(String location, String direction, String leniency, Map nsDeclarations){
+ this(location, isLoadEnabled(direction), isSaveEnabled(direction), decideLeniency(leniency), nsDeclarations);
+ this.direction = direction;
+ }
+
+ CommonAttributes(String location, boolean loadEnabled, boolean saveEnabled, Boolean leniency, Map nsDeclarations){
+ this.direction = null;
+ this.location = location;
+ this.loadEnabled = loadEnabled;
+ this.saveEnabled = saveEnabled;
+ this.leniency = leniency;
+ this.nsDeclarations = nsDeclarations;
+ }
+
+ /**
+ * Interpretes the value of the direction attribute into activity of the load action.
+ * @param direction
+ * @return true if direction is either set to "both" or "load"
+ */
+ private static boolean isLoadEnabled(String direction) {
+ return "both".equals(direction) || "load".equals(direction);
+ }
+
+ /**
+ * Interpretes the value of the direction attribute into activity of the save action.
+ * @param direction value of the @direction attribute
+ * @return true if direction is either set to "both" or "save"
+ */
+ private static boolean isSaveEnabled(String direction) {
+ return "both".equals(direction) || "save".equals(direction);
+ }
+
+
+ /**
+ * Interpretes the value of the lenient attribute into a Boolean object
+ * allowing three-state logic (true/false/unset)
+ * @param leniency value of the @lenient attribute
+ * @return null if the leniency parameter is null or a String otherwise the allowed values
+ */
+ private static Boolean decideLeniency(String leniency) {
+ return BooleanUtils.toBooleanObject(leniency);
+ }
+
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingBuilderBase.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingManager.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingManager.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingManager.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingManager.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,391 @@
+/*
+ * 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.binding;
+
+import java.util.ArrayList;
+import java.util.Stack;
+
+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.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+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.components.LifecycleHelper;
+import org.apache.cocoon.forms.CacheManager;
+import org.apache.cocoon.forms.binding.library.Library;
+import org.apache.cocoon.forms.binding.library.LibraryException;
+import org.apache.cocoon.forms.binding.library.LibraryManager;
+import org.apache.cocoon.forms.binding.library.LibraryManagerImpl;
+import org.apache.cocoon.forms.datatype.DatatypeManager;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.cocoon.forms.util.SimpleServiceSelector;
+import org.apache.cocoon.util.location.LocationAttributes;
+import org.apache.commons.lang.exception.NestableRuntimeException;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+
+/**
+ * JXPathBindingManager provides an implementation of {@link BindingManager}by
+ * usage of the <a href="http://jakarta.apache.org/commons/jxpath/index.html">
+ * JXPath package </a>.
+ *
+ * @version $Id: JXPathBindingManager.java 292615 2005-09-30 03:40:16Z antonio $
+ */
+public class JXPathBindingManager extends AbstractLogEnabled implements
+BindingManager, Contextualizable, Serviceable, Disposable, Initializable, Configurable,
+ThreadSafe {
+
+ private static final String PREFIX = "CocoonFormBinding:";
+
+ private ServiceManager manager;
+
+ private DatatypeManager datatypeManager;
+
+ private Configuration configuration;
+
+ private SimpleServiceSelector bindingBuilderSelector;
+
+ private CacheManager cacheManager;
+
+ private Context avalonContext;
+
+ private LibraryManagerImpl libraryManager;
+
+ public void contextualize(Context context) throws ContextException {
+ this.avalonContext = context;
+ }
+
+ public void service(ServiceManager manager) throws ServiceException {
+ this.manager = manager;
+ this.datatypeManager = (DatatypeManager) manager.lookup(DatatypeManager.ROLE);
+ this.cacheManager = (CacheManager) manager.lookup(CacheManager.ROLE);
+ }
+
+ public void configure(Configuration configuration)
+ throws ConfigurationException {
+ this.configuration = configuration;
+ }
+
+ public void initialize() throws Exception {
+ bindingBuilderSelector = new SimpleServiceSelector("binding",
+ JXPathBindingBuilderBase.class);
+ LifecycleHelper.setupComponent(bindingBuilderSelector,
+ getLogger(),
+ this.avalonContext,
+ this.manager,
+ configuration.getChild("bindings"));
+
+ libraryManager = new LibraryManagerImpl();
+ libraryManager.setBindingManager(this);
+ LifecycleHelper.setupComponent(libraryManager,
+ getLogger(),
+ this.avalonContext,
+ this.manager,
+ configuration.getChild("library"));
+ }
+
+ public Binding createBinding(Source source) throws BindingException {
+ Binding binding = (Binding) this.cacheManager.get(source, PREFIX);
+
+ if (binding != null && !binding.isValid())
+ binding = null; //invalidate
+
+ if (binding == null) {
+ try {
+ InputSource is = new InputSource(source.getInputStream());
+ is.setSystemId(source.getURI());
+
+ Document doc = DomHelper.parse(is, this.manager);
+ Element rootElm = doc.getDocumentElement();
+ if (BindingManager.NAMESPACE.equals(rootElm.getNamespaceURI())) {
+ binding = getBuilderAssistant()
+ .getBindingForConfigurationElement(rootElm);
+ ((JXPathBindingBase) binding).enableLogging(getLogger());
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Creation of new binding finished. " + binding);
+ }
+ } else {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Root Element of said binding file is in wrong namespace.");
+ }
+ }
+
+ this.cacheManager.set(binding, source, PREFIX);
+ } catch (BindingException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new BindingException("Error creating binding from " +
+ source.getURI(), e);
+ }
+ }
+
+ return binding;
+ }
+
+ public Binding createBinding(String bindingURI) throws BindingException {
+ SourceResolver sourceResolver = null;
+ Source source = null;
+
+ try {
+ try {
+ sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
+ source = sourceResolver.resolveURI(bindingURI);
+ } catch (Exception e) {
+ throw new BindingException("Error resolving binding source: " +
+ bindingURI);
+ }
+ return createBinding(source);
+ } finally {
+ if (source != null) {
+ sourceResolver.release(source);
+ }
+ if (sourceResolver != null) {
+ manager.release(sourceResolver);
+ }
+ }
+ }
+
+ public Assistant getBuilderAssistant() {
+ return new Assistant();
+ }
+
+ public void dispose() {
+ if (this.bindingBuilderSelector != null) {
+ this.bindingBuilderSelector.dispose();
+ this.bindingBuilderSelector = null;
+ }
+ this.manager.release(this.datatypeManager);
+ this.datatypeManager = null;
+ this.manager.release(this.cacheManager);
+ this.cacheManager = null;
+ this.manager = null;
+ }
+
+ /**
+ * Assistant Inner class discloses enough features to the created
+ * childBindings to recursively
+ *
+ * This patterns was chosen to prevent Inversion Of Control between this
+ * factory and its builder classes (that could be provided by third
+ * parties.)
+ */
+ /*
+ * NOTE: To get access to the logger in this inner class you must not call
+ * getLogger() as with JDK 1.3 this gives a NoSuchMethod error. You need to
+ * implement an explicit access method for the logger in the outer class.
+ */
+ public class Assistant {
+
+ private BindingBuilderContext context = new BindingBuilderContext();
+ private Stack contextStack = new Stack();
+
+ private JXPathBindingBuilderBase getBindingBuilder(String bindingType)
+ throws BindingException {
+ try {
+ return (JXPathBindingBuilderBase) bindingBuilderSelector
+ .select(bindingType);
+ } catch (ServiceException e) {
+ throw new BindingException(
+ "Cannot handle binding element with " + "name \""
+ + bindingType + "\".", e);
+ }
+ }
+
+ /**
+ * Creates a {@link Binding} following the specification in the
+ * provided config element.
+ */
+ public JXPathBindingBase getBindingForConfigurationElement(
+ Element configElm) throws BindingException {
+ String bindingType = configElm.getLocalName();
+ JXPathBindingBuilderBase bindingBuilder = getBindingBuilder(bindingType);
+
+ boolean flag = false;
+ if(context.getLocalLibrary() == null) {
+ Library lib = new Library(libraryManager);
+ context.setLocalLibrary(lib);
+ lib.setAssistant(getBuilderAssistant());
+ lib.setSourceURI(LocationAttributes.getURI(configElm));
+ flag = true;
+ }
+
+ if(context.getLocalLibrary()!=null
+ && configElm.hasAttribute("extends")) {
+ try {
+ context.setSuperBinding(context.getLocalLibrary().getBinding(configElm.getAttribute("extends")));
+
+ } catch(LibraryException e) {
+ //throw new RuntimeException("Error extending binding! (at "+DomHelper.getLocation(configElm)+")",e);
+ throw new NestableRuntimeException("Error extending binding! (at "+DomHelper.getLocation(configElm)+")",e);
+ }
+ } else {
+ context.setSuperBinding(null);
+ }
+
+ JXPathBindingBase childBinding = bindingBuilder.buildBinding(configElm, this);
+
+ if(flag && childBinding != null) {
+ childBinding.setLocalLibary(context.getLocalLibrary());
+ }
+
+ // this might get called unnecessarily, but solves issues with the libraries
+ if(childBinding != null)
+ childBinding.enableLogging(getLogger());
+
+
+ return childBinding;
+ }
+
+ private JXPathBindingBase[] mergeBindings(JXPathBindingBase[] existing, JXPathBindingBase[] extra) {
+
+ if(existing == null || existing.length == 0)
+ return extra;
+
+ if(extra == null || extra.length == 0)
+ return existing;
+
+ // have to do it the stupid painter way..
+ ArrayList list = new ArrayList(existing.length);
+ for(int i=0; i<existing.length; i++)
+ list.add(existing[i]);
+
+ for(int i=0; i<extra.length; i++) {
+ if(extra[i].getId()==null)
+ list.add(extra[i]);
+ else {
+ // try to replace existing one
+ boolean match = false;
+ for(int j=0; j<list.size(); j++) {
+ if(extra[i].getId().equals(((JXPathBindingBase)list.get(j)).getId())) {
+ list.set(j,extra[i]);
+ match = true;
+ break; // stop searching
+ }
+ }
+ // if no match, just add
+ if(!match)
+ list.add(extra[i]);
+ }
+ }
+
+ return (JXPathBindingBase[])list.toArray(new JXPathBindingBase[0]);
+ }
+
+ /**
+ * proxy for compatibility
+ *
+ */
+ public JXPathBindingBase[] makeChildBindings(Element parentElement) throws BindingException {
+ return makeChildBindings(parentElement,new JXPathBindingBase[0]);
+ }
+
+ /**
+ * Makes an array of childBindings for the child-elements of the
+ * provided configuration element.
+ */
+ public JXPathBindingBase[] makeChildBindings(Element parentElement, JXPathBindingBase[] existingBindings)
+ throws BindingException {
+ if (existingBindings == null)
+ existingBindings = new JXPathBindingBase[0];
+
+ if (parentElement != null) {
+ Element[] childElements = DomHelper.getChildElements(
+ parentElement, BindingManager.NAMESPACE);
+ if (childElements.length > 0) {
+ JXPathBindingBase[] childBindings = new JXPathBindingBase[childElements.length];
+ for (int i = 0; i < childElements.length; i++) {
+
+ pushContext();
+ context.setSuperBinding(null);
+
+ String id = DomHelper.getAttribute(childElements[i], "id", null);
+ String path = DomHelper.getAttribute(childElements[i], "path", null);
+ if(context.getLocalLibrary()!=null && childElements[i].getAttribute("extends")!=null) {
+ try {
+ context.setSuperBinding(context.getLocalLibrary().getBinding(childElements[i].getAttribute("extends")));
+
+ if(context.getSuperBinding() == null) // not found in library
+ context.setSuperBinding(getBindingByIdOrPath(id,path,existingBindings));
+
+ } catch(LibraryException e) {
+ throw new BindingException("Error extending binding! (at "+DomHelper.getLocation(childElements[i])+")",e);
+ }
+ }
+
+ childBindings[i] = getBindingForConfigurationElement(childElements[i]);
+
+ popContext();
+ }
+ return mergeBindings(existingBindings,childBindings);
+ }
+ }
+ return existingBindings;
+ }
+
+ private JXPathBindingBase getBindingByIdOrPath(String id, String path, JXPathBindingBase[] bindings) {
+ String name = id;
+ if(name == null) {
+ name = "Context:"+path;
+ }
+
+ for(int i=0; i<bindings.length; i++) {
+ if(name.equals(bindings[i].getId()))
+ return bindings[i];
+ }
+ return null;
+ }
+
+ public DatatypeManager getDatatypeManager() {
+ return datatypeManager;
+ }
+
+ public ServiceManager getServiceManager() {
+ return manager;
+ }
+
+ public LibraryManager getLibraryManager() {
+ return libraryManager;
+ }
+
+ public BindingBuilderContext getContext() {
+ return this.context;
+ }
+ private void pushContext() {
+ BindingBuilderContext c = new BindingBuilderContext(context);
+ contextStack.push(context);
+ context = c;
+ }
+ private void popContext() {
+ if(!contextStack.empty()) {
+ context = (BindingBuilderContext)contextStack.pop();
+ } else {
+ context = new BindingBuilderContext();
+ }
+ }
+
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JXPathBindingManager.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBinding.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBinding.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBinding.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBinding.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,130 @@
+/*
+ * 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.binding;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.CascadingRuntimeException;
+import org.apache.avalon.framework.context.Context;
+import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.components.flow.javascript.ScriptableMap;
+import org.apache.cocoon.forms.formmodel.Widget;
+import org.apache.cocoon.forms.util.JavaScriptHelper;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.Pointer;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.Scriptable;
+
+/**
+ *
+ * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
+ * @version $Id: JavaScriptJXPathBinding.java 327146 2005-10-21 10:38:37Z sylvain $
+ */
+public class JavaScriptJXPathBinding extends JXPathBindingBase {
+
+ private final Context avalonContext;
+ private final String id;
+ private final String path;
+ private final Function loadScript;
+ private final Function saveScript;
+ private final Scriptable childBindings;
+ private final Map childBindingsMap;
+
+ final static String[] LOAD_PARAMS = { "widget", "jxpathPointer", "jxpathContext", "childBindings" };
+ final static String[] SAVE_PARAMS = { "widget", "jxpathPointer", "jxpathContext", "childBindings" };
+
+ public JavaScriptJXPathBinding(
+ Context context, JXPathBindingBuilderBase.CommonAttributes commonAtts, String id,
+ String path, Function loadScript, Function saveScript, Map childBindings) {
+ super(commonAtts);
+ this.id = id;
+ this.path = path;
+ this.loadScript = loadScript;
+ this.saveScript = saveScript;
+ this.avalonContext = context;
+
+ // Set parent on child bindings
+ for(Iterator iter = childBindings.values().iterator(); iter.hasNext(); ) {
+ ((Binding)iter.next()).setParent(this);
+ }
+
+ this.childBindingsMap = childBindings;
+ this.childBindings = new ScriptableMap(childBindings);
+ }
+
+ public String getPath() { return path; }
+ public String getId() { return id; }
+ public Context getContext() { return avalonContext; }
+ public Function getLoadScript() { return loadScript; }
+ public Function getSaveScript() { return saveScript; }
+ public Map getChildBindingsMap() { return childBindingsMap; }
+
+ public void doLoad(Widget frmModel, JXPathContext jctx) {
+ if (this.loadScript != null) {
+ Widget widget = selectWidget(frmModel,this.id);
+
+ // Move to widget context
+ Pointer pointer = jctx.getPointer(this.path);
+
+ Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
+
+ try {
+ JXPathContext newCtx = pointer.getNode() == null ? null :
+ jctx.getRelativeContext(pointer);
+
+ JavaScriptHelper.callFunction(this.loadScript, widget,
+ new Object[] {widget, pointer, newCtx, this.childBindings}, objectModel);
+
+ } catch(RuntimeException re) {
+ // rethrow
+ throw re;
+ } catch(Exception e) {
+ throw new CascadingRuntimeException("Error invoking JavaScript event handler", e);
+ }
+ } else {
+ if (this.getLogger().isInfoEnabled()) {
+ this.getLogger().info("[Javascript Binding] - loadForm: No javascript code avaliable. Widget id=" + this.getId());
+ }
+ }
+ }
+
+ public void doSave(Widget frmModel, JXPathContext jctx) throws BindingException {
+ if (this.saveScript != null) {
+ Widget widget = selectWidget(frmModel,this.id);
+
+ // Move to widget context and create the path if needed
+ Pointer pointer = jctx.createPath(this.path);
+ JXPathContext widgetCtx = jctx.getRelativeContext(pointer);
+ try {
+ Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
+
+ JavaScriptHelper.callFunction(this.saveScript, widget,
+ new Object[] {widget, pointer, widgetCtx, this.childBindings}, objectModel);
+
+ } catch(RuntimeException re) {
+ // rethrow
+ throw re;
+ } catch(Exception e) {
+ throw new CascadingRuntimeException("Error invoking JavaScript event handler", e);
+ }
+ } else {
+ if (this.getLogger().isInfoEnabled()) {
+ this.getLogger().info("[Javascript Binding] - saveForm: No code avaliable on the javascript binding with id \"" + this.getId() + "\"");
+ }
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBinding.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBindingBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBindingBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBindingBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBindingBuilder.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,170 @@
+/*
+ * 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.binding;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.cocoon.forms.binding.JXPathBindingManager.Assistant;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.cocoon.forms.util.JavaScriptHelper;
+import org.mozilla.javascript.Function;
+import org.w3c.dom.Element;
+
+/**
+ * Builds a {@link Binding} based on two JavaScript snippets, respectively for loading and saving the form.
+ * This binding also optionally accepts named child bindings, which are useful when the bound widget is a container.
+ * <p>
+ * The syntax for this binding is as follows:
+ * <pre>
+ * <fb:javascript id="foo" path="@foo">
+ * <fb:load-form>
+ * var appValue = jxpathPointer.getValue();
+ * var formValue = doLoadConversion(appValue);
+ * widget.setValue(formValue);
+ * childBindings["foo"].loadFormFromModel(widget, jxpathContext);
+ * </fb:load-form>
+ * <fb:save-form>
+ * var formValue = widget.getValue();
+ * var appValue = doSaveConversion(formValue);
+ * jxpathPointer.setValue(appValue);
+ * childBindings["foo"].saveFormToModel(widget, jxpathContext);
+ * </fb:save-form>
+ * <fb:child-binding name="foo">
+ * <fb:value id="bar" path="baz"/>
+ * </fb:child-binding>
+ * </fb:javascript>
+ * </pre>
+ * This example is rather trivial and could be replaced by a simple <fb:value>, but
+ * it shows the available variables in the script:
+ * <ul>
+ * <li><code>widget</code>: the widget identified by the "id" attribute,
+ * <li><code>jxpathPointer</code>: the JXPath pointer corresponding to the "path" attribute,
+ * <li><code>jxpathContext</code> (not shown): the JXPath context corresponding to the "path" attribute
+ * </ul>
+ * <b>Notes:</b><ul>
+ * <li>The <fb:save-form> snippet should be ommitted if the "direction" attribute is set to "load".</li>
+ * <li>The <fb:load-form> snippet should be ommitted if the "direction" attribute is set to "save".</li>
+ * </ul>
+ *
+ * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
+ * @version $Id: JavaScriptJXPathBindingBuilder.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public class JavaScriptJXPathBindingBuilder extends JXPathBindingBuilderBase implements Contextualizable {
+
+ private Context avalonContext;
+
+ public void contextualize(Context context) throws ContextException {
+ this.avalonContext = context;
+ }
+
+ public JXPathBindingBase buildBinding(Element element, Assistant assistant) throws BindingException {
+ try {
+ CommonAttributes commonAtts = JXPathBindingBuilderBase.getCommonAttributes(element);
+
+ String id = DomHelper.getAttribute(element, "id", null);
+ String path = DomHelper.getAttribute(element, "path", null);
+
+ JavaScriptJXPathBinding otherBinding = (JavaScriptJXPathBinding)assistant.getContext().getSuperBinding();
+
+ if(otherBinding!=null) {
+ commonAtts = JXPathBindingBuilderBase.mergeCommonAttributes(otherBinding.getCommonAtts(),commonAtts);
+
+ if(id==null)
+ id=otherBinding.getId();
+ if(path==null)
+ path=otherBinding.getPath();
+ }
+
+ // Build load script
+ Function loadScript = null;
+ if (commonAtts.loadEnabled) {
+ if (otherBinding != null)
+ loadScript = otherBinding.getLoadScript();
+
+ Element loadElem = DomHelper.getChildElement(element, BindingManager.NAMESPACE, "load-form");
+ if (loadElem != null) {
+ loadScript = JavaScriptHelper.buildFunction(loadElem, "loadForm", JavaScriptJXPathBinding.LOAD_PARAMS);
+ }
+ }
+
+ // Build save script
+ Function saveScript = null;
+ if (commonAtts.saveEnabled) {
+ if (otherBinding != null)
+ saveScript = otherBinding.getSaveScript();
+
+ Element saveElem = DomHelper.getChildElement(element, BindingManager.NAMESPACE, "save-form");
+ if (saveElem != null) {
+ saveScript = JavaScriptHelper.buildFunction(saveElem, "saveForm", JavaScriptJXPathBinding.SAVE_PARAMS);
+ }
+ }
+
+ // Build child bindings
+ Map childBindings = new HashMap();
+
+ if (otherBinding != null) {
+ Map otherChildren = otherBinding.getChildBindingsMap();
+ Iterator it = otherChildren.entrySet().iterator();
+ while(it.hasNext()) {
+ Map.Entry entry = (Map.Entry)it.next();
+ childBindings.put(entry.getKey(),entry.getValue());
+ }
+ }
+
+ Element[] children = DomHelper.getChildElements(element, BindingManager.NAMESPACE, "child-binding");
+ if (children.length != 0) {
+ for (int i = 0; i < children.length; i++) {
+ Element child = children[i];
+
+ // Get the binding name and check its uniqueness
+ String name = DomHelper.getAttribute(child, "name");
+
+ JXPathBindingBase[] otherBindings = null;
+ if (childBindings.containsKey(name)) {
+ //throw new BindingException("Duplicate name '" + name + "' at " + DomHelper.getLocation(child));
+ otherBindings = ((ComposedJXPathBindingBase)childBindings.get(name)).getChildBindings();
+ }
+
+ // Build the child binding
+ JXPathBindingBase[] bindings = assistant.makeChildBindings(child,otherBindings);
+ if (bindings == null) {
+ bindings = new JXPathBindingBase[0];
+ }
+
+ ComposedJXPathBindingBase composedBinding = new ComposedJXPathBindingBase(commonAtts, bindings);
+ composedBinding.enableLogging(getLogger());
+ childBindings.put(name, composedBinding);
+ }
+ }
+
+ JXPathBindingBase result = new JavaScriptJXPathBinding(this.avalonContext, commonAtts, id, path, loadScript, saveScript,
+ Collections.unmodifiableMap(childBindings));
+ result.enableLogging(getLogger());
+ return result;
+
+ } catch(BindingException be) {
+ throw be;
+ } catch(Exception e) {
+ throw new BindingException("Cannot build binding at " + DomHelper.getLocation(element), e);
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/JavaScriptJXPathBindingBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBinding.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBinding.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBinding.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBinding.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,174 @@
+/*
+ * 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.binding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.cocoon.forms.datatype.convertor.Convertor;
+import org.apache.cocoon.forms.datatype.convertor.ConversionResult;
+import org.apache.cocoon.forms.formmodel.Widget;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.Pointer;
+
+/**
+ * Simple binding for multi fields: on save, first deletes the target data
+ * before recreating it from scratch.
+ *
+ * @version $Id: MultiValueJXPathBinding.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public class MultiValueJXPathBinding extends JXPathBindingBase {
+
+ private final String multiValueId;
+ private final String multiValuePath;
+ private final String rowPath;
+ private final JXPathBindingBase updateBinding;
+ private final Convertor convertor;
+ private final Locale convertorLocale;
+
+ public MultiValueJXPathBinding(
+ JXPathBindingBuilderBase.CommonAttributes commonAtts, String multiValueId,
+ String multiValuePath, String rowPath,
+ JXPathBindingBase[] updateBindings, Convertor convertor, Locale convertorLocale) {
+ super(commonAtts);
+ this.multiValueId = multiValueId;
+ this.multiValuePath = multiValuePath;
+ this.rowPath = rowPath;
+ this.updateBinding = new ComposedJXPathBindingBase(JXPathBindingBuilderBase.CommonAttributes.DEFAULT, updateBindings);
+ this.convertor = convertor;
+ this.convertorLocale = convertorLocale;
+ }
+
+ public String getId() { return multiValueId; }
+ public String getMultiValuePath() { return multiValuePath; }
+ public String getRowPath() { return rowPath; }
+ public ComposedJXPathBindingBase getUpdateBinding() { return (ComposedJXPathBindingBase)updateBinding; }
+ public Convertor getConvertor() { return convertor; }
+ public Locale getLocale() { return convertorLocale; }
+
+ public void doLoad(Widget frmModel, JXPathContext jctx) throws BindingException {
+ Widget widget = selectWidget(frmModel,this.multiValueId);
+ if (widget == null) {
+ throw new BindingException("The widget with the ID [" + this.multiValueId
+ + "] referenced in the binding does not exist in the form definition.");
+ }
+
+ // Move to multi value context
+ Pointer ptr = jctx.getPointer(this.multiValuePath);
+ if (ptr.getNode() != null) {
+ // There are some nodes to load from
+
+ JXPathContext multiValueContext = jctx.getRelativeContext(ptr);
+ // build a jxpath iterator for pointers
+ Iterator rowPointers = multiValueContext.iterate(this.rowPath);
+
+ LinkedList list = new LinkedList();
+
+ while (rowPointers.hasNext()) {
+ Object value = rowPointers.next();
+
+ if (value != null && convertor != null) {
+ if (value instanceof String) {
+ ConversionResult conversionResult = convertor.convertFromString((String)value, convertorLocale, null);
+ if (conversionResult.isSuccessful())
+ value = conversionResult.getResult();
+ else
+ value = null;
+ } else {
+ getLogger().warn("Convertor ignored on backend-value which isn't of type String.");
+ }
+ }
+
+ list.add(value);
+ }
+
+ widget.setValue(list.toArray());
+ }
+
+ if (getLogger().isDebugEnabled())
+ getLogger().debug("done loading values " + toString());
+ }
+
+ public void doSave(Widget frmModel, JXPathContext jctx) throws BindingException {
+ Widget widget = selectWidget(frmModel,this.multiValueId);
+ Object[] values = (Object[])widget.getValue();
+
+ JXPathContext multiValueContext = jctx.getRelativeContext(jctx.createPath(this.multiValuePath));
+
+ // Delete all that is already present
+
+ // Unfortunately the following statement doesn't work (it doesn't removes all elements from the
+ // list because of a bug in JXPath) so I had to work out another immediate solution
+ //multiValueContext.removeAll(this.rowPath);
+
+ Iterator rowPointers = multiValueContext.iteratePointers(this.rowPath);
+ List l = new ArrayList();
+ while( rowPointers.hasNext() )
+ {
+ Pointer p = (Pointer)rowPointers.next();
+ l.add(p.asPath());
+ }
+ Collections.sort(l);
+ for( int i = l.size()-1; i >= 0; i-- )
+ {
+ multiValueContext.removePath((String)l.get(i));
+ }
+
+ boolean update = false;
+
+ if (values != null) {
+ // first update the values
+ for (int i = 0; i < values.length; i++) {
+ String path = this.rowPath + '[' + (i+1) + ']';
+ Pointer rowPtr = multiValueContext.createPath(path);
+
+ Object value = values[i];
+ if (value != null && convertor != null) {
+ value = convertor.convertToString(value, convertorLocale, null);
+ }
+
+ rowPtr.setValue(value);
+ }
+
+ // now perform any other bindings that need to be performed when the value is updated
+ this.updateBinding.saveFormToModel(frmModel, multiValueContext);
+
+ update = true;
+ }
+
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("done saving " + toString() + " -- on-update == " + update);
+ }
+
+
+
+ }
+
+ public String toString() {
+ return "MultiValueJXPathBinding [widget=" + this.multiValueId + ", xpath=" + this.multiValuePath + "]";
+ }
+
+ public void enableLogging(Logger logger) {
+ super.enableLogging(logger);
+ this.updateBinding.enableLogging(logger);
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBinding.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBindingBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBindingBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBindingBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBindingBuilder.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,102 @@
+/*
+ * 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.binding;
+
+import java.util.Locale;
+
+import org.apache.cocoon.forms.FormsConstants;
+import org.apache.cocoon.forms.datatype.convertor.Convertor;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.apache.cocoon.i18n.I18nUtils;
+import org.w3c.dom.Element;
+
+/**
+ * A simple multi field binding that will replace (i.e. delete then re-add all) its
+ * content.
+ * <pre><code>
+ * <fb:multi-value id="<i>widget-id</i>"
+ * parent-path="<i>xpath-expression</i>"
+ * row-path="<i>xpath-expression</i>">
+ * <!-- optional child binding to be executed upon 'save' of changed value -->
+ * <fb:on-update>
+ * <!-- any childbinding -->
+ * </fb:on-update>
+ * </fb:multi-value>
+ * </code></pre>
+ *
+ * @version $Id: MultiValueJXPathBindingBuilder.java 326838 2005-10-20 06:26:53Z sylvain $
+ */
+public class MultiValueJXPathBindingBuilder
+ extends JXPathBindingBuilderBase {
+
+ public JXPathBindingBase buildBinding(
+ Element bindingElem,
+ JXPathBindingManager.Assistant assistant) throws BindingException {
+
+ try {
+ CommonAttributes commonAtts = JXPathBindingBuilderBase.getCommonAttributes(bindingElem);
+
+ String multiValueId = DomHelper.getAttribute(bindingElem, "id", null);
+ String parentPath = DomHelper.getAttribute(bindingElem, "parent-path", null);
+ String rowPath = DomHelper.getAttribute(bindingElem, "row-path", null);
+
+
+ Convertor convertor = null;
+ Locale convertorLocale = Locale.US;
+ Element convertorEl = DomHelper.getChildElement(bindingElem, FormsConstants.DEFINITION_NS, "convertor");
+ if (convertorEl != null) {
+ String datatype = DomHelper.getAttribute(convertorEl, "datatype", null);
+ String localeStr = DomHelper.getAttribute(convertorEl, "locale", null);
+ if (localeStr != null) {
+ convertorLocale = I18nUtils.parseLocale(localeStr);
+ }
+
+ convertor = assistant.getDatatypeManager().createConvertor(datatype, convertorEl);
+ }
+
+ MultiValueJXPathBinding existingBinding = (MultiValueJXPathBinding)assistant.getContext().getSuperBinding();
+ JXPathBindingBase[] existingBindings = new JXPathBindingBase[0];
+ if(existingBinding != null) {
+ commonAtts = JXPathBindingBuilderBase.mergeCommonAttributes(existingBinding.getCommonAtts(),commonAtts);
+ existingBindings = existingBinding.getUpdateBinding().getChildBindings();
+
+ if(multiValueId == null)
+ multiValueId = existingBinding.getId();
+ if(parentPath == null)
+ parentPath = existingBinding.getMultiValuePath();
+ if(rowPath == null)
+ rowPath = existingBinding.getRowPath();
+
+ if(convertor == null) {
+ convertor = existingBinding.getConvertor();
+ convertorLocale = existingBinding.getLocale();
+ }
+ }
+
+ Element updateWrapElement =
+ DomHelper.getChildElement(bindingElem, BindingManager.NAMESPACE, "on-update");
+ JXPathBindingBase[] updateBindings = assistant.makeChildBindings(updateWrapElement,existingBindings);
+
+
+ return new MultiValueJXPathBinding( commonAtts, multiValueId, parentPath, rowPath,
+ updateBindings, convertor, convertorLocale);
+ } catch (BindingException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new BindingException("Error building multi value binding defined at " + DomHelper.getLocation(bindingElem), e);
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/MultiValueJXPathBindingBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBinding.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBinding.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBinding.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBinding.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,100 @@
+/*
+ * 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.binding;
+
+import org.apache.cocoon.forms.formmodel.Widget;
+import org.apache.commons.jxpath.JXPathContext;
+
+/**
+ * NewJXPathBinding provides an implementation of a {@link Binding}
+ * that references a class of bindings.
+ * <p>
+ * NOTES: <ol>
+ * <li>This Binding assumes that the provided widget-id points to a
+ * class that contains other widgets.</li>
+ * </ol>
+ *
+ * @version $Id: NewJXPathBinding.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public class NewJXPathBinding extends ComposedJXPathBindingBase {
+
+ private final String widgetId;
+
+ private Binding classBinding;
+
+ /**
+ * Constructs NewJXPathBinding
+ * @param commonAtts
+ * @param widgetId
+ * @param childBindings
+ */
+ public NewJXPathBinding(JXPathBindingBuilderBase.CommonAttributes commonAtts,
+ String widgetId, JXPathBindingBase[] childBindings) {
+ super(commonAtts, childBindings);
+ this.widgetId = widgetId;
+ this.classBinding = null;
+ }
+
+ public String getId() { return widgetId; }
+
+ /**
+ * Recursively resolves references.
+ */
+ private void resolve() throws BindingException {
+ classBinding = getClass(widgetId);
+ if (classBinding == null) {
+ throw new BindingException("Class \"" + widgetId + "\" does not exist");
+ }
+ }
+
+ /**
+ * Narrows the scope on the form-model to the member widget-field, and
+ * narrows the scope on the object-model to the member xpath-context
+ * before continuing the binding over the child-bindings.
+ */
+ public void doLoad(Widget frmModel, JXPathContext jxpc) throws BindingException {
+ if (classBinding == null)
+ resolve();
+ Binding[] subBindings = ((ComposedJXPathBindingBase)classBinding).getChildBindings();
+ if (subBindings != null) {
+ int size = subBindings.length;
+ for (int i = 0; i < size; i++) {
+ subBindings[i].loadFormFromModel(frmModel, jxpc);
+ }
+ }
+ }
+
+ /**
+ * Narrows the scope on the form-model to the member widget-field, and
+ * narrows the scope on the object-model to the member xpath-context
+ * before continuing the binding over the child-bindings.
+ */
+ public void doSave(Widget frmModel, JXPathContext jxpc) throws BindingException {
+ if (classBinding == null)
+ resolve();
+ Binding[] subBindings = ((ComposedJXPathBindingBase)classBinding).getChildBindings();
+ if (subBindings != null) {
+ int size = subBindings.length;
+ for (int i = 0; i < size; i++) {
+ subBindings[i].saveFormToModel(frmModel, jxpc);
+ }
+ }
+ }
+
+ public String toString() {
+ return "NewJXPathBinding [widget=" + this.widgetId + "]";
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBinding.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBindingBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBindingBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBindingBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBindingBuilder.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,66 @@
+/*
+ * 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.binding;
+
+import org.apache.cocoon.forms.util.DomHelper;
+import org.w3c.dom.Element;
+
+/**
+ * NewJXPathBindingBuilder provides a helper class for the Factory
+ * implemented in {@link JXPathBindingManager} that helps construct the
+ * actual {@link NewJXPathBinding} out of the configuration in the
+ * provided configElement which looks like:
+ * <pre><code>
+ * <fb:new id="<i>widget-id</i>">
+ * <fb:field id="<i>sub-widget-id</i>" path="<i>relative-xpath</i>"
+ * direction="<i>load|save</i>" lenient="<i>true/false</i>"/>
+ * </fb:new>
+ * </code></pre>
+ *
+ * @version $Id: NewJXPathBindingBuilder.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public class NewJXPathBindingBuilder
+ extends JXPathBindingBuilderBase {
+
+ public JXPathBindingBase buildBinding(Element bindingElm, JXPathBindingManager.Assistant assistant)
+ throws BindingException {
+ try {
+ String widgetId = DomHelper.getAttribute(bindingElm, "id", null);
+ CommonAttributes commonAtts = JXPathBindingBuilderBase.getCommonAttributes(bindingElm);
+
+ JXPathBindingBase[] childBindings = new JXPathBindingBase[0];
+
+// do inheritance
+ NewJXPathBinding otherBinding = (NewJXPathBinding)assistant.getContext().getSuperBinding();
+ if(otherBinding!=null) {
+ childBindings = otherBinding.getChildBindings();
+ commonAtts = JXPathBindingBuilderBase.mergeCommonAttributes(otherBinding.getCommonAtts(),commonAtts);
+
+ if(widgetId==null)
+ widgetId = otherBinding.getId();
+ }
+
+ childBindings = assistant.makeChildBindings(bindingElm,childBindings);
+
+ NewJXPathBinding newBinding = new NewJXPathBinding(commonAtts, widgetId, childBindings);
+ return newBinding;
+ } catch (BindingException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new BindingException("Error building new binding defined at " + DomHelper.getLocation(bindingElm), e);
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/NewJXPathBindingBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/RepeaterJXPathBinding.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/RepeaterJXPathBinding.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/RepeaterJXPathBinding.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/RepeaterJXPathBinding.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,390 @@
+/*
+ * 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.binding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.cocoon.forms.formmodel.Repeater;
+import org.apache.cocoon.forms.formmodel.Widget;
+import org.apache.cocoon.forms.datatype.convertor.ConversionResult;
+import org.apache.commons.collections.ListUtils;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.Pointer;
+
+/**
+ * RepeaterJXPathBinding provides an implementation of a {@link Binding}
+ * that allows for bidirectional binding of a repeater-widget to/from
+ * repeating structures in the back-end object model.
+ *
+ * @version $Id: RepeaterJXPathBinding.java 290473 2005-09-20 15:30:48Z sylvain $
+ */
+public class RepeaterJXPathBinding extends JXPathBindingBase {
+
+ private final String repeaterId;
+ private final String repeaterPath;
+ private final String rowPath;
+ private final String rowPathForInsert;
+ private final JXPathBindingBase rowBinding;
+ private final JXPathBindingBase insertRowBinding;
+ private final JXPathBindingBase deleteRowBinding;
+ private final ComposedJXPathBindingBase identityBinding;
+
+ /**
+ * Constructs RepeaterJXPathBinding
+ */
+ public RepeaterJXPathBinding(
+ JXPathBindingBuilderBase.CommonAttributes commonAtts,
+ String repeaterId, String repeaterPath, String rowPath,
+ String rowPathForInsert,
+ JXPathBindingBase[] childBindings, JXPathBindingBase insertBinding,
+ JXPathBindingBase[] deleteBindings, JXPathBindingBase[] identityBindings) {
+ super(commonAtts);
+ this.repeaterId = repeaterId;
+ this.repeaterPath = repeaterPath;
+ this.rowPath = rowPath;
+ this.rowPathForInsert = rowPathForInsert;
+
+ this.rowBinding = new ComposedJXPathBindingBase(
+ JXPathBindingBuilderBase.CommonAttributes.DEFAULT,
+ childBindings);
+ this.rowBinding.setParent(this);
+
+ this.insertRowBinding = insertBinding;
+ if (this.insertRowBinding != null) {
+ this.insertRowBinding.setParent(this);
+ }
+
+ if (deleteBindings != null) {
+ this.deleteRowBinding = new ComposedJXPathBindingBase(
+ JXPathBindingBuilderBase.CommonAttributes.DEFAULT,
+ deleteBindings);
+ this.deleteRowBinding.setParent(this);
+ } else {
+ this.deleteRowBinding = null;
+ }
+
+
+ if (identityBindings != null) {
+
+ this.identityBinding = new ComposedJXPathBindingBase(
+ JXPathBindingBuilderBase.CommonAttributes.DEFAULT,
+ identityBindings);
+ this.identityBinding.setParent(this);
+ }
+ else
+ this.identityBinding = null;
+ }
+
+ public String getId() { return repeaterId; }
+ public String getRepeaterPath() { return repeaterPath; }
+ public String getRowPath() { return rowPath; }
+ public String getInsertRowPath() { return rowPathForInsert; }
+ public ComposedJXPathBindingBase getRowBinding() { return (ComposedJXPathBindingBase)rowBinding; }
+ public ComposedJXPathBindingBase getDeleteRowBinding() { return (ComposedJXPathBindingBase)deleteRowBinding; }
+ public ComposedJXPathBindingBase getIdentityBinding() { return (ComposedJXPathBindingBase)identityBinding; }
+ public JXPathBindingBase getInsertRowBinding() { return insertRowBinding; }
+
+ /**
+ * Binds the unique-id of the repeated rows, and narrows the context on
+ * objectModelContext and Repeater to the repeated rows before handing
+ * over to the actual binding-children.
+ */
+ public void doLoad(Widget frmModel, JXPathContext jxpc)
+ throws BindingException {
+ // Find the repeater
+ Repeater repeater = (Repeater) selectWidget(frmModel, this.repeaterId);
+ if (repeater == null) {
+ throw new BindingException("The repeater with the ID [" + this.repeaterId
+ + "] referenced in the binding does not exist in the form definition.");
+ }
+ repeater.clear();
+ int initialSize = repeater.getSize();
+
+ // build a jxpath iterator for pointers
+ JXPathContext repeaterContext =
+ jxpc.getRelativeContext(jxpc.getPointer(this.repeaterPath));
+ Iterator rowPointers = repeaterContext.iteratePointers(this.rowPath);
+ //iterate through it
+ while (rowPointers.hasNext()) {
+ // create a new row, take that as the frmModelSubContext
+ Repeater.RepeaterRow thisRow;
+ if (initialSize > 0) {
+ thisRow = repeater.getRow(--initialSize);
+ } else {
+ thisRow = repeater.addRow();
+ }
+ // make a jxpath ObjectModelSubcontext on the iterated element
+ Pointer jxp = (Pointer)rowPointers.next();
+ JXPathContext rowContext = repeaterContext.getRelativeContext(jxp);
+ // hand it over to children
+ if (this.identityBinding != null) {
+ this.identityBinding.loadFormFromModel(thisRow, rowContext);
+ }
+ this.rowBinding.loadFormFromModel(thisRow, rowContext);
+ }
+ if (getLogger().isDebugEnabled())
+ getLogger().debug("done loading rows " + toString());
+ }
+
+ /**
+ * Uses the mapped identity of each row to detect if rows have been
+ * updated, inserted or removed. Depending on what happened the appropriate
+ * child-bindings are allowed to visit the narrowed contexts.
+ */
+ public void doSave(Widget frmModel, JXPathContext jxpc)
+ throws BindingException {
+ // Find the repeater
+ Repeater repeater = (Repeater) selectWidget(frmModel, this.repeaterId);
+ // and his context
+ JXPathContext repeaterContext =
+ jxpc.getRelativeContext(jxpc.getPointer(this.repeaterPath));
+
+ // create set of updatedRowIds
+ Set updatedRows = new HashSet();
+ //create list of rows to insert at end
+ List rowsToInsert = new ArrayList();
+
+ // iterate rows in the form model...
+ int formRowCount = repeater.getSize();
+ for (int i = 0; i < formRowCount; i++) {
+ Repeater.RepeaterRow thisRow = repeater.getRow(i);
+
+ // Get the identity
+ List identity = getIdentity(thisRow);
+
+ if (hasNonNullElements(identity)) {
+ // iterate nodes to find match
+ Iterator rowPointers = repeaterContext.iteratePointers(this.rowPath);
+ boolean found = false;
+ while (rowPointers.hasNext()) {
+ Pointer jxp = (Pointer) rowPointers.next();
+ JXPathContext rowContext = repeaterContext.getRelativeContext(jxp);
+ List contextIdentity = getIdentity(rowContext);
+ if (ListUtils.isEqualList(identity, contextIdentity)) {
+ // match! --> bind to children
+ this.rowBinding.saveFormToModel(thisRow, rowContext);
+ // --> store rowIdValue in list of updatedRowIds
+ updatedRows.add(identity);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // this is a new row
+ rowsToInsert.add(thisRow);
+ // also add it to the updated row id's so that this row doesn't get deleted
+ updatedRows.add(identity);
+ }
+ } else {
+ // if there is no value to determine the identity --> this is a new row
+ rowsToInsert.add(thisRow);
+ }
+ }
+ // Iterate again nodes for deletion
+ Iterator rowPointers = repeaterContext.iteratePointers(this.rowPath);
+ List rowsToDelete = new ArrayList();
+ while (rowPointers.hasNext()) {
+ Pointer jxp = (Pointer)rowPointers.next();
+ JXPathContext rowContext = repeaterContext.getRelativeContext((Pointer)jxp.clone());
+ List contextIdentity = getIdentity(rowContext);
+ // check if the identity of the rowContext is in the updated rows
+ // if not --> bind for delete
+ if (!isIdentityInUpdatedRows(updatedRows, contextIdentity)) {
+ rowsToDelete.add(rowContext);
+ }
+ }
+ if (rowsToDelete.size() > 0) {
+ if (this.deleteRowBinding != null) {
+ // run backwards through the list, so that we don't get into
+ // trouble by shifting indexes
+ for (int i = rowsToDelete.size() - 1; i >= 0; i--) {
+ this.deleteRowBinding.saveFormToModel(frmModel,
+ rowsToDelete.get(i));
+ }
+ } else {
+ if (getLogger().isWarnEnabled()) {
+ getLogger().warn(
+ "RepeaterBinding has detected rows to delete, " +
+ "but misses the <on-delete-row> binding to do it."
+ );
+ }
+ }
+ }
+ // count how many we have now
+ int indexCount = 1;
+ rowPointers = repeaterContext.iteratePointers(this.rowPathForInsert);
+ while (rowPointers.hasNext()) {
+ rowPointers.next();
+ indexCount++;
+ }
+ // end with rows to insert (to make sure they don't get deleted!)
+ if (rowsToInsert.size() > 0) {
+ if (this.insertRowBinding != null) {
+ Iterator rowIterator = rowsToInsert.iterator();
+ //register the factory!
+ while (rowIterator.hasNext()) {
+ Repeater.RepeaterRow thisRow = (Repeater.RepeaterRow)rowIterator.next();
+ // Perform the insert row binding.
+ this.insertRowBinding.saveFormToModel(repeater, repeaterContext);
+ // --> create the path to let the context be created
+ Pointer newRowContextPointer = repeaterContext.createPath(
+ this.rowPathForInsert + "[" + indexCount + "]");
+ JXPathContext newRowContext =
+ repeaterContext.getRelativeContext(newRowContextPointer);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("inserted row at " + newRowContextPointer.asPath());
+ }
+ // + rebind to children for update
+ this.rowBinding.saveFormToModel(thisRow, newRowContext);
+ getLogger().debug("bound new row");
+ indexCount++;
+ }
+ } else {
+ if (getLogger().isWarnEnabled()) {
+ getLogger().warn("RepeaterBinding has detected rows to insert, but misses "
+ + "the <on-insert-row> binding to do it.");
+ }
+ }
+ }
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("done saving rows " + toString());
+ }
+ }
+
+ /**
+ * Tests if an identity is already contained in a Set of identities.
+ * @param identitySet the Set of identities.
+ * @param identity the identity that is tested if it is already in the Set.
+ * @return true if the Set contains the identity, false otherwise.
+ */
+ private boolean isIdentityInUpdatedRows(Set identitySet, List identity) {
+ Iterator iter = identitySet.iterator();
+ while (iter.hasNext()) {
+ List identityFromSet = (List)iter.next();
+ if (ListUtils.isEqualList(identityFromSet, identity)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tests if any of the elements in a List is not null.
+ * @param list
+ * @return
+ */
+ private boolean hasNonNullElements(List list) {
+ Iterator iter = list.iterator();
+ while (iter.hasNext()) {
+ if (iter.next() != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the identity of the given row context. That's infact a list of all
+ * the values of the fields in the bean or XML that constitute the identity.
+ * @param rowContext
+ * @return List the identity of the row context
+ */
+ private List getIdentity(JXPathContext rowContext) {
+ if (this.identityBinding == null) {
+ return Collections.EMPTY_LIST;
+ }
+
+ List identity = new ArrayList();
+
+ JXPathBindingBase[] childBindings = this.identityBinding.getChildBindings();
+ if (childBindings != null) {
+ int size = childBindings.length;
+ for (int i = 0; i < size; i++) {
+ ValueJXPathBinding vBinding = (ValueJXPathBinding)childBindings[i];
+ Object value = rowContext.getValue(vBinding.getXPath());
+ if (value != null && vBinding.getConvertor() != null) {
+ if (value instanceof String) {
+ ConversionResult conversionResult = vBinding.getConvertor().convertFromString(
+ (String)value, vBinding.getConvertorLocale(), null);
+ if (conversionResult.isSuccessful())
+ value = conversionResult.getResult();
+ else
+ value = null;
+ } else {
+ if (getLogger().isWarnEnabled()) {
+ getLogger().warn("Convertor ignored on backend-value " +
+ "which isn't of type String.");
+ }
+ }
+ }
+ identity.add(value);
+ }
+ }
+ return identity;
+ }
+
+ /**
+ * Get the identity of the given row. That's infact a list of all the values
+ * of the fields in the form model that constitute the identity.
+ * @param row
+ * @return List the identity of the row
+ */
+ private List getIdentity(Repeater.RepeaterRow row) {
+ // quit if we don't have an identity binding
+ if (this.identityBinding == null) {
+ return Collections.EMPTY_LIST;
+ }
+
+ List identity = new ArrayList();
+
+ JXPathBindingBase[] childBindings = this.identityBinding.getChildBindings();
+ if (childBindings != null) {
+ int size = childBindings.length;
+ for (int i = 0; i < size; i++) {
+ String fieldId = ((ValueJXPathBinding)childBindings[i]).getFieldId();
+ Widget widget = row.getChild(fieldId);
+ Object value = widget.getValue();
+ identity.add(value);
+ }
+ }
+ return identity;
+ }
+
+ public String toString() {
+ return "RepeaterJXPathBinding [widget=" + this.repeaterId +
+ ", xpath=" + this.repeaterPath + "]";
+ }
+
+ public void enableLogging(Logger logger) {
+ super.enableLogging(logger);
+ if (this.deleteRowBinding != null) {
+ this.deleteRowBinding.enableLogging(logger);
+ }
+ if (this.insertRowBinding != null) {
+ this.insertRowBinding.enableLogging(logger);
+ }
+ this.rowBinding.enableLogging(logger);
+ if (this.identityBinding != null) {
+ this.identityBinding.enableLogging(logger);
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/binding/RepeaterJXPathBinding.java
------------------------------------------------------------------------------
svn:eol-style = native