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.formmodel;
018:
019: import java.util.ArrayList;
020: import java.util.Collections;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025:
026: import org.apache.avalon.framework.activity.Disposable;
027: import org.apache.avalon.framework.service.ServiceException;
028: import org.apache.avalon.framework.service.ServiceManager;
029: import org.apache.avalon.framework.service.ServiceSelector;
030: import org.apache.avalon.framework.service.Serviceable;
031: import org.apache.excalibur.xml.sax.XMLizable;
032:
033: import org.apache.cocoon.forms.FormsConstants;
034: import org.apache.cocoon.forms.FormsException;
035: import org.apache.cocoon.forms.datatype.DatatypeManager;
036: import org.apache.cocoon.forms.event.CreateListener;
037: import org.apache.cocoon.forms.event.WidgetListener;
038: import org.apache.cocoon.forms.event.WidgetListenerBuilder;
039: import org.apache.cocoon.forms.expression.ExpressionManager;
040: import org.apache.cocoon.forms.util.DomHelper;
041: import org.apache.cocoon.forms.validation.WidgetValidatorBuilder;
042:
043: import org.w3c.dom.Element;
044: import org.w3c.dom.Node;
045: import org.w3c.dom.NodeList;
046:
047: /**
048: * Abstract base class for WidgetDefinitionBuilders. Provides functionality
049: * common to many implementations.
050: *
051: * @version $Id: AbstractWidgetDefinitionBuilder.java 450088 2006-09-26 15:36:34Z jbq $
052: */
053: public abstract class AbstractWidgetDefinitionBuilder implements
054: WidgetDefinitionBuilder, Serviceable, Disposable {
055:
056: protected ServiceSelector widgetDefinitionBuilderSelector;
057: protected ServiceSelector widgetValidatorBuilderSelector;
058: protected ServiceSelector widgetListenerBuilderSelector;
059: protected DatatypeManager datatypeManager;
060: protected ExpressionManager expressionManager;
061: protected ServiceManager serviceManager;
062:
063: protected WidgetDefinitionBuilderContext context;
064:
065: public void service(ServiceManager serviceManager)
066: throws ServiceException {
067: this .serviceManager = serviceManager;
068: this .widgetDefinitionBuilderSelector = (ServiceSelector) serviceManager
069: .lookup(WidgetDefinitionBuilder.class.getName()
070: + "Selector");
071: this .datatypeManager = (DatatypeManager) serviceManager
072: .lookup(DatatypeManager.ROLE);
073: this .expressionManager = (ExpressionManager) serviceManager
074: .lookup(ExpressionManager.ROLE);
075: this .widgetValidatorBuilderSelector = (ServiceSelector) serviceManager
076: .lookup(WidgetValidatorBuilder.ROLE + "Selector");
077: this .widgetListenerBuilderSelector = (ServiceSelector) serviceManager
078: .lookup(WidgetListenerBuilder.ROLE + "Selector");
079: }
080:
081: public void dispose() {
082: this .serviceManager
083: .release(this .widgetDefinitionBuilderSelector);
084: this .widgetDefinitionBuilderSelector = null;
085: this .serviceManager.release(this .datatypeManager);
086: this .datatypeManager = null;
087: this .serviceManager.release(this .expressionManager);
088: this .expressionManager = null;
089: this .serviceManager
090: .release(this .widgetValidatorBuilderSelector);
091: this .widgetValidatorBuilderSelector = null;
092: this .serviceManager = null;
093: }
094:
095: public WidgetDefinition buildWidgetDefinition(
096: Element widgetElement,
097: WidgetDefinitionBuilderContext context) throws Exception {
098: // so changes don't pollute upper levels
099: this .context = new WidgetDefinitionBuilderContext(context);
100:
101: WidgetDefinition def = buildWidgetDefinition(widgetElement);
102:
103: // register this class with the local library, if any.
104: if (DomHelper.getAttributeAsBoolean(widgetElement, "register",
105: false)
106: && this .context != null
107: && this .context.getLocalLibrary() != null) {
108: this .context.getLocalLibrary().addDefinition(def);
109: }
110:
111: this .context = null;
112: return def;
113: }
114:
115: protected void setupDefinition(Element widgetElement,
116: AbstractWidgetDefinition definition) throws Exception {
117: // location
118: definition.setLocation(DomHelper
119: .getLocationObject(widgetElement));
120:
121: if (this .context.getSuperDefinition() != null) {
122: definition
123: .initializeFrom(this .context.getSuperDefinition());
124: }
125:
126: setCommonProperties(widgetElement, definition);
127: setValidators(widgetElement, definition);
128: setCreateListeners(widgetElement, definition);
129: }
130:
131: protected void setCommonProperties(Element widgetElement,
132: AbstractWidgetDefinition widgetDefinition) throws Exception {
133:
134: // id
135: if (widgetDefinition instanceof FormDefinition) {
136: // FormDefinition is the *only* kind of widget that has an optional id
137: widgetDefinition.setId(DomHelper.getAttribute(
138: widgetElement, "id", ""));
139: } else {
140: String id = DomHelper.getAttribute(widgetElement, "id");
141: if (id.indexOf('/') != -1 || id.indexOf('.') != -1) {
142: throw new FormsException(
143: "A widget name cannot contain '.' or '/' as this conflicts with widget paths.",
144: DomHelper.getLocationObject(widgetElement));
145: }
146: // NewDefinitions are allowed to have a : in their id because they can look up
147: // class widgets from the library directly
148: if (id.indexOf(':') != -1
149: && !(widgetDefinition instanceof NewDefinition)) {
150: throw new FormsException(
151: "A widget name cannot contain ':' as this conflicts with library prefixes",
152: DomHelper.getLocationObject(widgetElement));
153: }
154: widgetDefinition.setId(id);
155: }
156:
157: // state
158: String stateValue = DomHelper.getAttribute(widgetElement,
159: "state", null);
160: if (stateValue != null) {
161: WidgetState state = WidgetState.stateForName(stateValue);
162: if (state == null) {
163: throw new FormsException("Unknown value '" + stateValue
164: + "' for state attribute.", DomHelper
165: .getLocationObject(widgetElement));
166: }
167: widgetDefinition.setState(state);
168: }
169:
170: // attributes
171: Element attrContainer = DomHelper.getChildElement(
172: widgetElement, FormsConstants.DEFINITION_NS,
173: "attributes", false);
174: if (attrContainer != null) {
175: // There's a <fd:attributes> element. Get its <fd:attribute> children
176: Element[] attrs = DomHelper.getChildElements(attrContainer,
177: FormsConstants.DEFINITION_NS, "attribute");
178: if (attrs != null && attrs.length > 0) {
179: // We actually do have some
180: Map attrMap = new HashMap();
181: for (int i = 0; i < attrs.length; i++) {
182: attrMap.put(DomHelper
183: .getAttribute(attrs[i], "name"), DomHelper
184: .getAttribute(attrs[i], "value"));
185: }
186: widgetDefinition.setAttributes(attrMap);
187: }
188: }
189: }
190:
191: protected WidgetDefinition buildAnotherWidgetDefinition(
192: Element widgetDefinition) throws Exception {
193: String widgetName = widgetDefinition.getLocalName();
194: WidgetDefinitionBuilder builder;
195: try {
196: builder = (WidgetDefinitionBuilder) widgetDefinitionBuilderSelector
197: .select(widgetName);
198: } catch (ServiceException e) {
199: throw new FormsException("Unknown kind of widget '"
200: + widgetName + "'.", e, DomHelper
201: .getLocationObject(widgetDefinition));
202: }
203:
204: return builder.buildWidgetDefinition(widgetDefinition,
205: this .context);
206: }
207:
208: protected List buildEventListeners(Element widgetElement,
209: String elementName, Class listenerClass) throws Exception {
210: List result = null;
211: Element listenersElement = DomHelper.getChildElement(
212: widgetElement, FormsConstants.DEFINITION_NS,
213: elementName);
214: if (listenersElement != null) {
215: NodeList list = listenersElement.getChildNodes();
216: for (int i = 0; i < list.getLength(); i++) {
217: if (list.item(i).getNodeType() == Node.ELEMENT_NODE) {
218: Element listenerElement = (Element) list.item(i);
219: WidgetListenerBuilder builder;
220: try {
221: builder = (WidgetListenerBuilder) widgetListenerBuilderSelector
222: .select(listenerElement.getLocalName());
223: } catch (ServiceException e) {
224: throw new FormsException(
225: "Unknown kind of eventlistener '"
226: + listenerElement
227: .getLocalName() + "'.",
228: e,
229: DomHelper
230: .getLocationObject(listenerElement));
231: }
232: WidgetListener listener = builder.buildListener(
233: listenerElement, listenerClass);
234: widgetListenerBuilderSelector.release(builder);
235: if (result == null) {
236: result = new ArrayList();
237: }
238: result.add(listener);
239: }
240: }
241: }
242:
243: return result == null ? Collections.EMPTY_LIST : result;
244: }
245:
246: protected void setDisplayData(Element widgetElement,
247: AbstractWidgetDefinition widgetDefinition) throws Exception {
248: final String[] names = { "label", "help", "hint" };
249: Map displayData = new HashMap(names.length);
250: for (int i = 0; i < names.length; i++) {
251: XMLizable data = null;
252: Element dataElement = DomHelper.getChildElement(
253: widgetElement, FormsConstants.DEFINITION_NS,
254: names[i]);
255: if (dataElement != null) {
256: data = DomHelper.compileElementContent(dataElement);
257: }
258:
259: // NOTE: We put also null values in the may in order to test their existence
260: // (see AbstractWidgetDefinition.generateDisplayData)
261: displayData.put(names[i], data);
262: }
263:
264: widgetDefinition.setDisplayData(displayData);
265: }
266:
267: protected void setValidators(Element widgetElement,
268: AbstractWidgetDefinition widgetDefinition) throws Exception {
269: Element validatorElement = DomHelper.getChildElement(
270: widgetElement, FormsConstants.DEFINITION_NS,
271: "validation");
272: if (validatorElement != null) {
273: NodeList list = validatorElement.getChildNodes();
274: for (int i = 0; i < list.getLength(); i++) {
275: if (list.item(i).getNodeType() == Node.ELEMENT_NODE) {
276: Element element = (Element) list.item(i);
277: String name = element.getLocalName();
278: WidgetValidatorBuilder builder;
279: try {
280: builder = (WidgetValidatorBuilder) this .widgetValidatorBuilderSelector
281: .select(name);
282: } catch (ServiceException e) {
283: throw new FormsException(
284: "Unknown kind of validator '" + name
285: + "'.", e, DomHelper
286: .getLocationObject(element));
287: }
288:
289: widgetDefinition.addValidator(builder.build(
290: element, widgetDefinition));
291: widgetValidatorBuilderSelector.release(builder);
292: }
293: }
294: }
295: }
296:
297: protected void setCreateListeners(Element widgetElement,
298: AbstractWidgetDefinition widgetDefinition) throws Exception {
299: Iterator i = buildEventListeners(widgetElement, "on-create",
300: CreateListener.class).iterator();
301: while (i.hasNext()) {
302: widgetDefinition.addCreateListener((CreateListener) i
303: .next());
304: }
305: }
306: }
|