/* * 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 java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.exist.EXistException; import org.exist.collections.Collection; import org.exist.dom.DocumentImpl; 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.TransactionException; import org.exist.storage.txn.TransactionManager; import org.exist.storage.txn.Txn; import org.exist.util.LockException; import org.exist.xmldb.XmldbURI; /** * Implements the WebDAV COPY method. * * @author wolf */ public class Copy extends AbstractWebDAVMethod { /** * */ public Copy(BrokerPool pool) { super(pool); } /* (non-Javadoc) * @see org.exist.http.webdav.WebDAVMethod#process(org.exist.security.User, 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 { DBBroker broker = null; Collection collection = null; DocumentImpl resource = null; try { broker = pool.get(user); collection = broker.openCollection(path, Lock.READ_LOCK); if(collection == null) { XmldbURI docUri = path.lastSegment(); XmldbURI collUri = path.removeLastSegment(); collection = broker.openCollection(collUri, Lock.READ_LOCK); if(collection == null) { LOG.debug("No resource or collection found for path: " + path); response.sendError(HttpServletResponse.SC_NOT_FOUND, NOT_FOUND_ERR); return; } resource = collection.getDocumentWithLock(broker, docUri, Lock.READ_LOCK); if(resource == null) { LOG.debug("No resource found for path: " + path); response.sendError(HttpServletResponse.SC_NOT_FOUND, NOT_FOUND_ERR); return; } } //TODO : release collection lock here ? String destination = request.getHeader("Destination"); XmldbURI destPath = null; try { URI uri = new URI(destination); String host = uri.getHost(); int port = uri.getPort(); if(!(host.equals(request.getServerName()) && port == request.getServerPort())) { response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Copying to a different server is not yet implemented"); return; } //TODO: use XmldbURI for this stuff too String tempDestPath = uri.getPath(); if(tempDestPath.startsWith(request.getContextPath())) tempDestPath = tempDestPath.substring(request.getContextPath().length()); if(tempDestPath.startsWith(request.getServletPath())) tempDestPath = tempDestPath.substring(request.getServletPath().length()); destPath = XmldbURI.create(tempDestPath); } catch (URISyntaxException e) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Malformed URL in destination header"); } if(resource != null) copyResource(user, broker, request, response, collection, resource, destPath); else copyCollection(user, broker, request, response, collection, destPath); } catch (EXistException e) { LOG.error(e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); } catch (LockException e) { LOG.debug(e.getMessage()); response.sendError(SC_RESOURCE_IS_LOCKED, e.getMessage()); } finally { if(collection != null) collection.release(Lock.READ_LOCK); if(resource != null) resource.getUpdateLock().release(Lock.READ_LOCK); pool.release(broker); } } private void copyResource(User user, DBBroker broker, HttpServletRequest request, HttpServletResponse response, Collection sourceCollection, DocumentImpl resource, XmldbURI destination) throws ServletException, IOException { XmldbURI newResourceName = destination.lastSegment(); if(newResourceName==null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Bad destination: " + destination); return; } destination = destination.removeLastSegment(); boolean replaced = false; Collection destCollection = null; TransactionManager transact = broker.getBrokerPool().getTransactionManager(); Txn transaction = transact.beginTransaction(); try { destCollection = broker.openCollection(destination, Lock.WRITE_LOCK); if(destCollection == null) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_CONFLICT, "Destination collection not found"); return; } DocumentImpl oldDoc = destCollection.getDocument(broker, newResourceName); if(oldDoc != null) { boolean overwrite = overwrite(request); if(!overwrite) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, "Destination resource exists and overwrite is not allowed"); return; } replaced = true; } //TODO : release collection lock here ? broker.copyResource(transaction, resource, destCollection, newResourceName); transact.commit(transaction); if(replaced) response.setStatus(HttpServletResponse.SC_NO_CONTENT); else response.setStatus(HttpServletResponse.SC_CREATED); } catch (PermissionDeniedException e) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage()); } catch (LockException e) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); } catch (TransactionException e) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); } finally { if(destCollection != null) destCollection.release(Lock.WRITE_LOCK); } } private void copyCollection(User user, DBBroker broker, HttpServletRequest request, HttpServletResponse response, Collection collection, XmldbURI destination) throws ServletException, IOException, EXistException { XmldbURI newCollectionName = destination.lastSegment(); if(newCollectionName==null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Bad destination: " + destination); return; } destination = destination.lastSegment(); boolean replaced = false; Collection destCollection = null; TransactionManager transact = broker.getBrokerPool().getTransactionManager(); Txn transaction = transact.beginTransaction(); try { destCollection = broker.openCollection(destination, Lock.WRITE_LOCK); if(destCollection == null) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_CONFLICT, "Destination collection not found"); return; } if(destCollection.hasChildCollection(newCollectionName)) { boolean overwrite = overwrite(request); if(!overwrite) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, "Destination collection exists and overwrite is not allowed"); return; } replaced = true; } //TODO : release collection lock here ? broker.copyCollection(transaction, collection, destCollection, newCollectionName); transact.commit(transaction); if(replaced) response.setStatus(HttpServletResponse.SC_NO_CONTENT); else response.setStatus(HttpServletResponse.SC_CREATED); } catch (PermissionDeniedException e) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage()); } catch (LockException e) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); } catch (TransactionException e) { transact.abort(transaction); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); } finally { if(destCollection != null) destCollection.release(Lock.WRITE_LOCK); } } private boolean overwrite(HttpServletRequest request) { String header = request.getHeader("Overwrite"); if(header == null) return false; return header.equals("T"); } }