/* * 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()); } } }