Package org.exist.xquery.functions.xmldb

Source Code of org.exist.xquery.functions.xmldb.XMLDBStore

/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2009 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*  $Id$
*/
package org.exist.xquery.functions.xmldb;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;

import org.apache.log4j.Logger;

import org.exist.dom.QName;
import org.exist.storage.serializers.EXistOutputKeys;
import org.exist.util.MimeTable;
import org.exist.util.MimeType;
import org.exist.util.serializer.SAXSerializer;
import org.exist.xmldb.EXistResource;
import org.exist.xquery.Cardinality;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.value.AnyURIValue;
import org.exist.xquery.value.BinaryValue;
import org.exist.xquery.value.FunctionReturnSequenceType;
import org.exist.xquery.value.FunctionParameterSequenceType;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.JavaObjectValue;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.StringValue;
import org.exist.xquery.value.Type;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Resource;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;

/**
* @author wolf
*/
public class XMLDBStore extends XMLDBAbstractCollectionManipulator {
 
  protected static final Logger logger = Logger.getLogger(XMLDBStore.class);

  protected static final FunctionParameterSequenceType ARG_COLLECTION = new FunctionParameterSequenceType("collection-uri", Type.STRING, Cardinality.EXACTLY_ONE, "The collection URI");
  protected static final FunctionParameterSequenceType ARG_RESOURCE_NAME = new FunctionParameterSequenceType("resource-name", Type.STRING, Cardinality.ZERO_OR_ONE, "The resource name");
  protected static final FunctionParameterSequenceType ARG_CONTENTS = new FunctionParameterSequenceType("contents", Type.ITEM, Cardinality.EXACTLY_ONE, "The contents");
  protected static final FunctionParameterSequenceType ARG_MIME_TYPE = new FunctionParameterSequenceType("mime-type", Type.STRING, Cardinality.EXACTLY_ONE, "The mime type");
 
  protected static final FunctionReturnSequenceType RETURN_TYPE = new FunctionReturnSequenceType(Type.STRING, Cardinality.ZERO_OR_ONE, "the path to new resource if sucessfully stored, otherwise the emtpty sequence");

    protected static final Properties SERIALIZATION_PROPERTIES = new Properties();
    static {
        SERIALIZATION_PROPERTIES.setProperty(EXistOutputKeys.EXPAND_XINCLUDES, "no");
    }

  public final static FunctionSignature signatures[] = {
    new FunctionSignature(
      new QName("store", XMLDBModule.NAMESPACE_URI, XMLDBModule.PREFIX),
      "Stores a new resource into the database. The resource is stored  " +
      "in the collection $collection-uri with the name $resource-name. " +
            XMLDBModule.COLLECTION_URI +
            // fixit! - security -  if URI and possibly also file object
            // DBA role should be required/ljo
            // Of course we need to think of the node case too but it has at
            // least been passed throught fn:doc() but since the retrieval
            // happens firstly who knows ...
      " The contents $contents, is either a node, an xs:string, a Java file object or an xs:anyURI. " +
      "A node will be serialized to SAX. It becomes the root node of the new " +
      "document. If $contents is of type xs:anyURI, the resource is loaded " +
      "from that URI. " +
            "Returns the path to the new document if successfully stored, " +
            "otherwise an XPathException is thrown.",
      new SequenceType[] { ARG_COLLECTION, ARG_RESOURCE_NAME, ARG_CONTENTS },
      RETURN_TYPE),
    new FunctionSignature(
      new QName("store", XMLDBModule.NAMESPACE_URI, XMLDBModule.PREFIX),
      "Stores a new resource into the database. The resource is stored  " +
      "in the collection $collection-uri with the name $resource-name. " +
            XMLDBModule.COLLECTION_URI +
            // fixit! - security -  if URI and possibly also file object
            // DBA role should be required/ljo
            // Of course we need to think of the node case too but it has at
            // least been passed through fn:doc() but since the retrieval
            // happens firstly who knows ...

            " The contents $contents, is either a node, an xs:string, a Java file object or an xs:anyURI. " +
      "A node will be serialized to SAX. It becomes the root node of the new " +
      "document. If $contents is of type xs:anyURI, the resource is loaded " +
      "from that URI. The final argument $mime-type is used to specify " +
            "a mime type.  If the mime-type is not a xml based type, the " +
            "resource will be stored as a binary resource." +
            "Returns the path to the new document if successfully stored, " +
        "otherwise an XPathException is thrown.",
      new SequenceType[] { ARG_COLLECTION, ARG_RESOURCE_NAME, ARG_CONTENTS, ARG_MIME_TYPE },
      RETURN_TYPE)
  };

  /**
   * @param context
   * @param signature
   */
  public XMLDBStore(XQueryContext context, FunctionSignature signature) {
    super(context, signature);
  }

  /* (non-Javadoc)
   * @see org.exist.xquery.Expression#eval(org.exist.dom.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
   */
  public Sequence evalWithCollection(Collection collection, Sequence args[],
    Sequence contextSequence)
    throws XPathException {
    String docName = args[1].isEmpty() ? null : args[1].getStringValue();
    if(docName != null && docName.length() == 0)
      {docName = null;}
    else if(docName != null)
      {docName = new AnyURIValue(docName).toXmldbURI().toString();}
   
    final Item item = args[2].itemAt(0);
        String mimeType = MimeType.XML_TYPE.getName();
    boolean binary = !Type.subTypeOf(item.getType(), Type.NODE);
   
    if(getSignature().getArgumentCount() == 4) {
        mimeType = args[3].getStringValue();
        final MimeType mime = MimeTable.getInstance().getContentType(mimeType);
        if (mime != null)
      {binary = !mime.isXMLType();}
           
    } else if (docName != null){
        final MimeType mime = MimeTable.getInstance().getContentTypeFor(docName);
            if (mime != null) {
                mimeType = mime.getName();
                binary = !mime.isXMLType();
            }
        }
   
    Resource resource;
    try {
      if(Type.subTypeOf(item.getType(), Type.JAVA_OBJECT)) {
        final Object obj = ((JavaObjectValue)item).getObject();
        if(!(obj instanceof File)) {
                    logger.error("Passed java object should be a File");
          throw new XPathException(this, "Passed java object should be a File");
                }
        resource = loadFromFile(collection, (File)obj, docName, binary, mimeType);

      } else if(Type.subTypeOf(item.getType(), Type.ANY_URI)) {
        try {
          final URI uri = new URI(item.getStringValue());
          resource = loadFromURI(collection, uri, docName, binary, mimeType);

        } catch (final URISyntaxException e) {
                    logger.error("Invalid URI: " + item.getStringValue());
          throw new XPathException(this, "Invalid URI: " + item.getStringValue(), e);
        }

      } else {
        if(binary) {
          resource = collection.createResource(docName, "BinaryResource");
                } else {
          resource = collection.createResource(docName, "XMLResource");
                }

        if(Type.subTypeOf(item.getType(), Type.STRING)) {
          resource.setContent(item.getStringValue());

        } else if(item.getType() == Type.BASE64_BINARY) {
          resource.setContent(((BinaryValue)item).toJavaObject());

        } else if(Type.subTypeOf(item.getType(), Type.NODE)) {
          if(binary) {
            final StringWriter writer = new StringWriter();
            final SAXSerializer serializer = new SAXSerializer();
            serializer.setOutput(writer, null);
            item.toSAX(context.getBroker(), serializer, SERIALIZATION_PROPERTIES);
            resource.setContent(writer.toString());
          } else {
            final ContentHandler handler = ((XMLResource)resource).setContentAsSAX();
            handler.startDocument();

            item.toSAX(context.getBroker(), handler, SERIALIZATION_PROPERTIES);
            handler.endDocument();
          }
        } else {
                    logger.error("Data should be either a node or a string");
          throw new XPathException(this, "Data should be either a node or a string");
                }

                ((EXistResource) resource).setMimeType(mimeType);
        collection.storeResource(resource);
      }
           
    } catch (final XMLDBException e) {
                        logger.error(e.getMessage(), e);
      throw new XPathException(this,
        "XMLDB reported an exception while storing document" + e, e);

    } catch (final SAXException e) {
            logger.error(e.getMessage());
      throw new XPathException(this, "SAX reported an exception while storing document",  e);
    }

    if (resource == null) {
      return Sequence.EMPTY_SEQUENCE;

        } else {
      try {
                //TODO : use dedicated function in XmldbURI
        return new StringValue(collection.getName() + "/" + resource.getId());
      } catch (final XMLDBException e) {
                logger.error(e.getMessage());
        throw new XPathException(this, "XMLDB reported an exception while retrieving the " +
            "stored document", e);
      }

        }
  }
 
  private Resource loadFromURI(Collection collection, URI uri, String docName, boolean binary, String mimeType)
  throws XPathException {
    Resource resource;
    if("file".equals(uri.getScheme())) {
      final String path = uri.getPath();
            if(path == null)
                {throw new XPathException(this, "Cannot read from URI: " + uri.toASCIIString());}
      final File file = new File(path);
      if(!file.canRead())
        {throw new XPathException(this, "Cannot read path: " + path);}
      resource = loadFromFile(collection, file, docName, binary, mimeType);

    } else {
      File temp = null;
      try {
        temp = File.createTempFile("existDBS", ".xml");
        // This is deleted later; is this necessary?
        temp.deleteOnExit();
        final OutputStream os = new FileOutputStream(temp);
        final InputStream is = uri.toURL().openStream();
        final byte[] data = new byte[1024];
        int read = 0;
        while((read = is.read(data)) > -1) {
          os.write(data, 0, read);
        }
        is.close();
        os.close();
        resource = loadFromFile(collection, temp, docName, binary, mimeType);
        temp.delete();

      } catch (final MalformedURLException e) {
        throw new XPathException(this, "Malformed URL: " + uri.toString(), e);

      } catch (final IOException e) {
        throw new XPathException(this, "IOException while reading from URL: " +
            uri.toString(), e);
      } finally {
        if(temp!=null)
          {temp.delete();}
      }
    }
    return resource;
  }
 
  private Resource loadFromFile(Collection collection, File file, String docName, boolean binary, String mimeType)
  throws XPathException {
    if(file.isFile()) {
      if(docName == null)
        {docName = file.getName();}
      try {
        Resource resource;
        if(binary) {
          resource = collection.createResource(docName, "BinaryResource");
                } else
          {resource = collection.createResource(docName, "XMLResource");}
                ((EXistResource)resource).setMimeType(mimeType);
        resource.setContent(file);
        collection.storeResource(resource);
        return resource;

      } catch (final XMLDBException e) {
        throw new XPathException(this, "Could not store file " + file.getAbsolutePath() +
            ": " + e.getMessage(), e);
      }
           
    } else
      {throw new XPathException(this, file.getAbsolutePath() + " does not point to a file");}
  }
}
TOP

Related Classes of org.exist.xquery.functions.xmldb.XMLDBStore

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.