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.woody.datatype;
018:
019: import org.xml.sax.ContentHandler;
020: import org.xml.sax.SAXException;
021: import org.xml.sax.Attributes;
022: import org.apache.avalon.framework.service.ServiceManager;
023: import org.apache.excalibur.source.SourceResolver;
024: import org.apache.excalibur.source.Source;
025: import org.apache.cocoon.ProcessingException;
026: import org.apache.cocoon.components.source.SourceUtil;
027: import org.apache.cocoon.xml.AttributesImpl;
028: import org.apache.cocoon.xml.AbstractXMLPipe;
029: import org.apache.cocoon.xml.dom.DOMBuilder;
030: import org.apache.cocoon.woody.Constants;
031: import org.apache.cocoon.woody.datatype.convertor.Convertor;
032: import org.apache.cocoon.woody.datatype.convertor.DefaultFormatCache;
033: import org.w3c.dom.Element;
034:
035: import java.io.IOException;
036: import java.util.Locale;
037:
038: /**
039: * SelectionList implementation that always reads its content from the source
040: * each time it is requested.
041: *
042: * <p>Note: the class {@link SelectionListBuilder} also interprets the same wd:selection-list XML, so if
043: * anything changes here to how that XML is interpreted, it also needs to change over there and vice versa.
044: *
045: * @version $Id: DynamicSelectionList.java 433543 2006-08-22 06:22:54Z crossley $
046: */
047: public class DynamicSelectionList implements SelectionList {
048: private String src;
049: private Datatype datatype;
050: private ServiceManager serviceManager;
051:
052: public DynamicSelectionList(Datatype datatype, String src,
053: ServiceManager serviceManager) {
054: this .datatype = datatype;
055: this .src = src;
056: this .serviceManager = serviceManager;
057: }
058:
059: public Datatype getDatatype() {
060: return datatype;
061: }
062:
063: /*
064: * This method is only used by a test case and by the public version
065: * of generateSaxFragment.
066: */
067: void generateSaxFragment(ContentHandler contentHandler,
068: Locale locale, Source source) throws ProcessingException,
069: SAXException, IOException {
070: SelectionListHandler handler = new SelectionListHandler(locale);
071: handler.setContentHandler(contentHandler);
072: SourceUtil.toSAX(serviceManager, source, null, handler);
073: }
074:
075: public void generateSaxFragment(ContentHandler contentHandler,
076: Locale locale) throws SAXException {
077: SourceResolver sourceResolver = null;
078: Source source = null;
079: try {
080: sourceResolver = (SourceResolver) serviceManager
081: .lookup(SourceResolver.ROLE);
082: source = sourceResolver.resolveURI(src);
083: generateSaxFragment(contentHandler, locale, source);
084: } catch (Exception e) {
085: throw new SAXException(
086: "Error while generating selection list: "
087: + e.getMessage(), e);
088: } finally {
089: if (sourceResolver != null) {
090: if (source != null)
091: try {
092: sourceResolver.release(source);
093: } catch (Exception e) {
094: }
095: serviceManager.release(sourceResolver);
096: }
097: }
098: }
099:
100: /**
101: * XMLConsumer used to handle selection lists generated on the fly.
102: */
103: public class SelectionListHandler extends AbstractXMLPipe {
104: private Object currentValue;
105: private String currentValueAsString;
106: private boolean hasLabel;
107: private Locale locale;
108: /** The convertor used to parse the values in the selection list. */
109: private Convertor convertor;
110: private DOMBuilder convertorConfigDOMBuilder;
111: private int convertorConfigNestingLevel = 0;
112: private Convertor.FormatCache fromFormatCache = new DefaultFormatCache();
113: private Convertor.FormatCache toFormatCache = new DefaultFormatCache();
114:
115: public SelectionListHandler(Locale locale) {
116: this .locale = locale;
117: }
118:
119: public void startDocument() throws SAXException {
120: }
121:
122: public void endDocument() throws SAXException {
123: }
124:
125: public void endDTD() throws SAXException {
126: }
127:
128: public void startDTD(String name, String publicId,
129: String systemId) throws SAXException {
130: }
131:
132: public void startElement(String namespaceURI, String localName,
133: String qName, Attributes attributes)
134: throws SAXException {
135: if (convertorConfigNestingLevel > 0) {
136: convertorConfigNestingLevel++;
137: convertorConfigDOMBuilder.startElement(namespaceURI,
138: localName, qName, attributes);
139: } else if (namespaceURI.equals(Constants.WD_NS)) {
140: if (localName.equals("item")) {
141: if (convertor == null) {
142: // if no convertor was explicitely configured, use the default one of the datatype
143: convertor = datatype.getConvertor();
144: }
145: hasLabel = false;
146:
147: String unparsedValue = attributes.getValue("value");
148: if (unparsedValue == null
149: || "".equals(unparsedValue)) {
150: // Empty (or null) value translates into the empty string
151: currentValueAsString = "";
152: } else {
153: currentValue = convertor.convertFromString(
154: unparsedValue, locale, fromFormatCache);
155: if (currentValue == null) {
156: throw new SAXException(
157: "Could not interpret the following value: \""
158: + unparsedValue + "\".");
159: }
160: currentValueAsString = datatype.getConvertor()
161: .convertToString(currentValue, locale,
162: toFormatCache);
163: }
164: AttributesImpl attrs = new AttributesImpl();
165: attrs.addCDATAAttribute("value",
166: currentValueAsString);
167: super .startElement(Constants.WI_NS, localName,
168: Constants.WI_PREFIX_COLON + localName,
169: attrs);
170: } else if (localName.equals("label")) {
171: hasLabel = true;
172: super .startElement(Constants.WI_NS, localName,
173: Constants.WI_PREFIX_COLON + localName,
174: attributes);
175: } else if (localName.equals("selection-list")) {
176: super .startElement(Constants.WI_NS, localName,
177: Constants.WI_PREFIX_COLON + localName,
178: attributes);
179: } else if (convertor == null
180: && localName.equals("convertor")) {
181: // record the content of this element in a dom-tree
182: convertorConfigDOMBuilder = new DOMBuilder();
183: convertorConfigDOMBuilder.startElement(
184: namespaceURI, localName, qName, attributes);
185: convertorConfigNestingLevel++;
186: } else {
187: super .startElement(namespaceURI, localName, qName,
188: attributes);
189: }
190: } else {
191: super .startElement(namespaceURI, localName, qName,
192: attributes);
193: }
194: }
195:
196: private static final String LABEL_EL = "label";
197:
198: public void endElement(String namespaceURI, String localName,
199: String qName) throws SAXException {
200: if (convertorConfigNestingLevel > 0) {
201: convertorConfigNestingLevel--;
202: convertorConfigDOMBuilder.endElement(namespaceURI,
203: localName, qName);
204: if (convertorConfigNestingLevel == 0) {
205: Element convertorElement = convertorConfigDOMBuilder
206: .getDocument().getDocumentElement();
207: try {
208: convertor = datatype.getBuilder()
209: .buildConvertor(convertorElement);
210: } catch (Exception e) {
211: throw new SAXException(
212: "Error building convertor from convertor configuration embedded in selection list XML.",
213: e);
214: }
215: }
216: } else if (namespaceURI.equals(Constants.WD_NS)) {
217: if (localName.equals("item")) {
218: if (!hasLabel) {
219: // make the label now
220: super .startElement(Constants.WI_NS, LABEL_EL,
221: Constants.WI_PREFIX_COLON + LABEL_EL,
222: new AttributesImpl());
223: super .characters(currentValueAsString
224: .toCharArray(), 0, currentValueAsString
225: .length());
226: super .endElement(Constants.WI_NS, LABEL_EL,
227: Constants.WI_PREFIX_COLON + LABEL_EL);
228: }
229: super .endElement(Constants.WI_NS, localName,
230: Constants.WI_PREFIX_COLON + localName);
231: } else if (localName.equals("label")) {
232: super .endElement(Constants.WI_NS, localName,
233: Constants.WI_PREFIX_COLON + localName);
234: } else if (localName.equals("selection-list")) {
235: super .endElement(Constants.WI_NS, localName,
236: Constants.WI_PREFIX_COLON + localName);
237: } else {
238: super .endElement(namespaceURI, localName, qName);
239: }
240: } else {
241: super .endElement(namespaceURI, localName, qName);
242: }
243: }
244:
245: public void comment(char ch[], int start, int len)
246: throws SAXException {
247: if (convertorConfigNestingLevel > 0) {
248: convertorConfigDOMBuilder.comment(ch, start, len);
249: } else
250: super .comment(ch, start, len);
251: }
252:
253: public void startPrefixMapping(String prefix, String uri)
254: throws SAXException {
255: if (convertorConfigNestingLevel > 0) {
256: convertorConfigDOMBuilder.startPrefixMapping(prefix,
257: uri);
258: } else
259: super .startPrefixMapping(prefix, uri);
260: }
261:
262: public void endPrefixMapping(String prefix) throws SAXException {
263: if (convertorConfigNestingLevel > 0) {
264: convertorConfigDOMBuilder.endPrefixMapping(prefix);
265: } else
266: super .endPrefixMapping(prefix);
267: }
268:
269: public void characters(char c[], int start, int len)
270: throws SAXException {
271: if (convertorConfigNestingLevel > 0) {
272: convertorConfigDOMBuilder.characters(c, start, len);
273: } else
274: super .characters(c, start, len);
275: }
276:
277: public void ignorableWhitespace(char c[], int start, int len)
278: throws SAXException {
279: if (convertorConfigNestingLevel > 0) {
280: convertorConfigDOMBuilder.ignorableWhitespace(c, start,
281: len);
282: } else
283: super .ignorableWhitespace(c, start, len);
284: }
285:
286: public void processingInstruction(String target, String data)
287: throws SAXException {
288: if (convertorConfigNestingLevel > 0) {
289: convertorConfigDOMBuilder.processingInstruction(target,
290: data);
291: } else
292: super .processingInstruction(target, data);
293: }
294:
295: public void skippedEntity(String name) throws SAXException {
296: if (convertorConfigNestingLevel > 0) {
297: convertorConfigDOMBuilder.skippedEntity(name);
298: } else
299: super .skippedEntity(name);
300: }
301:
302: public void startEntity(String name) throws SAXException {
303: if (convertorConfigNestingLevel > 0) {
304: convertorConfigDOMBuilder.startEntity(name);
305: } else
306: super .startEntity(name);
307: }
308:
309: public void endEntity(String name) throws SAXException {
310: if (convertorConfigNestingLevel > 0) {
311: convertorConfigDOMBuilder.endEntity(name);
312: } else
313: super .endEntity(name);
314: }
315:
316: public void startCDATA() throws SAXException {
317: if (convertorConfigNestingLevel > 0) {
318: convertorConfigDOMBuilder.startCDATA();
319: } else
320: super .startCDATA();
321: }
322:
323: public void endCDATA() throws SAXException {
324: if (convertorConfigNestingLevel > 0) {
325: convertorConfigDOMBuilder.endCDATA();
326: } else
327: super.endCDATA();
328: }
329: }
330: }
|