| /* |
| * 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.datatype; |
| |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.Attributes; |
| import org.apache.avalon.framework.service.ServiceManager; |
| import org.apache.excalibur.source.SourceResolver; |
| import org.apache.excalibur.source.Source; |
| import org.apache.cocoon.ProcessingException; |
| import org.apache.cocoon.components.source.SourceUtil; |
| import org.apache.cocoon.xml.AttributesImpl; |
| import org.apache.cocoon.xml.AbstractXMLPipe; |
| import org.apache.cocoon.xml.dom.DOMBuilder; |
| import org.apache.cocoon.woody.Constants; |
| import org.apache.cocoon.woody.datatype.convertor.Convertor; |
| import org.apache.cocoon.woody.datatype.convertor.DefaultFormatCache; |
| import org.w3c.dom.Element; |
| |
| import java.io.IOException; |
| import java.util.Locale; |
| |
| /** |
| * SelectionList implementation that always reads its content from the source |
| * each time it is requested. |
| * |
| * <p>Note: the class {@link SelectionListBuilder} also interprets the same wd:selection-list XML, so if |
| * anything changes here to how that XML is interpreted, it also needs to change over there and vice versa. |
| * |
| * @version $Id$ |
| */ |
| public class DynamicSelectionList implements SelectionList { |
| private String src; |
| private Datatype datatype; |
| private ServiceManager serviceManager; |
| |
| public DynamicSelectionList(Datatype datatype, String src, ServiceManager serviceManager) { |
| this.datatype = datatype; |
| this.src = src; |
| this.serviceManager = serviceManager; |
| } |
| |
| public Datatype getDatatype() { |
| return datatype; |
| } |
| |
| /* |
| * This method is only used by a test case and by the public version |
| * of generateSaxFragment. |
| */ |
| void generateSaxFragment(ContentHandler contentHandler, Locale locale, Source source) throws ProcessingException, SAXException, IOException { |
| SelectionListHandler handler = new SelectionListHandler(locale); |
| handler.setContentHandler(contentHandler); |
| SourceUtil.toSAX(serviceManager, source, null, handler); |
| } |
| |
| public void generateSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException { |
| SourceResolver sourceResolver = null; |
| Source source = null; |
| try { |
| sourceResolver = (SourceResolver)serviceManager.lookup(SourceResolver.ROLE); |
| source = sourceResolver.resolveURI(src); |
| generateSaxFragment(contentHandler, locale, source); |
| } catch (Exception e) { |
| throw new SAXException("Error while generating selection list: " + e.getMessage(), e); |
| } finally { |
| if (sourceResolver != null) { |
| if (source != null) |
| try { sourceResolver.release(source); } catch (Exception e) {} |
| serviceManager.release(sourceResolver); |
| } |
| } |
| } |
| |
| /** |
| * XMLConsumer used to handle selection lists generated on the fly. |
| */ |
| public class SelectionListHandler extends AbstractXMLPipe { |
| private Object currentValue; |
| private String currentValueAsString; |
| private boolean hasLabel; |
| private Locale locale; |
| /** The convertor used to parse the values in the selection list. */ |
| private Convertor convertor; |
| private DOMBuilder convertorConfigDOMBuilder; |
| private int convertorConfigNestingLevel = 0; |
| private Convertor.FormatCache fromFormatCache = new DefaultFormatCache(); |
| private Convertor.FormatCache toFormatCache = new DefaultFormatCache(); |
| |
| public SelectionListHandler(Locale locale) { |
| this.locale = locale; |
| } |
| |
| public void startDocument() |
| throws SAXException { |
| } |
| |
| public void endDocument() |
| throws SAXException { |
| } |
| |
| public void endDTD() |
| throws SAXException { |
| } |
| |
| public void startDTD(String name, String publicId, String systemId) |
| throws SAXException { |
| } |
| |
| public void startElement(String namespaceURI, String localName, String qName, Attributes attributes) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigNestingLevel++; |
| convertorConfigDOMBuilder.startElement(namespaceURI, localName, qName, attributes); |
| } else if (namespaceURI.equals(Constants.WD_NS)) { |
| if (localName.equals("item")) { |
| if (convertor == null) { |
| // if no convertor was explicitely configured, use the default one of the datatype |
| convertor = datatype.getConvertor(); |
| } |
| hasLabel = false; |
| |
| String unparsedValue = attributes.getValue("value"); |
| if (unparsedValue == null || "".equals(unparsedValue)) { |
| // Empty (or null) value translates into the empty string |
| currentValueAsString = ""; |
| } else { |
| currentValue = convertor.convertFromString(unparsedValue, locale, fromFormatCache); |
| if (currentValue == null) { |
| throw new SAXException("Could not interpret the following value: \"" + unparsedValue + "\"."); |
| } |
| currentValueAsString = datatype.getConvertor().convertToString(currentValue, locale, toFormatCache); |
| } |
| AttributesImpl attrs = new AttributesImpl(); |
| attrs.addCDATAAttribute("value", currentValueAsString); |
| super.startElement(Constants.WI_NS, localName, Constants.WI_PREFIX_COLON + localName, attrs); |
| } else if (localName.equals("label")) { |
| hasLabel = true; |
| super.startElement(Constants.WI_NS, localName, Constants.WI_PREFIX_COLON + localName, attributes); |
| } else if (localName.equals("selection-list")) { |
| super.startElement(Constants.WI_NS, localName, Constants.WI_PREFIX_COLON + localName, attributes); |
| } else if (convertor == null && localName.equals("convertor")) { |
| // record the content of this element in a dom-tree |
| convertorConfigDOMBuilder = new DOMBuilder(); |
| convertorConfigDOMBuilder.startElement(namespaceURI, localName, qName, attributes); |
| convertorConfigNestingLevel++; |
| } else { |
| super.startElement(namespaceURI, localName, qName, attributes); |
| } |
| } else { |
| super.startElement(namespaceURI, localName, qName, attributes); |
| } |
| } |
| |
| private static final String LABEL_EL = "label"; |
| |
| public void endElement(String namespaceURI, String localName, String qName) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigNestingLevel--; |
| convertorConfigDOMBuilder.endElement(namespaceURI, localName, qName); |
| if (convertorConfigNestingLevel == 0) { |
| Element convertorElement = convertorConfigDOMBuilder.getDocument().getDocumentElement(); |
| try { |
| convertor = datatype.getBuilder().buildConvertor(convertorElement); |
| } catch (Exception e) { |
| throw new SAXException("Error building convertor from convertor configuration embedded in selection list XML.", e); |
| } |
| } |
| } else if (namespaceURI.equals(Constants.WD_NS)) { |
| if (localName.equals("item")) { |
| if (!hasLabel) { |
| // make the label now |
| super.startElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL, new AttributesImpl()); |
| super.characters(currentValueAsString.toCharArray(), 0, currentValueAsString.length()); |
| super.endElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL); |
| } |
| super.endElement(Constants.WI_NS, localName, Constants.WI_PREFIX_COLON + localName); |
| } else if (localName.equals("label")) { |
| super.endElement(Constants.WI_NS, localName, Constants.WI_PREFIX_COLON + localName); |
| } else if (localName.equals("selection-list")) { |
| super.endElement(Constants.WI_NS, localName, Constants.WI_PREFIX_COLON + localName); |
| } else { |
| super.endElement(namespaceURI, localName, qName); |
| } |
| } else { |
| super.endElement(namespaceURI, localName, qName); |
| } |
| } |
| |
| public void comment(char ch[], int start, int len) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.comment(ch, start, len); |
| } else |
| super.comment(ch, start, len); |
| } |
| |
| public void startPrefixMapping(String prefix, String uri) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.startPrefixMapping(prefix, uri); |
| } else |
| super.startPrefixMapping(prefix, uri); |
| } |
| |
| public void endPrefixMapping(String prefix) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.endPrefixMapping(prefix); |
| } else |
| super.endPrefixMapping(prefix); |
| } |
| |
| public void characters(char c[], int start, int len) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.characters(c, start, len); |
| } else |
| super.characters(c, start, len); |
| } |
| |
| public void ignorableWhitespace(char c[], int start, int len) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.ignorableWhitespace(c, start, len); |
| } else |
| super.ignorableWhitespace(c, start, len); |
| } |
| |
| public void processingInstruction(String target, String data) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.processingInstruction(target, data); |
| } else |
| super.processingInstruction(target, data); |
| } |
| |
| public void skippedEntity(String name) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.skippedEntity(name); |
| } else |
| super.skippedEntity(name); |
| } |
| |
| public void startEntity(String name) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.startEntity(name); |
| } else |
| super.startEntity(name); |
| } |
| |
| public void endEntity(String name) |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.endEntity(name); |
| } else |
| super.endEntity(name); |
| } |
| |
| public void startCDATA() |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.startCDATA(); |
| } else |
| super.startCDATA(); |
| } |
| |
| public void endCDATA() |
| throws SAXException { |
| if (convertorConfigNestingLevel > 0) { |
| convertorConfigDOMBuilder.endCDATA(); |
| } else |
| super.endCDATA(); |
| } |
| } |
| } |