protected void insertFragment()

in core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/transformation/SourceWritingTransformer.java [562:790]


    protected void insertFragment(String systemID,
                                  String path,
                                  DocumentFragment fragment,
                                  String replacePath,
                                  boolean create,
                                  boolean overwrite,
                                  String  reinsertPath,
                                  String  localSerializer,
                                  String  tagname)
    throws SAXException, IOException, ProcessingException {
        // no sync req
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Insert fragment. systemID=" + systemID +
                              ", path=" + path +
                              ", replace=" + replacePath +
                              ", create=" + create +
                              ", overwrite=" + overwrite +
                              ", reinsert=" + reinsertPath +
                              ", fragment=" + (fragment == null ? "null" : XMLUtils.serializeNode(fragment)));
        }

        // test parameter
        if (systemID == null) {
            throw new ProcessingException("insertFragment: systemID is required.");
        }
        if (path == null) {
            throw new ProcessingException("insertFragment: path is required.");
        }
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        if (fragment == null) {
            throw new ProcessingException("insertFragment: fragment is required.");
        }

        // first: read the source as a DOM
        Source source = null;
        Document resource = null;
        boolean failed = true;
        boolean exists = false;
        String message = "";
        String target = systemID;
        try {
            source = this.resolver.resolveURI(systemID);
            if (! (source instanceof ModifiableSource)) {
                throw new ProcessingException("Source '" + systemID + "' is not writeable.");
            }
            ModifiableSource ws = (ModifiableSource) source;
            exists = ws.exists();
            target = source.getURI();

            // Insert?
            if (exists && this.state == STATE_INSERT) {
                message = "content inserted at: " + path;
                resource = SourceUtil.toDOM(this.manager, source);
                // import the fragment
                Node importNode = resource.importNode(fragment, true);
                // get the node
                Node parent = DOMUtil.selectSingleNode(resource, path, this.xpathProcessor);

                // replace?
                if (replacePath != null) {
                    try {
                        Node replaceNode = DOMUtil.getSingleNode(parent, replacePath, this.xpathProcessor);
                        // now get the parent of this node until it is the parent node for insertion
                        while (replaceNode != null && !replaceNode.getParentNode().equals(parent)) {
                           replaceNode = replaceNode.getParentNode();
                        }

                        if (replaceNode != null) {
                            if (overwrite) {
                                if (parent.getNodeType() == Node.DOCUMENT_NODE) {
                                    // replacing of the document element is not allowed
                                    resource = newDocument();
                                    resource.appendChild(resource.importNode(importNode, true));
                                    parent = resource;
                                    replaceNode = resource.importNode(replaceNode, true);
                                } else {
                                    parent.replaceChild(importNode, replaceNode);
                                }
                                message += ", replacing: " + replacePath;
                                if (reinsertPath != null) {
                                    Node insertAt = DOMUtil.getSingleNode(parent, reinsertPath, this.xpathProcessor);
                                    if (insertAt != null) {
                                        while (replaceNode.hasChildNodes()) {
                                            insertAt.appendChild(replaceNode.getFirstChild());
                                        }
                                    } else { // reinsert point null
                                        message = "replace failed, could not find your reinsert path: " + reinsertPath;
                                        resource = null;
                                    }
                                }
                            } else { // overwrite was false
                                message = "replace failed, no overwrite allowed.";
                                resource = null;
                            }
                        } else { // specified replaceNode was not found
                            parent.appendChild(importNode);
                        }
                    } catch (javax.xml.transform.TransformerException sax) {
                        throw new ProcessingException("TransformerException: " + sax, sax);
                    }
                } else { // no replace path, just do an insert at end
                    parent.appendChild(importNode);
                }

            // Create?
            } else if (create) {
                // Create new document
                resource = newDocument();

                // Import the fragment
                Node importNode = resource.importNode(fragment, true);

                if (path.equals("")) {
                    // Parent node is document itself
                    NodeList nodes = importNode.getChildNodes();
                    for (int i = 0; i < nodes.getLength();) {
                        Node node = nodes.item(i);
                        switch (node.getNodeType()) {
                            case Node.ELEMENT_NODE:
                                // May throw exception if fragment has more than one element
                                resource.appendChild(node);
                                break;

                            case Node.DOCUMENT_TYPE_NODE:
                            case Node.PROCESSING_INSTRUCTION_NODE:
                            case Node.COMMENT_NODE:
                                resource.appendChild(node);
                                break;

                            default:
                                // Ignore all other nodes
                                i++;
                                break;
                        }
                    }
                    message = "entire source overwritten";

                } else {
                    // Get the parent node
                    Node parent = DOMUtil.selectSingleNode(resource, path, this.xpathProcessor);
                    // Add a fragment
                    parent.appendChild(importNode);
                    message = "content appended to: " + path;
                }

            // Oops: Document does not exist and create is not allowed.
            } else {
                message = "create not allowed";
                resource = null;/**/
            }


            // Write source
            if (resource != null) {
                resource.normalize();
                // use serializer
                if (localSerializer == null) {
                    localSerializer = this.configuredSerializerName;
                }

                if (localSerializer != null) {
                    // Lookup the Serializer
                    ServiceSelector selector = null;
                    Serializer serializer = null;
                    OutputStream oStream = null;
                    try {
                        selector = (ServiceSelector)manager.lookup(Serializer.ROLE + "Selector");
                        serializer = (Serializer)selector.select(localSerializer);
                        oStream = ws.getOutputStream();
                        serializer.setOutputStream(oStream);
                        DOMStreamer streamer = new DOMStreamer(serializer);
                        streamer.stream(resource);
                    } finally {
                        if (oStream != null) {
                            oStream.flush();
                            try {
                                oStream.close();
                                failed = false;
                            } catch (Throwable t) {
                                if (getLogger().isDebugEnabled()) {
                                    getLogger().debug("FAIL (oStream.close) exception"+t, t);
                                }
                                throw new ProcessingException("Could not process your document.", t);
                            } finally {
                                if (selector != null) {
                                    selector.release(serializer);
                                    this.manager.release(selector);
                                }
                            }
                        }
                    }
                } else {
                    if (getLogger().isDebugEnabled()) {
                        getLogger().debug("ERROR: No serializer");
                    }
                    //throw new ProcessingException("No serializer specified for writing to source " + systemID);
                    message = "That source requires a serializer, please add the appropirate tag to your code.";
                }
            }
        } catch (DOMException de) {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("FAIL exception: "+de, de);
            }
            message = "There was a problem manipulating your document: " + de;
        } catch (ServiceException ce) {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("FAIL exception: "+ce, ce);
            }
            message = "There was a problem looking up a component: " + ce;
        } catch (SourceException se) {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("FAIL exception: "+se, se);
            }
            message = "There was a problem resolving that source: [" + systemID + "] : " + se;
        } finally {
            this.resolver.release(source);
        }

        // Report result
        String result = (failed) ? RESULT_FAILED : RESULT_SUCCESS;
        String action = ACTION_NONE;
        if (!failed) {
            action = (exists) ? ACTION_OVER : ACTION_NEW;
        }

        reportResult(localSerializer, tagname, message, target, result, action);
    }