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.forms.binding;
018:
019: import java.util.Locale;
020:
021: import org.apache.avalon.framework.logger.Logger;
022:
023: import org.apache.cocoon.forms.datatype.convertor.ConversionResult;
024: import org.apache.cocoon.forms.datatype.convertor.Convertor;
025: import org.apache.cocoon.forms.formmodel.Widget;
026:
027: import org.apache.commons.jxpath.JXPathContext;
028: import org.apache.commons.jxpath.JXPathException;
029:
030: /**
031: * ValueJXPathBinding provides an implementation of a {@link Binding}
032: * that loads and saves the information behind a specific xpath expresion
033: * (pointing to an attribute or text-node) to and from a specific CForms
034: * widget as identified by its id.
035: *
036: * @version $Id: ValueJXPathBinding.java 450255 2006-09-26 23:48:43Z vgritsenko $
037: */
038: public class ValueJXPathBinding extends JXPathBindingBase {
039:
040: /**
041: * The xpath expression to the objectModel property
042: */
043: private final String xpath;
044:
045: /**
046: * The id of the CForms form-widget
047: */
048: private final String fieldId;
049:
050: /**
051: * Flag indicating if the objectModel-property can be altered or not
052: */
053: private final JXPathBindingBase updateBinding;
054:
055: /**
056: * Optional convertor to convert values to and from strings when setting or reading
057: * the from the model. Especially used in combination with XML models where everything
058: * are strings.
059: */
060: private final Convertor convertor;
061:
062: /**
063: * The locale to pass to the {@link #convertor}.
064: */
065: private final Locale convertorLocale;
066:
067: /**
068: * Constructs FieldJXPathBinding.
069: *
070: * @param convertor may be null
071: */
072: public ValueJXPathBinding(
073: JXPathBindingBuilderBase.CommonAttributes commonAtts,
074: String widgetId, String xpath,
075: JXPathBindingBase[] updateBindings, Convertor convertor,
076: Locale convertorLocale) {
077: super (commonAtts);
078: this .fieldId = widgetId;
079: this .xpath = xpath;
080: this .updateBinding = new ComposedJXPathBindingBase(
081: JXPathBindingBuilderBase.CommonAttributes.DEFAULT,
082: updateBindings);
083: this .convertor = convertor;
084: this .convertorLocale = convertorLocale;
085: }
086:
087: public void enableLogging(Logger logger) {
088: super .enableLogging(logger);
089: this .updateBinding.enableLogging(logger);
090: }
091:
092: public String getId() {
093: return fieldId;
094: }
095:
096: public ComposedJXPathBindingBase getUpdateBinding() {
097: return (ComposedJXPathBindingBase) updateBinding;
098: }
099:
100: /**
101: * Actively performs the binding from the ObjectModel wrapped in a jxpath
102: * context to the CForms-form-widget specified in this object.
103: */
104: public void doLoad(Widget frmModel, JXPathContext jxpc)
105: throws BindingException {
106: Widget widget = selectWidget(frmModel, this .fieldId);
107: if (widget == null) {
108: throw new BindingException(
109: "The widget with the ID ["
110: + this .fieldId
111: + "] referenced in the binding does not exist in the form definition.");
112: }
113:
114: Object value = jxpc.getValue(this .xpath);
115: if (value != null && convertor != null) {
116: if (value instanceof String) {
117: ConversionResult conversionResult = convertor
118: .convertFromString((String) value,
119: convertorLocale, null);
120: if (conversionResult.isSuccessful())
121: value = conversionResult.getResult();
122: else
123: value = null;
124: } else {
125: getLogger()
126: .warn(
127: "Convertor ignored on backend-value which isn't of type String.");
128: }
129: }
130:
131: widget.setValue(value);
132: if (getLogger().isDebugEnabled()) {
133: getLogger().debug(
134: "Done loading " + toString() + " -- value= "
135: + value);
136: }
137: }
138:
139: /**
140: * Actively performs the binding from the CForms-form to the ObjectModel
141: * wrapped in a jxpath context
142: */
143: public void doSave(Widget frmModel, JXPathContext jxpc)
144: throws BindingException {
145: Widget widget = selectWidget(frmModel, this .fieldId);
146: Object value = widget.getValue();
147: if (value != null && convertor != null) {
148: value = convertor.convertToString(value, convertorLocale,
149: null);
150: }
151:
152: Object oldValue = jxpc.getValue(this .xpath);
153: if (getLogger().isDebugEnabled()) {
154: getLogger().debug(
155: "value= " + value + " -- oldvalue=" + oldValue);
156: }
157:
158: boolean update = false;
159:
160: if ((value == null && oldValue != null) || value != null
161: && !value.equals(oldValue)) {
162: // first update the value itself
163: jxpc.createPathAndSetValue(this .xpath, value);
164:
165: // now perform any other bindings that need to be performed when the value is updated
166: JXPathContext subContext = null;
167: try {
168: subContext = jxpc.getRelativeContext(jxpc
169: .getPointer(this .xpath));
170: } catch (JXPathException e) {
171: // if the value has been set to null and the underlying model is a bean, then
172: // JXPath will not be able to create a relative context
173: if (getLogger().isDebugEnabled()) {
174: getLogger().debug(
175: "(Ignorable) problem binding field "
176: + widget.getRequestParameterName(),
177: e);
178: }
179: }
180: if (subContext != null) {
181: this .updateBinding
182: .saveFormToModel(frmModel, subContext);
183: }
184:
185: update = true;
186: }
187:
188: if (getLogger().isDebugEnabled()) {
189: getLogger().debug(
190: "done saving " + toString() + " -- value= " + value
191: + " -- on-update == " + update);
192: }
193: }
194:
195: public String toString() {
196: return "ValueJXPathBinding [widget=" + this .fieldId
197: + ", xpath=" + this .xpath + "]";
198: }
199:
200: public String getFieldId() {
201: return this .fieldId;
202: }
203:
204: public String getXPath() {
205: return this .xpath;
206: }
207:
208: public Convertor getConvertor() {
209: return this .convertor;
210: }
211:
212: public Locale getConvertorLocale() {
213: return this.convertorLocale;
214: }
215: }
|