001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.woody.binding;
018:
019: import java.util.Iterator;
020: import java.util.LinkedList;
021: import java.util.Locale;
022:
023: import org.apache.avalon.framework.logger.Logger;
024: import org.apache.cocoon.woody.datatype.convertor.Convertor;
025: import org.apache.cocoon.woody.formmodel.Widget;
026: import org.apache.commons.jxpath.JXPathContext;
027: import org.apache.commons.jxpath.Pointer;
028:
029: /**
030: * Simple binding for multi fields: on save, first deletes the target data
031: * before recreating it from scratch.
032: *
033: * @version CVS $Id: MultiValueJXPathBinding.java 433543 2006-08-22 06:22:54Z crossley $
034: */
035: public class MultiValueJXPathBinding extends JXPathBindingBase {
036:
037: private final String multiValueId;
038: private final String multiValuePath;
039: private final String rowPath;
040: private final JXPathBindingBase updateBinding;
041: private final Convertor convertor;
042: private final Locale convertorLocale;
043:
044: public MultiValueJXPathBinding(
045: JXPathBindingBuilderBase.CommonAttributes commonAtts,
046: String multiValueId, String multiValuePath, String rowPath,
047: JXPathBindingBase[] updateBindings, Convertor convertor,
048: Locale convertorLocale) {
049: super (commonAtts);
050: this .multiValueId = multiValueId;
051: this .multiValuePath = multiValuePath;
052: this .rowPath = rowPath;
053: this .updateBinding = new ComposedJXPathBindingBase(
054: JXPathBindingBuilderBase.CommonAttributes.DEFAULT,
055: updateBindings);
056: this .convertor = convertor;
057: this .convertorLocale = convertorLocale;
058: }
059:
060: public void doLoad(Widget frmModel, JXPathContext jctx)
061: throws BindingException {
062: Widget widget = frmModel.getWidget(this .multiValueId);
063: if (widget == null) {
064: throw new BindingException(
065: "The widget with the ID ["
066: + this .multiValueId
067: + "] referenced in the binding does not exist in the form definition.");
068: }
069:
070: // Move to multi value context
071: Pointer ptr = jctx.getPointer(this .multiValuePath);
072: if (ptr.getNode() != null) {
073: // There are some nodes to load from
074:
075: JXPathContext multiValueContext = jctx
076: .getRelativeContext(ptr);
077: // build a jxpath iterator for pointers
078: Iterator rowPointers = multiValueContext
079: .iterate(this .rowPath);
080:
081: LinkedList list = new LinkedList();
082:
083: while (rowPointers.hasNext()) {
084: Object value = rowPointers.next();
085:
086: if (value != null && convertor != null) {
087: if (value instanceof String) {
088: value = convertor.convertFromString(
089: (String) value, convertorLocale, null);
090: } else {
091: getLogger()
092: .warn(
093: "Convertor ignored on backend-value which isn't of type String.");
094: }
095: }
096:
097: list.add(value);
098: }
099:
100: widget.setValue(list.toArray());
101: }
102:
103: if (getLogger().isDebugEnabled())
104: getLogger().debug("done loading values " + toString());
105: }
106:
107: public void doSave(Widget frmModel, JXPathContext jctx)
108: throws BindingException {
109: Widget widget = frmModel.getWidget(this .multiValueId);
110: Object[] values = (Object[]) widget.getValue();
111:
112: JXPathContext multiValueContext = jctx.getRelativeContext(jctx
113: .createPath(this .multiValuePath));
114: // Delete all that is already present
115: multiValueContext.removeAll(this .rowPath);
116:
117: boolean update = false;
118:
119: if (values != null) {
120: // first update the values
121: for (int i = 0; i < values.length; i++) {
122: String path = this .rowPath + '[' + (i + 1) + ']';
123: Pointer rowPtr = multiValueContext.createPath(path);
124:
125: Object value = values[i];
126: if (value != null && convertor != null) {
127: value = convertor.convertToString(value,
128: convertorLocale, null);
129: }
130:
131: rowPtr.setValue(value);
132: }
133:
134: // now perform any other bindings that need to be performed when the value is updated
135: this .updateBinding.saveFormToModel(frmModel,
136: multiValueContext);
137:
138: update = true;
139: }
140:
141: if (getLogger().isDebugEnabled()) {
142: getLogger().debug(
143: "done saving " + toString() + " -- on-update == "
144: + update);
145: }
146:
147: }
148:
149: public String toString() {
150: return "MultiValueJXPathBinding [widget=" + this .multiValueId
151: + ", xpath=" + this .multiValuePath + "]";
152: }
153:
154: public void enableLogging(Logger logger) {
155: super.enableLogging(logger);
156: this.updateBinding.enableLogging(logger);
157: }
158: }
|