Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 251   Methods: 4
NCLOC: 159   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DAVOperations.java 40% 53.6% 100% 49.7%
coverage coverage
 1    /*
 2    * Licensed to the Apache Software Foundation (ASF) under one or more
 3    * contributor license agreements. See the NOTICE file distributed with
 4    * this work for additional information regarding copyright ownership.
 5    * The ASF licenses this file to You under the Apache License, Version 2.0
 6    * (the "License"); you may not use this file except in compliance with
 7    * the License. You may obtain a copy of the License at
 8    *
 9    * http://www.apache.org/licenses/LICENSE-2.0
 10    *
 11    * Unless required by applicable law or agreed to in writing, software
 12    * distributed under the License is distributed on an "AS IS" BASIS,
 13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14    * See the License for the specific language governing permissions and
 15    * limitations under the License.
 16    *
 17    * $Id: DAVOperations.java 600169 2007-12-01 17:25:52Z vgritsenko $
 18    */
 19   
 20    package org.apache.xindice.webadmin.util;
 21   
 22    import org.apache.xindice.core.Collection;
 23    import org.apache.xindice.core.DBException;
 24    import org.apache.xindice.core.FaultCodes;
 25    import org.apache.xindice.core.data.Key;
 26    import org.apache.xindice.core.data.Entry;
 27    import org.apache.xindice.webadmin.webdav.WebdavStatus;
 28    import org.apache.xindice.webadmin.Location;
 29    import org.apache.xindice.util.Configuration;
 30    import org.apache.commons.logging.Log;
 31    import org.apache.commons.logging.LogFactory;
 32    import org.w3c.dom.Document;
 33   
 34    import java.util.HashMap;
 35    import java.util.Map;
 36    import java.util.Collections;
 37   
 38    /**
 39    * Helper for copy/move operations.
 40    *
 41    * @author <a href="mailto:jmetzner@apache.org">Jan Metzner</a>
 42    * @version $Revision: 600169 $, $Date: 2007-12-01 17:25:52 +0000 (Sat, 01 Dec 2007) $
 43    */
 44    public class DAVOperations {
 45   
 46    private static final Log log = LogFactory.getLog(DAVOperations.class);
 47   
 48    /**
 49    * Copies collection to the new destination
 50    *
 51    * @param col Collection to be copied
 52    * @param dest Destination path (includes DB name)
 53    * @param overwrite true if previously existed collection at dest path can be overwritten
 54    * @return map containing status for a path
 55    * @throws DBException
 56    */
 57  5 public static Map copy(Collection col, String dest, boolean overwrite, boolean deep) throws DBException {
 58   
 59  5 Location destLocation = new Location(dest);
 60  5 Collection destCollection = destLocation.getCollection();
 61  5 String destName = destLocation.getName();
 62  5 Map results = new HashMap();
 63   
 64  5 if (destLocation.isRoot()) {
 65  0 results.put(dest, new Integer(WebdavStatus.SC_BAD_REQUEST));
 66  0 return results;
 67  5 } else if (destCollection == null) {
 68    // either intermidiate collection does not exist or destination points to
 69    // the first level collection (database).
 70  0 results.put(dest, new Integer(WebdavStatus.SC_CONFLICT));
 71  0 return results;
 72  5 } else if (deep && destCollection.getCanonicalName().startsWith(col.getCanonicalName())) {
 73    // destination points to a location inside target collection subtree.
 74    // deep copy does not make sense in that case
 75  2 results.put(dest, new Integer(WebdavStatus.SC_FORBIDDEN));
 76  2 return results;
 77    }
 78   
 79    // FIXME: the operations are not atomic, they can fail because of another
 80    // thread deleting or creating collections. Introduce locks.
 81  3 if (destName != null) { // destination collection does not exist
 82   
 83  3 results.putAll(copyCollection(col, destCollection, destName, deep));
 84  3 if (results.size() == 0) {
 85  3 results.put(dest, new Integer(WebdavStatus.SC_CREATED));
 86    }
 87    } else { // existing collection
 88   
 89  0 if (overwrite) {
 90    // overwrites the collection
 91  0 String name = destCollection.getName();
 92  0 Collection parent = destCollection.getParentCollection();
 93    // delete collection
 94  0 parent.dropCollection(destCollection);
 95  0 results.putAll(copyCollection(col, parent, name, deep));
 96  0 if (results.size() == 0) {
 97  0 results.put(dest, new Integer(WebdavStatus.SC_NO_CONTENT));
 98    }
 99    } else {
 100  0 results.put(dest, new Integer(WebdavStatus.SC_PRECONDITION_FAILED));
 101    }
 102   
 103    }
 104   
 105  3 return results;
 106    }
 107   
 108    /**
 109    * Copies a resource to a new location.
 110    *
 111    * @param col Source collection
 112    * @param name Resource name
 113    * @param dest Path to the new location. It includes db name and new resource name
 114    * @param overwrite true if previously existed resource at dest path can be overwritten
 115    * @return status
 116    * @throws DBException
 117    */
 118  6 public static int copy(Collection col, String name, String dest, boolean overwrite) throws DBException {
 119   
 120  6 Location destLocation = new Location(dest);
 121  6 Collection destCollection = destLocation.getCollection();
 122  6 String destName = destLocation.getName();
 123   
 124  6 if (destLocation.isRoot()) {
 125    // resource cannot be added to root directly, database has to be created manually
 126  0 return WebdavStatus.SC_FORBIDDEN;
 127  6 } else if (destCollection == null) {
 128  2 return WebdavStatus.SC_CONFLICT;
 129  4 } else if (col == destCollection && name.equals(destName)) {
 130  0 return WebdavStatus.SC_FORBIDDEN;
 131    }
 132   
 133    // get source
 134  4 Entry object = col.getEntry(name);
 135  4 if (object == null) {
 136  0 return WebdavStatus.SC_NOT_FOUND;
 137    }
 138   
 139  4 int status;
 140  4 try {
 141  4 if (object.getEntryType() == Entry.BINARY) { // insert Binary
 142  0 if (overwrite) {
 143  0 if (destCollection.setBinary(new Key(destName), (byte[]) object.getValue())) {
 144  0 status = WebdavStatus.SC_CREATED;
 145    } else {
 146  0 status = WebdavStatus.SC_NO_CONTENT;
 147    }
 148    } else {
 149  0 destCollection.insertBinary(destName, (byte[]) object.getValue());
 150  0 status = WebdavStatus.SC_CREATED;
 151    }
 152  4 } else if (object.getEntryType() == Entry.DOCUMENT) {
 153  4 if (overwrite) {
 154  2 if (destCollection.setDocument(new Key(destName), (Document) object.getValue())) {
 155  2 status = WebdavStatus.SC_CREATED;
 156    } else {
 157  0 status = WebdavStatus.SC_NO_CONTENT;
 158    }
 159    } else {
 160  2 destCollection.insertDocument(destName, (Document) object.getValue());
 161  0 status = WebdavStatus.SC_CREATED;
 162    }
 163    } else {
 164    // placeholder, won't get here
 165  0 status = WebdavStatus.SC_FORBIDDEN;
 166    }
 167    } catch (DBException e) {
 168  2 if (e.faultCode == FaultCodes.COL_DUPLICATE_RESOURCE) {
 169  2 status = WebdavStatus.SC_PRECONDITION_FAILED;
 170  0 } else if (e.faultCode == FaultCodes.COL_NO_FILER) {
 171  0 status = WebdavStatus.SC_FORBIDDEN;
 172  0 } else if (e.faultCode == FaultCodes.COL_COLLECTION_NOT_FOUND) {
 173  0 status = WebdavStatus.SC_CONFLICT;
 174  0 } else if (e.faultCode == FaultCodes.COL_CANNOT_STORE) {
 175  0 if (log.isDebugEnabled()) {
 176  0 log.debug("Collection Inline Metadata is not enabled!");
 177    }
 178  0 status = WebdavStatus.SC_FORBIDDEN;
 179    } else {
 180  0 throw e;
 181    }
 182    }
 183   
 184  4 return status;
 185    }
 186   
 187  3 private static Map copyCollection(Collection col, Collection parent, String name, boolean deep)
 188    throws DBException {
 189   
 190  3 Configuration config = CollectionConfigurationHelper.copyConfiguration(name, col.getConfig());
 191  3 Collection newCol = parent.createCollection(name, config);
 192   
 193  3 if (deep) {
 194  2 return copyCollectionContent(col, newCol);
 195    } else {
 196  1 return Collections.EMPTY_MAP;
 197    }
 198    }
 199   
 200  4 private static Map copyCollectionContent(Collection srcCol, Collection destCol) throws DBException {
 201  4 HashMap result = new HashMap();
 202   
 203    // copy resources
 204  4 String[] resList = srcCol.listDocuments();
 205  4 for (int i = 0; i < resList.length; i++) {
 206  200 Entry object = srcCol.getEntry(resList[i]);
 207  200 if (object.getEntryType() == Entry.DOCUMENT) {
 208  200 destCol.setDocument(resList[i], (Document) object.getValue());
 209    } else {
 210  0 destCol.setBinary(resList[i], (byte[]) object.getValue());
 211    }
 212    }
 213   
 214    // copy child collections content collections
 215    /* From the specification:
 216    If an error occurs while copying an internal collection, the server MUST NOT
 217    copy any resources identified by members of this collection (i.e., the server
 218    must skip this subtree), as this would create an inconsistent namespace.
 219    After detecting an error, the COPY operation SHOULD try to finish as much
 220    of the original copy operation as possible (i.e., the server should still
 221    attempt to copy other subtrees and their members, that are not descendents
 222    of an error-causing collection).
 223    */
 224  4 String[] colList = srcCol.listCollections();
 225  4 for (int i = 0; i < colList.length; i++) {
 226  2 Collection srcChild = srcCol.getCollection(colList[i]);
 227  2 Collection destChild = destCol.getCollection(colList[i]);
 228  2 try {
 229  2 result.putAll(copyCollectionContent(srcChild, destChild));
 230    } catch (DBException e) {
 231  0 int code;
 232  0 if (e.faultCode == FaultCodes.COL_NO_FILER) {
 233  0 code = WebdavStatus.SC_FORBIDDEN;
 234  0 } else if (e.faultCode == FaultCodes.COL_COLLECTION_NOT_FOUND) {
 235  0 code = WebdavStatus.SC_CONFLICT;
 236  0 } else if (e.faultCode == FaultCodes.COL_CANNOT_STORE) {
 237  0 if (log.isDebugEnabled()) {
 238  0 log.debug("Collection Inline Metadata is not enabled!");
 239    }
 240  0 code = WebdavStatus.SC_FORBIDDEN;
 241    } else {
 242  0 throw e;
 243    }
 244   
 245  0 result.put(destChild.getCanonicalName(), new Integer(code));
 246    }
 247    }
 248   
 249  4 return result;
 250    }
 251    }