Package org.apache.lenya.cms.editors.forms

Source Code of org.apache.lenya.cms.editors.forms.FormsEditor$FormPrefixResolver

/*
* 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.lenya.cms.editors.forms;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.environment.Request;
import org.apache.commons.lang.StringUtils;
import org.apache.excalibur.source.ModifiableSource;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceResolver;
import org.apache.lenya.cms.usecase.DocumentUsecase;
import org.apache.lenya.cms.usecase.UsecaseException;
import org.apache.lenya.cms.usecase.UsecaseMessage;
import org.apache.lenya.cms.usecase.xml.UsecaseErrorHandler;
import org.apache.lenya.cms.workflow.WorkflowUtil;
import org.apache.lenya.cms.workflow.usecases.UsecaseWorkflowHelper;
import org.apache.lenya.xml.DocumentHelper;
import org.apache.lenya.xml.ValidationUtil;
import org.apache.lenya.xml.XPath;
import org.apache.xindice.core.xupdate.XPathQueryFactoryImpl;
import org.apache.xindice.core.xupdate.XUpdateImpl;
import org.apache.xindice.xml.NamespaceMap;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xml.utils.PrefixResolverDefault;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmldb.common.xml.queries.XPathQueryFactory;

/**
* Multiple forms editor usecase.
*
* @version $Id: FormsEditor.java 597277 2007-11-22 00:46:12Z andreas $
*/
public class FormsEditor extends DocumentUsecase {

    protected static final String VALIDATION_ERRORS = "private.validationErrors";

    private static final class XUpdateAttributes {
        /**
         * <code>xupdateAttrExpr</code> The Xupdate expression
         */
        public String xupdateAttrExpr = "";
        /**
         * <code>tagID</code> The tag ID
         */
        public String tagID = "";

        /**
         * Set Xupdate attributes
         * @param _xupdateAttrExpr The xupdate expression
         * @param _tagID The tag id
         */
        public XUpdateAttributes(String _xupdateAttrExpr, String _tagID) {
            this.xupdateAttrExpr = _xupdateAttrExpr;
            this.tagID = _tagID;
        }
    }

    protected static final String WORKFLOW_INVOKED = "private.workflowInvoked";

    /**
     * @see org.apache.lenya.cms.usecase.AbstractUsecase#getNodesToLock()
     */
    protected org.apache.lenya.cms.repository.Node[] getNodesToLock() throws UsecaseException {
        org.apache.lenya.cms.publication.Document doc = getSourceDocument();
        Set nodes = new HashSet();
        if (doc != null) {
            nodes.add(doc.getRepositoryNode());
        }
        return (org.apache.lenya.cms.repository.Node[])
            nodes.toArray(new org.apache.lenya.cms.repository.Node[nodes.size()]);
    }

    /**
     * @see org.apache.lenya.cms.usecase.AbstractUsecase#doCheckPreconditions()
     */
    protected void doCheckPreconditions() throws Exception {
        super.doCheckPreconditions();
        if (!hasErrors()) {
            org.apache.lenya.cms.publication.Document doc = getSourceDocument();
            UsecaseWorkflowHelper.checkWorkflow(this.manager, this, getEvent(), doc, getLogger());
        }
    }

    /**
     * @see org.apache.lenya.cms.usecase.Usecase#advance()
     */
    public void advance() throws UsecaseException {
        super.advance();

        String unnumberTagsXslUri = "fallback://lenya/modules/editors/usecases/forms/unnumberTags.xsl";
        String numberTagsXslUri = "fallback://lenya/modules/editors/usecases/forms/numberTags.xsl";

        Source unnumberTagsXslSource = null;
        Source numberTagsXslSource = null;

        SourceResolver resolver = null;
        try {
            resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);

            unnumberTagsXslSource = resolver.resolveURI(unnumberTagsXslUri);
            numberTagsXslSource = resolver.resolveURI(numberTagsXslUri);

            if (getParameterAsString("cancel") != null) {
                getLogger().warn("Editing has been canceled");
                // modifiableXmlSource.delete();
                return;
            }

            Request request = ContextHelper.getRequest(this.context);
            String encoding = request.getCharacterEncoding();
            save(resolver, getSourceDocument(), unnumberTagsXslSource, numberTagsXslSource, encoding);

            if (hasErrors()) {
                setParameter(VALIDATION_ERRORS, getErrorMessages());
            } else if (!getParameterAsBoolean(WORKFLOW_INVOKED, false)) {
                deleteParameter(VALIDATION_ERRORS);
                WorkflowUtil.invoke(this.manager,
                        getSession(),
                        getLogger(),
                        getSourceDocument(),
                        getEvent());
                setParameter(WORKFLOW_INVOKED, Boolean.valueOf(true));
            }

        } catch (final Exception e) {
            throw new UsecaseException(e);
        } finally {
            if (resolver != null) {
                if (unnumberTagsXslSource != null) {
                    resolver.release(unnumberTagsXslSource);
                }
                if (numberTagsXslSource != null) {
                    resolver.release(numberTagsXslSource);
                }
                this.manager.release(resolver);
            }
        }
    }

    protected void doExecute() throws Exception {
        super.doExecute();
       
        advance();

        List errors = (List) getParameter(VALIDATION_ERRORS);
        if (errors != null) {
            for (Iterator i = errors.iterator(); i.hasNext();) {
                UsecaseMessage message = (UsecaseMessage) i.next();
                addErrorMessage(message.getMessage(), message.getParameters());
            }
        }
    }

    /**
     * Save the Form
     * @param resolver
     * @param lenyaDocument
     * @param unnumberTagsXslSource
     * @param numberTagsXslSource
     * @throws ProcessingException
     * @throws FactoryConfigurationError
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     * @throws XPathQueryConfigurationException
     * @throws Exception
     * @throws MalformedURLException
     * @throws TransformerConfigurationException
     * @throws TransformerException
     */
    private void save(SourceResolver resolver, org.apache.lenya.cms.publication.Document lenyaDocument,
            Source unnumberTagsXslSource, Source numberTagsXslSource,String encoding) throws Exception {
        if (!lenyaDocument.exists()) {
            throw new ProcessingException("The document [" + lenyaDocument + "] does not exist.");
        }
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Save modifications to [" + lenyaDocument + "]");
        }
       
        Document doc = null;
        DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
        parserFactory.setValidating(false);
        parserFactory.setNamespaceAware(true);
        parserFactory.setIgnoringElementContentWhitespace(true);
        DocumentBuilder builder = parserFactory.newDocumentBuilder();

        InputSource xmlInputSource = new InputSource(lenyaDocument.getInputStream());
        Document document = builder.parse(xmlInputSource);

        Document renumberedDocument = renumberDocument(document, unnumberTagsXslSource,numberTagsXslSource);
       
        System.setProperty(XPathQueryFactory.class.getName(), XPathQueryFactoryImpl.class.getName());

        XUpdateImpl xUpdate = new XUpdateImpl();

        String editSelect = processElements(renumberedDocument, xUpdate);
        setParameter("editSelect", editSelect);

        Source validationSource = null;
        Source unnumberTagsSource = null;

        try {
            String validationUri = lenyaDocument.getSourceURI() + ".validate";
            validationSource = resolver.resolveURI(validationUri);
            checkModifiability(validationSource);

            String unnumberTagsUri = lenyaDocument.getSourceURI() + ".validate.unnumber";
            unnumberTagsSource = resolver.resolveURI(unnumberTagsUri);
            checkModifiability(unnumberTagsSource);

            javax.xml.transform.Source transformXmlSource = new DOMSource(renumberedDocument);
            javax.xml.transform.Source transformXslSource = new StreamSource(unnumberTagsXslSource.getInputStream());

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            StreamResult unnumberXmlResult = new StreamResult(out);

            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(transformXslSource);
            transformer.transform(transformXmlSource, unnumberXmlResult);

            ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
            doc = DocumentHelper.readDocument(in);
           
            ValidationUtil.validate(this.manager, doc, getSourceDocument().getResourceType()
                    .getSchema(), new UsecaseErrorHandler(this));

        } finally {
            if (validationSource != null) {
                resolver.release(validationSource);
            }
            if (unnumberTagsSource != null) {
                resolver.release(unnumberTagsSource);
            }
        }

        if (doc != null){
          writeDocument(doc, getSourceDocument().getOutputStream(), encoding);
        }
    }

    /**
     * Process elements
     * @param document
     * @param xq
     * @return A string.
     * @throws Exception
     */
    private String processElements(Document document, XUpdateImpl xq) throws Exception {
        String editSelect = null;
        String[] paramNames = getParameterNames();
        for (int paramIndex = 0; paramIndex < paramNames.length; paramIndex++) {
            String pname = paramNames[paramIndex];
            getLogger().debug("Parameter: " + pname + " = " + getParameterAsString(pname));

            // Extract the xpath to edit
            if (pname.indexOf("edit[") >= 0) {
                if (pname.endsWith("].x")) {
                    editSelect = pname.substring(5, pname.length() - 3);
                    getLogger().debug("Edit: " + editSelect);
                }
                deleteParameter(pname);
            }

            // Make sure we are dealing with an xupdate statement,
            // else skip
            if (pname.startsWith("<xupdate:")) {
                String select = pname.substring(pname.indexOf("select") + 8);
                select = select.substring(0, select.indexOf("\""));
                getLogger().debug("Select Node: " + select);

                // Check if node exists
                PrefixResolver resolver = new FormPrefixResolver(document.getDocumentElement());
                XObject xObject = XPathAPI.eval(document.getDocumentElement(), select, resolver);
                NodeList nodes = xObject.nodelist();
                if (nodes.getLength() == 0) {
                    getLogger().debug(".act(): Node does not exist (might have been deleted during update): "
                            + select);
                } else {
                    String xupdateModifications = null;
                    // now check for the different xupdate
                    // statements, and handle appropriately
                    if (pname.indexOf("xupdate:update-parent") > 0) {
                        getLogger().debug("UPDATE PARENT Node: " + pname);
                        // CDATA updates need to be handled
                        // seperately
                        if (pname.indexOf("<![CDATA[") > 0) {
                            xupdateModifications = updateCDATA(pname, true);
                        } else {
                            xupdateModifications = update(pname, select, nodes.item(0), true);
                        }
                    } else if (pname.indexOf("xupdate:update") > 0) {
                        getLogger().debug("UPDATE Node: " + pname);
                        // CDATA updates need to be handled
                        // seperately
                        if (pname.indexOf("<![CDATA[") > 0) {
                            xupdateModifications = updateCDATA(pname, false);
                        } else {
                            xupdateModifications = update(pname, select, nodes.item(0), false);
                        }
                    } else if (pname.indexOf("xupdate:append") > 0 && pname.endsWith(">.x")) {
                        xupdateModifications = append(pname.substring(0, pname.length() - 2));
                        // insert-before: in case of select/option
                    } else if (pname.indexOf("xupdate:insert-before") > 0 && pname.endsWith("/>")) {
                        if (!getParameterAsString(pname).equals("null")) {
                            xupdateModifications = insertBefore(getParameterAsString(pname));
                            editSelect = pname.substring(31,pname.length() - 3);
                            editSelect = changeTagNumber(editSelect, -1);
                        }
                        // insert-before: in case of image
                    } else if (pname.indexOf("xupdate:insert-before") > 0 && pname.endsWith(">.x")) {
                      xupdateModifications = insertBefore(pname.substring(0, pname.length() - 2));
                        // insert-after: in case of select/option
                    } else if (pname.indexOf("xupdate:insert-after") > 0 && pname.endsWith("/>")) {
                        if (!getParameterAsString(pname).equals("null")) {
                            xupdateModifications = insertAfter(getParameterAsString(pname));
                            editSelect = pname.substring(30,pname.length() - 3);
                            editSelect = changeTagNumber(editSelect, 1);
                        }
                        // insert-after: in case of image
                    } else if (pname.indexOf("xupdate:insert-after") > 0 && pname.endsWith(">.x")) {
                        xupdateModifications = insertAfter(pname.substring(0, pname.length() - 2));
                    } else if (pname.indexOf("xupdate:remove") > 0 && pname.endsWith("/>.x")) {
                        xupdateModifications = remove(pname.substring(0, pname.length() - 2));
                        editSelect = pname.substring(24,pname.length() - 3);
                    } else if (pname.endsWith(">.y")) {
                        getLogger().debug("Don't handle this: " + pname);
                    } else {
                        getLogger().debug("Don't handle this either: " + pname);
                    }

                    // Get hidden namespaces
                    String namespaces = getParameterAsString("namespaces");

                    // Add XML declaration
                    // NOTE: select/option is generating parameter
                    // which should be considered as null
                    if (xupdateModifications != null) {
                        xupdateModifications = "<?xml version=\"1.0\"?>" + xupdateModifications;
                    }

                    // now run the assembled xupdate query
                    if (xupdateModifications != null) {
                        getLogger().info("Execute XUpdate Modifications: " + xupdateModifications);
                        xq.setQString(xupdateModifications);
                        xq.setNamespaceMap(getNamespaceMap(namespaces));
                        xq.execute(document);
                    } else {
                        getLogger().debug("Parameter did not match any xupdate command: " + pname);
                    }
                }
                deleteParameter(pname);
            }
        }
        return editSelect;
    }

    protected NamespaceMap getNamespaceMap(String namespaces) {
        NamespaceMap nsMap = new NamespaceMap();
        String[] namespace = namespaces.split("[\\s]+");
        for (int i = 0; i < namespace.length; i++) {
            String[] prefixAndUri = namespace[i].split("=");
            String prefix = prefixAndUri[0];
            String uri = prefixAndUri[1].replaceAll("\"", "");
           
            int colonIndex = prefix.indexOf(":");
            if (colonIndex == -1) {
                nsMap.setDefaultNamespace(uri);
            } else {
                prefix = prefix.substring(colonIndex + 1);
                if (!nsMap.containsKey(prefix)) {
                    nsMap.setNamespace(prefix, uri);
                }
            }
        }
        return nsMap;
    }

    /**
     * Change the tag number of the selected node.
     * The variable is used in a javascript in order to jump to the
     * appropriate node after deleting or inserting a node.
     * @param tagID The tagID where the new node is inserted.
     * @param step  int value for changing the tagID.
     */  
    protected String changeTagNumber(String tagID, int step){
        String number = tagID.substring(tagID.lastIndexOf(".")+1,tagID.lastIndexOf("]")-1);
        int num = Integer.parseInt(number) + step;
        String newTagNumber = tagID.substring(0, tagID.lastIndexOf(".")+1);
        return newTagNumber.concat(Integer.toString(num)+"']");
    }

    /**
     * Writes a document to a modifiable source.
     * @param document The document.
     * @param oStream The source.
     * @throws IOException if an error occurs.
     * @throws TransformerConfigurationException if an error occurs.
     * @throws TransformerException if an error occurs.
     * @throws ProcessingException if an error occurs.
     */
    protected void writeDocument(Document document, OutputStream oStream, String encoding) throws IOException,
            TransformerConfigurationException, TransformerException, ProcessingException {
        Writer writer = new OutputStreamWriter(oStream, encoding);
        DocumentHelper.writeDocument(document, writer);
        if (oStream != null) {
            oStream.flush();
            try {
                oStream.close();
            } catch (Throwable t) {
                if (getLogger().isDebugEnabled()) {
                    getLogger().debug("Exception closing output stream: ", t);
                }
                throw new ProcessingException("Could not write document: ", t);
            }
        }
    }

    /**
     * Checks if a source is modifiable.
     * @param source The source.
     * @throws ProcessingException if the source is not modifiable.
     */
    protected void checkModifiability(Source source) throws ProcessingException {
        if (!(source instanceof ModifiableSource)) {
            throw new ProcessingException("Cannot write to source [" + source.getURI() + "]");
        }
    }

    /**
     * Get attributes from original node
     * @param node Original node
     * @return An XupdateAttributes class holding the attributes
     */
    private XUpdateAttributes getAttributes(Node node) {

        StringBuffer buf = new StringBuffer();
        String xupdateString = "";
        String tagID = "";
        org.w3c.dom.NamedNodeMap attributes = node.getAttributes();
        if (attributes != null) {
            for (int i = 0; i < attributes.getLength(); i++) {
                org.w3c.dom.Attr attribute = (org.w3c.dom.Attr) attributes.item(i);
                getLogger().debug(".getAttributes(): " + attribute.getName() + " "
                        + attribute.getValue());
                if (!attribute.getName().equals("tagID")) {
                    String namespace = attribute.getNamespaceURI();
                    getLogger().debug(".getAttributes(): Namespace: " + namespace);
                    String namespaceAttribute = "";
                    if (namespace != null) {
                        namespaceAttribute = " namespace=\"" + namespace + "\"";
                    }
                    buf.append("<xupdate:attribute name=\"" + attribute.getName() + "\""
                            + namespaceAttribute + ">" + attribute.getValue()
                            + "</xupdate:attribute>");
                } else {
                    buf.append("<xupdate:attribute name=\"tagID\">temp</xupdate:attribute>");
                    tagID = attribute.getValue();
                }
            }
            xupdateString = buf.toString();
        } else {
            xupdateString = "";
        }
        getLogger().debug("Attributes: " + xupdateString);

        return new XUpdateAttributes(xupdateString, tagID);
    }

    /**
     * Get attributes from actual update
     * @param update The actual update
     * @param tagID The tag id to get the updates for
     * @return An XupdateAttributes class holding the attributes
     */
    private XUpdateAttributes getAttributes(String update, String tagID) {
        getLogger().debug(update);

        StringBuffer xupdateBuffer = new StringBuffer("<xupdate:attribute name=\"tagID\">temp</xupdate:attribute>");

        String[] attributes = update.substring(0, update.indexOf(">")).split(" ");
        for (int i = 1; i < attributes.length; i++) {
            // TODO: beware of white spaces
            int index = attributes[i].indexOf("=");
            if (index > 0) {
                String name = attributes[i].substring(0, index);
                String value = attributes[i].substring(index + 2, attributes[i].length() - 1);
                if (name.indexOf("xmlns") < 0) {
                    xupdateBuffer.append("<xupdate:attribute name=\"" + name + "\">");
                    xupdateBuffer.append(value).append("</xupdate:attribute>");
                }
            }
        }

        getLogger().debug("Attributes: " + xupdateBuffer.toString());

        return new XUpdateAttributes(xupdateBuffer.toString(), tagID);
    }

    /**
     * xupdate:update
     * @param pname Name of the parent element
     * @param select The attribute to update
     * @param nodeToUpdate The node to update
     * @param parent If true then parent element is part of update and attributes need to be updated
     *            resp. added or deleted
     * @return the Xupdate statement
     */
    private String update(String pname, String select, Node nodeToUpdate, boolean parent) {
        getLogger().debug("Update node: " + select);

        // deal with attribute values here..
        if (nodeToUpdate.getNodeType() == Node.ATTRIBUTE_NODE) {
            getLogger().debug("Update attribute: " + select);

            String xupdateUpdate = pname + getParameterAsString(pname) + "</xupdate:update>";
            return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">"
                    + xupdateUpdate + "</xupdate:modifications>";
            /*
             * And deal with mixed content here.. NOTE: Lexus has trouble with mixed content. As
             * Workaround we insert-after the new node, remove the original node and replace the
             * temporary tagID by the original tagID.
             */
        }

        getLogger().debug("Update element: " + select);

        String namespace = nodeToUpdate.getNamespaceURI();
        String namespaceAttribute = "";
        if (namespace != null) {
            namespaceAttribute = " namespace=\"" + namespace + "\"";
        }
        // NOTE: getAttributes adds the attribute tagID with value "temp",
        // which will be replaced further down
        XUpdateAttributes xa = getAttributes(nodeToUpdate);
        String xupdateInsertAfter = null;
        if (parent) {
            xa = getAttributes(getParameterAsString(pname), xa.tagID);
            xupdateInsertAfter = "<xupdate:insert-after select=\"" + select
                    + " \"><xupdate:element name=\"" + new XPath(select).getNameWithoutPredicates()
                    + "\"" + namespaceAttribute + ">" + xa.xupdateAttrExpr
                    + removeParent(getParameterAsString(pname))
                    + "</xupdate:element></xupdate:insert-after>";
        } else {
            xupdateInsertAfter = "<xupdate:insert-after select=\"" + select
                    + " \"><xupdate:element name=\"" + new XPath(select).getNameWithoutPredicates()
                    + "\"" + namespaceAttribute + ">" + xa.xupdateAttrExpr
                    + getParameterAsString(pname) + "</xupdate:element></xupdate:insert-after>";
        }
        getLogger().debug(".update(): Update Node (insert-after): " + xupdateInsertAfter);

        String xupdateRemove = "<xupdate:remove select=\"" + select + " \"/>";
        getLogger().debug(".update(): Update Node (remove): " + xupdateRemove);

        String xupdateUpdateAttribute = "<xupdate:update select=\""
                + new XPath(select).removePredicates(select) + "[@tagID='temp']/@tagID" + " \">"
                + xa.tagID + "</xupdate:update>";
        getLogger().debug(".update(): Update Node (update tagID attribute): "
                + xupdateUpdateAttribute);

        return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">"
                + xupdateInsertAfter + xupdateRemove + xupdateUpdateAttribute
                + "</xupdate:modifications>";
    }

    /**
     * xupdate:update CDATA
     * @param pname The name of the parent element
     * @param parent if true then attributes of parent will also be updated
     * @return The Xupdate expression
     */
    private String updateCDATA(String pname, boolean parent) {
        String xupdateUpdate = pname + getParameterAsString(pname) + "]]></xupdate:update>";
        return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">"
                + xupdateUpdate + "</xupdate:modifications>";
    }

    /**
     * xupdate:append
     * @param pname The node to append to
     * @return The Xupdate statement
     */
    private String append(String pname) {
        getLogger().debug(".append() APPEND Node: " + pname);
        return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
                + "</xupdate:modifications>";
    }

    /**
     * xupdate:insert-before
     * @param pname The node to insert before
     * @return The Xupdate statement
     */
    private String insertBefore(String pname) {
        getLogger().debug(".insertBefore() INSERT-BEFORE Node: " + pname);
        return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
                + "</xupdate:modifications>";
    }

    /**
     * xupdate:insert-after
     * @param pname The node to insert after
     * @return The Xupdate statement
     */
    private String insertAfter(String pname) {
        getLogger().debug(".insertAfter() INSERT-AFTER Node: " + pname);
        return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
                + "</xupdate:modifications>";
    }

    /**
     * xupdate:remove
     * @param pname The node to remove
     * @return The Xupdate statement
     */
    private String remove(String pname) {
        getLogger().debug(".remove() REMOVE Node: " + pname);
        return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
                + "</xupdate:modifications>";
    }

    /**
     * Renumber the tags within a document. Each tag gets a unique number used in Xupdate
     * expressions.
     * @param doc The document to renumber
     * @param unnumberTagsXSL The XSL stylesheet to remove the tagID attribute
     * @param numberTagsXSL The XSL stylesheet to add the tagID attribute
     * @return The renumbered document
     * @throws UsecaseException
     */
    private Document renumberDocument(Document doc, Source unnumberTagsXSL, Source numberTagsXSL)
            throws UsecaseException {

        try {
            DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
            parserFactory.setValidating(false);
            parserFactory.setNamespaceAware(true);
            parserFactory.setIgnoringElementContentWhitespace(true);
            DocumentBuilder builder = parserFactory.newDocumentBuilder();

            TransformerFactory tf = TransformerFactory.newInstance();

            // Remove tagIDs
            Transformer ut = tf.newTransformer(new StreamSource(unnumberTagsXSL.getInputStream()));
            Document unnumberedDocument = builder.newDocument();
            ut.transform(new DOMSource(doc), new DOMResult(unnumberedDocument));

            // Add tagIDs
            Transformer nt = tf.newTransformer(new StreamSource(numberTagsXSL.getInputStream()));
            Document renumberedDocument = builder.newDocument();
            nt.transform(new DOMSource(unnumberedDocument), new DOMResult(renumberedDocument));

            return renumberedDocument;
        } catch (final Exception e) {
            throw new UsecaseException(e);
        }
    }

    /**
     * Remove parent element
     * @param xmlSnippet The XML snippet to remove the parent from
     * @return The XML snippet with the parent removed
     */
    private String removeParent(String xmlSnippet) {
        String xmlSnippetWithoutParent = xmlSnippet;
        xmlSnippetWithoutParent = xmlSnippetWithoutParent.substring(xmlSnippetWithoutParent.indexOf(">") + 1);
        xmlSnippetWithoutParent = StringUtils.reverse(xmlSnippetWithoutParent);
        xmlSnippetWithoutParent = xmlSnippetWithoutParent.substring(xmlSnippetWithoutParent.indexOf("<") + 1);
        xmlSnippetWithoutParent = StringUtils.reverse(xmlSnippetWithoutParent);
        return xmlSnippetWithoutParent;
    }

    /**
     * Prefix resolver which uses the usecase parameters like
     * "namespace.xhtml=http://www.w3.org/1999/xhtml" to resolve prefixes.
     */
    public class FormPrefixResolver extends PrefixResolverDefault {

        /**
         * Ctor.
         * @param context The context node.
         */
        public FormPrefixResolver(Node context) {
            super(context);
        }

        /**
         * @see org.apache.xml.utils.PrefixResolver#getNamespaceForPrefix(java.lang.String,
         *      org.w3c.dom.Node)
         */
        public String getNamespaceForPrefix(String prefix, Node context) {
            String uri = super.getNamespaceForPrefix(prefix, context);
            if (uri == null) {
                uri = FormsEditor.this.getParameterAsString("namespace." + prefix);
            }
            return uri;
        }

    }

    protected String getEvent() {
        return "edit";
    }

}
TOP

Related Classes of org.apache.lenya.cms.editors.forms.FormsEditor$FormPrefixResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.