Package org.apache.xindice.core.xupdate

Source Code of org.apache.xindice.core.xupdate.XUpdateImpl

/*
* 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.
*
* $Id: XUpdateImpl.java 511426 2007-02-25 03:25:02Z vgritsenko $
*/

package org.apache.xindice.core.xupdate;

import org.apache.xindice.core.Collection;
import org.apache.xindice.core.data.NodeSet;
import org.apache.xindice.xml.NamespaceMap;
import org.apache.xindice.xml.NodeSource;
import org.apache.xindice.xml.dom.CompressedNode;
import org.apache.xindice.xml.dom.DBNode;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import org.xmldb.xupdate.lexus.XUpdateQueryImpl;
import org.xmldb.xupdate.lexus.commands.CommandConstants;
import org.xmldb.xupdate.lexus.commands.CommandObject;
import org.xmldb.xupdate.lexus.commands.DefaultCommand;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

/**
* Provides Collection and document based XUpdate capabilities.
*
* For more detail about XUpdate look at the
* <a href="http://xmldb-org.sourceforge.net/xupdate/xupdate-wd.html">XUpdate Working Draft</a>.
*
* @version $Revision: 511426 $, $Date: 2007-02-24 22:25:02 -0500 (Sat, 24 Feb 2007) $
*/
public class XUpdateImpl extends XUpdateQueryImpl {

    /**
     * If set to true, then namespaces set explicitly via an API call will take precendence.
     * If set to false, then namespaces set implicitly within query string will take precedence.
     */
    private static final boolean API_NS_PRECEDENCE = true;

    protected int nodesModified;
    protected NamespaceMap nsMap;

    /**
     * Set the namespace map to be used when resolving queries
     */
    public void setNamespaceMap(NamespaceMap nsMap) {
        if (nsMap == null) {
            return;
        }

        if (this.nsMap == null) {
            this.nsMap = nsMap;
        } else {
            this.nsMap.includeNamespaces(nsMap, API_NS_PRECEDENCE);
        }
    }


    /**
     * Sets the query string to be used when executing update
     */
    public void setQString(String query) throws SAXException {
        super.setQString(query);
        if (nsMap == null) {
            nsMap = new NamespaceMap();
        }
        nsMap.includeNamespaces(super.namespaces, !API_NS_PRECEDENCE);
    }


    /**
     * Execute the XUpdate commands against a document.
     */
    public void execute(Node contextNode) throws Exception {
        CommandObject currentCommand = new DefaultCommand(contextNode);
        Enumeration commands = super.query[0].elements();
        Enumeration attributes = super.query[1].elements();
        Enumeration characters = super.query[2].elements();
        Node origNode = contextNode;
        CommandObject.getXPath().setNamespace(nsMap.getContextNode());

        while (commands.hasMoreElements()) {
            int id = ((Integer) commands.nextElement()).intValue();

            if (id == CommandConstants.ATTRIBUTES) {
                currentCommand.submitAttributes((Hashtable) attributes.nextElement());
            } else if (id == CommandConstants.CHARACTERS) {
                currentCommand.submitCharacters((String) characters.nextElement());
            } else if (id > 0) {
                if (!currentCommand.submitInstruction(id)) {
                    super.commandConstants.setContextNode(contextNode);
                    currentCommand = super.commandConstants.commandForID(id);
                    if (currentCommand == null) {
                        throw new Exception("Operation can not have any XUpdate-instruction!");
                    }
                    currentCommand.reset();
                }
            } else {
                if (!currentCommand.executeInstruction()) {
                    try {
                        contextNode = currentCommand.execute();
                    } catch (Exception e) {
                        // While not ideal, CommandObject.execute throws
                        // Exception("no nodes selected !") if nothing is
                        // selected for modification we trap that case
                        // and ignore allowing continued processing
                        // of remaining xupdate instructions that may be present
                        if (!"no nodes selected !".equals(e.getMessage())) {
                            throw e;
                        }
                    }
                    // Default do-nothing command will soak up anything
                    // (characters, attributes, etc.) encountered until we
                    // come across the next xupdate instruction
                    // (e.g. remove, append, insert, etc.)
                    currentCommand = new DefaultCommand(contextNode);
                }
            }
        }

        if (origNode instanceof CompressedNode) {
            CompressedNode cn = (CompressedNode) origNode;
            if (cn.isDirty()) {
                nodesModified++;
            }
        }
    }

    /**
     * Execute the set of XUpdate commands against a collection.
     *
     * @param col The collection against which the command will be executed
     * @exception Exception Description of Exception
     */
    public void execute(Collection col) throws Exception {
        int attribIndex = 0;

        // TODO: Don't cache all the documents in memory.
        // Need to keep updated documents in memory so that can
        // 'rollback' all the changes in case of failure.
        // Won't need this in case underlying collection supports
        // transaction.
        HashMap docsUpdated = new HashMap();
        for (int i = 0; i < super.query[0].size(); i++) {
            int cmdID = ((Integer) super.query[0].elementAt(i)).intValue();

            if (cmdID == CommandConstants.ATTRIBUTES) {
                Hashtable attribs = (Hashtable) super.query[1].elementAt(attribIndex);
                String selector = (String) attribs.get("select");
                attribIndex++;

                // If we found an XPath selector we need to execute the commands,
                // but we can not execute xupdate variables again.
                // all variables start with a '$'
                if (selector != null && !selector.startsWith("$")) {
                    NodeSet ns = col.queryCollection("XPath", selector, nsMap);
                    while (ns != null && ns.hasMoreNodes()) {
                        DBNode node = (DBNode) ns.getNextNode();
                        Document doc = node.getOwnerDocument();
                        NodeSource source = node.getSource();

                        if (docsUpdated.containsKey(source.getKey())) {
                            continue; // We only have to process it once
                        } else {
                            docsUpdated.put(source.getKey(), doc);
                        }

                        execute(doc.getDocumentElement());
                    }
                }
            }
        }

        // Update all documents at once
        // this way we don't get any half run xupdate commands.
        Iterator i = docsUpdated.entrySet().iterator();
        while (i.hasNext()) {
            Map.Entry set = (Map.Entry) i.next();
            col.setDocument(set.getKey(), (Document) set.getValue());
        }
    }

    public int getModifiedCount() {
        return nodesModified;
    }
}
TOP

Related Classes of org.apache.xindice.core.xupdate.XUpdateImpl

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.