blob: 57f98657928f4139413b58fa75bec7d444d067a9 [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.forms.formmodel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.ServiceSelector;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.excalibur.xml.sax.XMLizable;
import org.apache.cocoon.forms.FormsConstants;
import org.apache.cocoon.forms.FormsException;
import org.apache.cocoon.forms.datatype.DatatypeManager;
import org.apache.cocoon.forms.event.CreateListener;
import org.apache.cocoon.forms.event.WidgetListener;
import org.apache.cocoon.forms.event.WidgetListenerBuilder;
import org.apache.cocoon.forms.expression.ExpressionManager;
import org.apache.cocoon.forms.util.DomHelper;
import org.apache.cocoon.forms.validation.WidgetValidatorBuilder;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Abstract base class for WidgetDefinitionBuilders. Provides functionality
* common to many implementations.
*
* @version $Id$
*/
public abstract class AbstractWidgetDefinitionBuilder implements WidgetDefinitionBuilder, Serviceable, Disposable {
protected ServiceSelector widgetDefinitionBuilderSelector;
protected ServiceSelector widgetValidatorBuilderSelector;
protected ServiceSelector widgetListenerBuilderSelector;
protected DatatypeManager datatypeManager;
protected ExpressionManager expressionManager;
protected ServiceManager serviceManager;
public void service(ServiceManager serviceManager) throws ServiceException {
this.serviceManager = serviceManager;
this.widgetDefinitionBuilderSelector = (ServiceSelector) serviceManager.lookup(WidgetDefinitionBuilder.class.getName() + "Selector");
this.datatypeManager = (DatatypeManager) serviceManager.lookup(DatatypeManager.ROLE);
this.expressionManager = (ExpressionManager) serviceManager.lookup(ExpressionManager.ROLE);
this.widgetValidatorBuilderSelector = (ServiceSelector) serviceManager.lookup(WidgetValidatorBuilder.ROLE + "Selector");
this.widgetListenerBuilderSelector = (ServiceSelector) serviceManager.lookup(WidgetListenerBuilder.ROLE + "Selector");
}
public void dispose() {
this.serviceManager.release(this.widgetDefinitionBuilderSelector);
this.widgetDefinitionBuilderSelector = null;
this.serviceManager.release(this.datatypeManager);
this.datatypeManager = null;
this.serviceManager.release(this.expressionManager);
this.expressionManager = null;
this.serviceManager.release(this.widgetValidatorBuilderSelector);
this.widgetValidatorBuilderSelector = null;
this.serviceManager = null;
}
public WidgetDefinition buildWidgetDefinition(Element widgetElement) throws Exception {
throw new UnsupportedOperationException("Please use the other signature with WidgetDefinitionBuilderContext!");
}
protected void setupDefinition(Element widgetElement, AbstractWidgetDefinition definition, WidgetDefinitionBuilderContext context)
throws Exception {
// location
definition.setLocation(DomHelper.getLocationObject(widgetElement));
if (context.getSuperDefinition() != null) {
definition.initializeFrom(context.getSuperDefinition());
}
setCommonProperties(widgetElement, definition);
setValidators(widgetElement, definition);
setCreateListeners(widgetElement, definition);
}
protected void setCommonProperties(Element widgetElement, AbstractWidgetDefinition widgetDefinition)
throws Exception {
// id
if (widgetDefinition instanceof FormDefinition) {
// FormDefinition is the *only* kind of widget that has an optional id
widgetDefinition.setId(DomHelper.getAttribute(widgetElement, "id", ""));
} else {
String id = DomHelper.getAttribute(widgetElement, "id");
if (id.indexOf('/') != -1 || id.indexOf('.') != -1) {
throw new FormsException("A widget name cannot contain '.' or '/' as this conflicts with widget paths.",
DomHelper.getLocationObject(widgetElement));
}
// NewDefinitions are allowed to have a : in their id because they can look up
// class widgets from the library directly
if (id.indexOf(':') != -1 && !(widgetDefinition instanceof NewDefinition)) {
throw new FormsException("A widget name cannot contain ':' as this conflicts with library prefixes",
DomHelper.getLocationObject(widgetElement));
}
widgetDefinition.setId(id);
}
// state
String stateValue = DomHelper.getAttribute(widgetElement, "state", null);
if (stateValue != null) {
WidgetState state = WidgetState.stateForName(stateValue);
if (state == null) {
throw new FormsException("Unknown value '" + stateValue +"' for state attribute.",
DomHelper.getLocationObject(widgetElement));
}
widgetDefinition.setState(state);
}
// attributes
Element attrContainer = DomHelper.getChildElement(widgetElement, FormsConstants.DEFINITION_NS, "attributes", false);
if (attrContainer != null) {
// There's a <fd:attributes> element. Get its <fd:attribute> children
Element[] attrs = DomHelper.getChildElements(attrContainer, FormsConstants.DEFINITION_NS, "attribute");
if (attrs != null && attrs.length > 0) {
// We actually do have some
Map attrMap = new HashMap();
for (int i = 0; i < attrs.length; i++) {
attrMap.put(DomHelper.getAttribute(attrs[i], "name"), DomHelper.getAttribute(attrs[i], "value"));
}
widgetDefinition.setAttributes(attrMap);
}
}
}
protected WidgetDefinition buildAnotherWidgetDefinition(Element widgetElement, WidgetDefinitionBuilderContext context)
throws Exception {
String widgetName = widgetElement.getLocalName();
WidgetDefinitionBuilder builder;
try {
builder = (WidgetDefinitionBuilder) widgetDefinitionBuilderSelector.select(widgetName);
} catch (ServiceException e) {
throw new FormsException("Unknown kind of widget '" + widgetName + "'.",
e, DomHelper.getLocationObject(widgetElement));
}
WidgetDefinition def = builder.buildWidgetDefinition(widgetElement, context);
// register this class with the local library, if any.
if (DomHelper.getAttributeAsBoolean(widgetElement, "register", false)) {
context.getLocalLibrary().addDefinition(def);
}
return def;
}
protected List buildEventListeners(Element widgetElement, String elementName, Class listenerClass)
throws Exception {
List result = null;
Element listenersElement = DomHelper.getChildElement(widgetElement, FormsConstants.DEFINITION_NS, elementName);
if (listenersElement != null) {
NodeList list = listenersElement.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i).getNodeType() == Node.ELEMENT_NODE) {
Element listenerElement = (Element)list.item(i);
WidgetListenerBuilder builder;
try {
builder = (WidgetListenerBuilder) widgetListenerBuilderSelector.select(listenerElement.getLocalName());
} catch (ServiceException e) {
throw new FormsException("Unknown kind of eventlistener '" + listenerElement.getLocalName() + "'.", e,
DomHelper.getLocationObject(listenerElement));
}
WidgetListener listener = builder.buildListener(listenerElement, listenerClass);
widgetListenerBuilderSelector.release(builder);
if (result == null) {
result = new ArrayList();
}
result.add(listener);
}
}
}
return result == null ? Collections.EMPTY_LIST : result;
}
protected void setDisplayData(Element widgetElement, AbstractWidgetDefinition widgetDefinition)
throws Exception {
final String[] names = {"label", "help", "hint"};
Map displayData = new HashMap(names.length);
for (int i = 0; i < names.length; i++) {
XMLizable data = null;
Element dataElement = DomHelper.getChildElement(widgetElement, FormsConstants.DEFINITION_NS, names[i]);
if (dataElement != null) {
data = DomHelper.compileElementContent(dataElement);
}
// NOTE: We put also null values in the may in order to test their existence
// (see AbstractWidgetDefinition.generateDisplayData)
displayData.put(names[i], data);
}
widgetDefinition.setDisplayData(displayData);
}
protected void setValidators(Element widgetElement, AbstractWidgetDefinition widgetDefinition)
throws Exception {
Element validatorElement = DomHelper.getChildElement(widgetElement, FormsConstants.DEFINITION_NS, "validation");
if (validatorElement != null) {
NodeList list = validatorElement.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i).getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element)list.item(i);
String name = element.getLocalName();
WidgetValidatorBuilder builder;
try {
builder = (WidgetValidatorBuilder)this.widgetValidatorBuilderSelector.select(name);
} catch(ServiceException e) {
throw new FormsException("Unknown kind of validator '" + name + "'.",
e, DomHelper.getLocationObject(element));
}
widgetDefinition.addValidator(builder.build(element, widgetDefinition));
widgetValidatorBuilderSelector.release(builder);
}
}
}
}
protected void setCreateListeners(Element widgetElement, AbstractWidgetDefinition widgetDefinition)
throws Exception {
Iterator i = buildEventListeners(widgetElement, "on-create", CreateListener.class).iterator();
while (i.hasNext()) {
widgetDefinition.addCreateListener((CreateListener)i.next());
}
}
}