blob: 34d08239b5cb7458515c7ccdc0d68d0bf39279fe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.woody.binding;
import java.util.HashMap;
import java.util.Map;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.cocoon.util.jxpath.DOMFactory;
import org.apache.cocoon.woody.formmodel.Widget;
import org.apache.commons.jxpath.JXPathContext;
import org.w3c.dom.Node;
/**
* Provides a base class for hooking up Binding implementations that use the
* Jakarta Commons <a href="http://jakarta.apache.org/commons/jxpath/index.html">
* JXPath package</a>.
*
* @version CVS $Id$
*/
public abstract class JXPathBindingBase implements Binding, LogEnabled {
/**
* Avalon Logger to use in all subclasses.
*/
private Logger logger;
/**
* Object holding the values of the common objects on all Bindings.
*/
private final JXPathBindingBuilderBase.CommonAttributes commonAtts;
/**
* Parent binding of this binding.
*/
protected Binding parent;
/**
* Cache of class definitions
*/
protected Map classes;
private JXPathBindingBase() {
this(JXPathBindingBuilderBase.CommonAttributes.DEFAULT);
}
protected JXPathBindingBase(
JXPathBindingBuilderBase.CommonAttributes commonAtts) {
this.commonAtts = commonAtts;
}
/**
* Sets parent binding.
*/
public void setParent(Binding binding) {
this.parent = binding;
}
/**
* Returns binding definition id.
*/
public String getId() {
return null;
}
public Binding getClass(String id) {
Binding classBinding = null;
if (classes != null) {
// Query cache for class
classBinding = (Binding)classes.get(id);
}
if (classBinding == null) {
// Query parent for class
if (parent != null) {
classBinding = parent.getClass(id);
// Cache result
if (classes == null) {
classes = new HashMap();
}
classes.put(id, classBinding);
} else {
// TODO: Improve message to include source location.
throw new RuntimeException("Class \"" + id + "\" not found.");
}
}
return classBinding;
}
protected Widget getWidget(Widget widget, String id) {
Widget childWidget = widget.getWidget(id);
if (childWidget != null) {
return childWidget;
} else {
throw new RuntimeException(getClass().getName() + ": Widget \"" +
id + "\" does not exist in container \"" +
widget.getFullyQualifiedId() + "\" (" +
widget.getLocation() + ").");
}
}
/**
* Performs the actual load binding regardless of the configured value of the "direction" attribute.
* Abstract method that subclasses need to implement for specific activity.
*/
public abstract void doLoad(Widget frmModel, JXPathContext jxpc)
throws BindingException;
/**
* Redefines the Binding action as working on a JXPathContext Type rather
* then on generic objects.
* Executes the actual loading via {@link #doLoad(Widget, JXPathContext)}
* depending on the configured value of the "direction" attribute.
*/
public final void loadFormFromModel(Widget frmModel, JXPathContext jxpc)
throws BindingException {
boolean inheritedLeniency = jxpc.isLenient();
applyLeniency(jxpc);
if (this.commonAtts.loadEnabled) {
doLoad(frmModel, jxpc);
}
jxpc.setLenient(inheritedLeniency);
}
/**
* Hooks up with the more generic Binding of any objectModel by wrapping
* it up in a JXPathContext object and then transfering control over to
* the new overloaded version of this method.
*/
public final void loadFormFromModel(Widget frmModel, Object objModel)
throws BindingException {
if (objModel != null) {
JXPathContext jxpc = makeJXPathContext(objModel);
loadFormFromModel(frmModel, jxpc);
} else {
throw new NullPointerException(
"null object passed to loadFormFromModel() method");
}
}
/**
* Performs the actual save binding regardless of the configured value of the "direction" attribute.
* Abstract method that subclasses need to implement for specific activity.
*/
public abstract void doSave(Widget frmModel, JXPathContext jxpc)
throws BindingException;
/**
* Redefines the Binding action as working on a JXPathContext Type rather
* then on generic objects.
* Executes the actual saving via {@link #doSave(Widget, JXPathContext)}
* depending on the configured value of the "direction" attribute.
*/
public final void saveFormToModel(Widget frmModel, JXPathContext jxpc)
throws BindingException{
boolean inheritedLeniency = jxpc.isLenient();
applyLeniency(jxpc);
if (this.commonAtts.saveEnabled) {
doSave(frmModel, jxpc);
}
jxpc.setLenient(inheritedLeniency);
}
/**
* Hooks up with the more generic Binding of any objectModel by wrapping
* it up in a JXPathContext object and then transfering control over to
* the new overloaded version of this method.
*/
public void saveFormToModel(Widget frmModel, Object objModel)
throws BindingException {
if (objModel != null) {
JXPathContext jxpc = makeJXPathContext(objModel);
saveFormToModel(frmModel, jxpc);
} else {
throw new NullPointerException(
"null object passed to saveFormToModel() method");
}
}
private void applyLeniency(JXPathContext jxpc) {
if (this.commonAtts.leniency != null) {
jxpc.setLenient(this.commonAtts.leniency.booleanValue());
}
}
private JXPathContext makeJXPathContext(Object objModel) {
JXPathContext jxpc;
if (!(objModel instanceof JXPathContext)) {
jxpc = JXPathContext.newContext(objModel);
jxpc.setLenient(true);
if (objModel instanceof Node) {
jxpc.setFactory(new DOMFactory());
}
} else {
jxpc = (JXPathContext) objModel;
}
return jxpc;
}
/**
* Receives the Avalon logger to use.
* Subclasses should always start with <code>super.enableLogging(logger)
* </code> in possible overriding versions.
*/
public void enableLogging(Logger logger) {
this.logger = logger;
}
protected Logger getLogger() {
return logger;
}
}