/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-06 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* $Id$
*/
package org.exist.http.webdav.methods;
import org.exist.EXistException;
import org.exist.collections.Collection;
import org.exist.collections.IndexInfo;
import org.exist.collections.triggers.TriggerException;
import org.exist.dom.DocumentImpl;
import org.exist.dom.LockToken;
import org.exist.security.PermissionDeniedException;
import org.exist.security.User;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
import org.exist.storage.lock.Lock;
import org.exist.storage.txn.TransactionManager;
import org.exist.storage.txn.Txn;
import org.exist.util.LockException;
import org.exist.util.MimeTable;
import org.exist.util.MimeType;
import org.exist.xmldb.XmldbURI;
import org.exist.xquery.value.StringValue;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Implements the WebDAV PUT method.
*
* @author wolf
* @author dizzz
*/
public class Put extends AbstractWebDAVMethod {
public Put(BrokerPool pool) {
super(pool);
}
/* (non-Javadoc)
* @see org.exist.http.webdav.WebDAVMethod#process(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.exist.collections.Collection, org.exist.dom.DocumentImpl)
*/
public void process(User user, HttpServletRequest request,
HttpServletResponse response, XmldbURI path) throws ServletException, IOException {
LOG.debug("PUT start");
File tempFile = saveRequestContent(request);
String url = tempFile.toURI().toASCIIString();
String contentType = request.getContentType();
DBBroker broker = null;
Collection collection = null;
boolean collectionLocked = true;
TransactionManager transact = pool.getTransactionManager();
Txn txn = transact.beginTransaction();
try {
broker = pool.get(user);
XmldbURI pathUri = path.lastSegment();
XmldbURI collUri = path.removeLastSegment();
LOG.debug("collUri='"+collUri+"'; path="+pathUri+"';" );
collection = broker.openCollection(collUri, Lock.READ_LOCK);
// TODO check why not use WRITE_LOCK here?
if(collection == null) {
transact.abort(txn);
response.sendError(HttpServletResponse.SC_CONFLICT,
"Parent collection " + collUri + " not found");
return;
}
if(collection.hasChildCollection(pathUri)) {
transact.abort(txn);
response.sendError(HttpServletResponse.SC_CONFLICT,
"Cannot overwrite an existing collection with a resource");
return;
}
MimeType mime;
if(contentType == null) {
mime = MimeTable.getInstance().getContentTypeFor(pathUri);
if (mime != null)
contentType = mime.getName();
} else {
int p = contentType.indexOf(';');
if (p > -1)
contentType = StringValue.trimWhitespace(contentType.substring(0, p));
mime = MimeTable.getInstance().getContentType(contentType);
}
if (mime == null){
mime = MimeType.BINARY_TYPE;
}
LOG.debug("Storing document " + pathUri + "; content-type='" + contentType+"'");
DocumentImpl doc = null;
if(mime.isXMLType()) {
LOG.debug("Storing XML resource");
// 0 byte XML files cannot exist, create place colder
if(tempFile.length()==0L){
LOG.debug("Create '0 byte' place for XML resource");
String txt="<!-- place holder for null byte sized XML document --><null/>";
InputSource is = new InputSource(url);
IndexInfo info = collection.validateXMLResource(txn, broker, pathUri, txt);
doc = info.getDocument();
doc.getMetadata().setMimeType(contentType);
collection.store(txn, broker, info, txt, false);
} else {
InputSource is = new InputSource(url);
IndexInfo info = collection.validateXMLResource(txn, broker, pathUri, is);
doc = info.getDocument();
doc.getMetadata().setMimeType(contentType);
collection.store(txn, broker, info, is, false);
}
LOG.debug("done");
} else {
LOG.debug("Storing binary resource");
FileInputStream is = new FileInputStream(tempFile);
doc = collection.addBinaryResource(txn, broker, pathUri, is, contentType, (int) tempFile.length());
is.close();
LOG.debug("done");
}
// Remove Null Resource flag
LockToken token = doc.getMetadata().getLockToken();
if(token!=null){
token.setResourceType(LockToken.RESOURCE_TYPE_NOT_SPECIFIED);
} else {
LOG.debug("token==null");
}
transact.commit(txn);
LOG.debug("PUT ready");
} catch (EXistException e) {
transact.abort(txn);
LOG.error(e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
e.getMessage());
return;
} catch (PermissionDeniedException e) {
transact.abort(txn);
LOG.debug(e);
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
return;
} catch (TriggerException e) {
transact.abort(txn);
LOG.debug(e);
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
return;
} catch (SAXException e) {
transact.abort(txn);
LOG.debug(e);
response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
return;
} catch (LockException e) {
transact.abort(txn);
LOG.debug(e);
response.sendError(HttpServletResponse.SC_CONFLICT, e.getMessage());
return;
} finally {
pool.release(broker);
if(collectionLocked && collection != null)
collection.release(Lock.READ_LOCK);
tempFile.delete();
}
response.setStatus(HttpServletResponse.SC_CREATED);
}
private File saveRequestContent(HttpServletRequest request) throws IOException {
ServletInputStream is = request.getInputStream();
int len = request.getContentLength();
// put may send a lot of data, so save it
// to a temporary file first.
File tempFile = File.createTempFile("existSRC", ".tmp");
FileOutputStream fos = new FileOutputStream(tempFile);
BufferedOutputStream os = new BufferedOutputStream(fos);
if(len!=0){
byte[] buffer = new byte[4096];
int count, l = 0;
do {
count = is.read(buffer);
if (count > 0)
os.write(buffer, 0, count);
l += count;
} while (l < len);
os.close();
is.close(); // DIZ: sure about this?
}
return tempFile;
}
}