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.binding;
018:
019: import org.apache.avalon.framework.service.ServiceManager;
020: import org.apache.excalibur.source.Source;
021: import org.apache.excalibur.source.SourceResolver;
022: import org.apache.excalibur.xml.xpath.XPathProcessor;
023:
024: import org.apache.cocoon.components.source.SourceUtil;
025: import org.apache.cocoon.forms.util.DomHelper;
026: import org.apache.cocoon.util.location.LocationAttributes;
027:
028: import org.w3c.dom.Document;
029: import org.w3c.dom.DocumentFragment;
030: import org.w3c.dom.Element;
031: import org.w3c.dom.Node;
032: import org.w3c.dom.NodeList;
033:
034: /**
035: * InsertNodeJXPathBindingBuilder provides a helper class for the Factory
036: * implemented in {@link JXPathBindingManager} that helps construct the
037: * actual {@link InsertNodeJXPathBinding} out of the configuration in the
038: * provided configElement which looks like:
039: * <pre><code>
040: * <fb:insert-node>
041: * <!-- in here comes a template that will be inserted in the target
042: * document -->
043: * </fb:insert-node>
044: * </code></pre>
045: *
046: * @version $Id: InsertNodeJXPathBindingBuilder.java 517733 2007-03-13 15:37:22Z vgritsenko $
047: */
048: public class InsertNodeJXPathBindingBuilder extends
049: JXPathBindingBuilderBase {
050:
051: /**
052: * Creates an instance of {@link InsertNodeJXPathBinding} configured
053: * with the nested template of the bindingElm.
054: */
055: public JXPathBindingBase buildBinding(Element bindingElm,
056: JXPathBindingManager.Assistant assistant)
057: throws BindingException {
058:
059: try {
060: CommonAttributes commonAtts = JXPathBindingBuilderBase
061: .getCommonAttributes(bindingElm);
062:
063: DocumentFragment domTemplate = null;
064:
065: String src = DomHelper
066: .getAttribute(bindingElm, "src", null);
067: if (src != null) {
068: ServiceManager manager = assistant.getServiceManager();
069: SourceResolver sourceResolver = (SourceResolver) manager
070: .lookup(SourceResolver.ROLE);
071: Source source = null;
072: try {
073: source = sourceResolver.resolveURI(src);
074: Document document = SourceUtil.toDOM(source);
075: Element element = document.getDocumentElement();
076:
077: String xpath = DomHelper.getAttribute(bindingElm,
078: "xpath", null);
079: if (xpath != null) {
080: XPathProcessor xpathProcessor = (XPathProcessor) manager
081: .lookup(XPathProcessor.ROLE);
082: try {
083: Node node = xpathProcessor
084: .selectSingleNode(document, xpath);
085: if (node == null) {
086: throw new BindingException(
087: "XPath expression '"
088: + xpath
089: + "' didn't return a result.",
090: DomHelper
091: .getLocationObject(bindingElm));
092: }
093: if (!(node instanceof Element)) {
094: throw new BindingException(
095: "XPath expression '"
096: + xpath
097: + "' did not return an element node.",
098: DomHelper
099: .getLocationObject(bindingElm));
100: }
101: element = (Element) node;
102: } finally {
103: manager.release(xpathProcessor);
104: }
105: }
106: domTemplate = document.createDocumentFragment();
107: domTemplate.appendChild(element);
108: } finally {
109: if (source != null) {
110: sourceResolver.release(source);
111: }
112: manager.release(sourceResolver);
113: }
114: } else if (bindingElm.hasChildNodes()) {
115: // FIXME: using the binding's document prevents it to be garbage collected.
116: // --> create a new Document and use doc.importNode();
117: domTemplate = bindingElm.getOwnerDocument()
118: .createDocumentFragment();
119: NodeList nested = bindingElm.getChildNodes();
120: int size = nested.getLength();
121: for (int i = 0; i < size; i++) {
122: Node node = nested.item(i).cloneNode(true);
123: if (node.getNodeType() == Node.ELEMENT_NODE) {
124: LocationAttributes.remove((Element) node, true);
125: }
126: domTemplate.appendChild(node);
127: }
128: }
129:
130: // do inheritance
131: InsertNodeJXPathBinding otherBinding = (InsertNodeJXPathBinding) assistant
132: .getContext().getSuperBinding();
133: if (otherBinding != null) {
134: commonAtts = JXPathBindingBuilderBase
135: .mergeCommonAttributes(otherBinding
136: .getCommonAtts(), commonAtts);
137:
138: if (domTemplate == null) {
139: domTemplate = otherBinding.getTemplate();
140: }
141: }
142:
143: return new InsertNodeJXPathBinding(commonAtts, domTemplate);
144: } catch (BindingException e) {
145: throw e;
146: } catch (Exception e) {
147: throw new BindingException(
148: "Error building the insert-node binding", e,
149: DomHelper.getLocationObject(bindingElm));
150: }
151: }
152: }
|