Clover coverage report -
Coverage timestamp: Sun Nov 16 2008 23:05:30 GMT
file stats: LOC: 696   Methods: 28
NCLOC: 411   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
CollectionImpl.java 64.7% 66.8% 89.3% 68.4%
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: CollectionImpl.java 643240 2008-04-01 01:53:39Z natalia $
 18    */
 19   
 20    package org.apache.xindice.client.xmldb.embed;
 21   
 22    import org.apache.xindice.client.xmldb.ResourceSetImpl;
 23    import org.apache.xindice.client.xmldb.XindiceCollection;
 24    import org.apache.xindice.client.xmldb.resources.BinaryResourceImpl;
 25    import org.apache.xindice.client.xmldb.resources.XMLResourceImpl;
 26    import org.apache.xindice.core.Collection;
 27    import org.apache.xindice.core.DBException;
 28    import org.apache.xindice.core.Database;
 29    import org.apache.xindice.core.FaultCodes;
 30    import org.apache.xindice.core.data.Entry;
 31    import org.apache.xindice.core.data.NodeSet;
 32    import org.apache.xindice.core.meta.MetaData;
 33    import org.apache.xindice.core.query.QueryUtil;
 34    import org.apache.xindice.util.Configuration;
 35    import org.apache.xindice.xml.TextWriter;
 36    import org.apache.xindice.xml.dom.DocumentImpl;
 37    import org.w3c.dom.Document;
 38    import org.w3c.dom.Element;
 39    import org.w3c.dom.Node;
 40    import org.xmldb.api.base.ErrorCodes;
 41    import org.xmldb.api.base.Resource;
 42    import org.xmldb.api.base.ResourceSet;
 43    import org.xmldb.api.base.XMLDBException;
 44    import org.xmldb.api.modules.BinaryResource;
 45    import org.xmldb.api.modules.XMLResource;
 46   
 47    import java.util.Hashtable;
 48    import java.util.StringTokenizer;
 49   
 50    /**
 51    * Implementation of XML:DB's <code>Collection</code> interface using
 52    * direct access to interact with database server
 53    *
 54    * @author <a href="mailto:james.bates@amplexor.com">James Bates</a>
 55    * @author <a href="mailto:kstaken@xmldatabases.org">Kimbro Staken</a>
 56    * @version $Revision: 643240 $, $Date: 2008-04-01 01:53:39 +0000 (Tue, 01 Apr 2008) $
 57    */
 58    public class CollectionImpl extends XindiceCollection {
 59   
 60    private Database db;
 61    private Collection col;
 62   
 63    /**
 64    * Creates new <code>CollectionImpl</code> instance representing connection
 65    * to server collection.
 66    *
 67    * @param db Database this collection resides in
 68    * @param collPath Canonical path of this collection (including database name)
 69    * @exception XMLDBException thrown if a connection could not be established,
 70    * because of URL syntax errors, or connection failure, or if no
 71    * collection with path <code>collPath</code> could be located.
 72    */
 73  1127 public CollectionImpl(Database db, String collPath) throws XMLDBException {
 74  1127 super(collPath);
 75  1127 this.db = db;
 76   
 77    // Extract path of the collection within database
 78  1127 String collName = "/";
 79  1127 int colIndex = collPath.indexOf('/', 1);
 80  1127 if (colIndex != -1) {
 81  1122 collName = collPath.substring(colIndex);
 82  1122 if (collName.equals("")) {
 83  0 collName = "/";
 84    }
 85    }
 86   
 87  1127 try {
 88  1127 this.col = db.getCollection(collName);
 89    } catch (Exception e) {
 90  0 throw FaultCodes.createXMLDBException(ErrorCodes.INVALID_COLLECTION,
 91    "Collection not available: " + collPath, e);
 92    }
 93   
 94  1127 if (this.col == null) {
 95  1 throw new XMLDBException(ErrorCodes.NO_SUCH_COLLECTION,
 96    "Collection not found: " + collPath);
 97    }
 98    }
 99   
 100    /**
 101    * Retrieves a <code>Resource</code> from the database. If the
 102    * <code>Resource</code> could not be
 103    * located a null value will be returned.
 104    *
 105    * @param id the unique id for the requested resource.
 106    * @return The retrieved <code>Resource</code> instance.
 107    * @exception XMLDBException with expected error codes.<br />
 108    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 109    * specific errors that occur.<br />
 110    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 111    * method has been called on the <code>Collection</code><br />
 112    */
 113  175 public Resource getResource(String id) throws XMLDBException {
 114   
 115  175 checkOpen();
 116  175 try {
 117  175 Entry entry = col.getEntry(id);
 118  175 if (entry == null) {
 119  7 return null;
 120    }
 121   
 122  168 switch (entry.getEntryType()) {
 123  166 case Entry.DOCUMENT:
 124  166 DocumentImpl doc = (DocumentImpl) entry.getValue();
 125   
 126    // This should probably just pass the document.
 127  166 if (doc.getDataBytes() == null) {
 128  166 return new XMLResourceImpl(id, id, this, TextWriter.toString(doc));
 129    } else {
 130  0 return new XMLResourceImpl(id, id, this, doc.getSymbols(), doc.getDataBytes());
 131    }
 132   
 133  2 case Entry.BINARY:
 134  2 return new BinaryResourceImpl(id, this, (byte[]) entry.getValue());
 135   
 136  0 default:
 137  0 throw new XMLDBException(ErrorCodes.UNKNOWN_RESOURCE_TYPE,
 138    "Internal error: Unexpected resource type " + entry.getEntryType());
 139    }
 140   
 141    } catch (Exception e) {
 142  0 throw FaultCodes.createXMLDBException("Resource not available: " + id, e);
 143    }
 144    }
 145   
 146    /**
 147    * Returns the number of resources currently stored in this collection or 0
 148    * if the collection is empty.
 149    *
 150    * @return the number of resource in the collection.
 151    * @exception XMLDBException with expected error codes.<br />
 152    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 153    * specific errors that occur.<br />
 154    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 155    * method has been called on the <code>Collection</code><br />
 156    */
 157  21 public int getResourceCount() throws XMLDBException {
 158   
 159  21 checkOpen();
 160  21 try {
 161  21 return (int) col.getDocumentCount();
 162    } catch (Exception e) {
 163  0 throw FaultCodes.createXMLDBException(e);
 164    }
 165    }
 166   
 167    /**
 168    * Stores the provided resource into the database. If the resource does not
 169    * already exist it will be created. If it does already exist it will be
 170    * updated.
 171    *
 172    * @param res the resource to store in the database.
 173    * @exception XMLDBException with expected error codes.<br />
 174    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 175    * specific errors that occur.<br />
 176    * <code>ErrorCodes.INVALID_RESOURCE</code> if the <code>Resource</code> is
 177    * not valid..<br />
 178    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 179    * method has been called on the <code>Collection</code><br />
 180    */
 181  406 public void storeResource(Resource res) throws XMLDBException {
 182  406 if (res.getContent() == null) {
 183  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "No resource data");
 184    }
 185   
 186  406 checkOpen();
 187   
 188  406 try {
 189  406 if (res instanceof XMLResource) {
 190  402 Node content = getXMLContent(res);
 191  402 if (res.getId() != null) {
 192  402 col.setDocument(res.getId(), (Document) content);
 193    } else {
 194  0 String name = col.insertDocument((Document) content).toString();
 195  0 ((XMLResourceImpl) res).setId(name);
 196    }
 197   
 198  4 } else if (res instanceof BinaryResource) {
 199  4 byte[] bytes = getBinaryContent(res);
 200  4 if (res.getId() != null) {
 201  4 col.setBinary(res.getId(), bytes);
 202    } else {
 203  0 String name = col.insertBinary(bytes).toString();
 204  0 ((BinaryResourceImpl) res).setId(name);
 205    }
 206   
 207    } else {
 208  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
 209    "Only XMLResource and BinaryResource supported");
 210    }
 211    } catch (DBException e) {
 212  0 throw FaultCodes.createXMLDBException(e.faultCode, e.getMessage(), e);
 213    } catch (XMLDBException e) {
 214  0 throw e;
 215    } catch (Exception e) {
 216  0 throw FaultCodes.createXMLDBException(ErrorCodes.INVALID_RESOURCE,
 217    "Invalid resource: " + res.getId(), e);
 218    }
 219    }
 220   
 221    /**
 222    * Inserts the provided resource into the database.
 223    *
 224    * @param res the resource to insert.
 225    * @exception XMLDBException with expected error codes.<br />
 226    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 227    * specific errors that occur.<br />
 228    * <code>ErrorCodes.INVALID_RESOURCE</code> if the <code>Resource</code> is
 229    * not valid..<br />
 230    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 231    * method has been called on the <code>Collection</code><br />
 232    */
 233  2 public void insertResource(Resource res) throws XMLDBException {
 234  2 if (res.getContent() == null) {
 235  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "No resource data");
 236    }
 237   
 238  2 checkOpen();
 239   
 240  2 try {
 241  2 if (res instanceof BinaryResource) {
 242  0 byte[] bytes = getBinaryContent(res);
 243  0 if (res.getId() != null) {
 244  0 col.insertBinary(res.getId(), bytes);
 245    } else {
 246  0 String name = col.insertBinary(bytes).toString();
 247  0 ((BinaryResourceImpl) res).setId(name);
 248    }
 249  2 } else if (res instanceof XMLResource) {
 250  2 Node content = getXMLContent(res);
 251  2 if (res.getId() != null) {
 252  2 col.insertDocument(res.getId(), (Document) content);
 253    } else {
 254  0 String name = col.insertDocument((Document) content).toString();
 255  0 ((XMLResourceImpl) res).setId(name);
 256    }
 257   
 258    } else {
 259  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
 260    "Only XMLResource and BinaryResource supported");
 261    }
 262    } catch (DBException e) {
 263  1 throw FaultCodes.createXMLDBException(e.faultCode, e.getMessage(), e);
 264    } catch (XMLDBException e) {
 265  0 throw e;
 266    } catch (Exception e) {
 267  0 throw FaultCodes.createXMLDBException(ErrorCodes.INVALID_RESOURCE,
 268    "Invalid resource: " + res.getId(), e);
 269    }
 270    }
 271   
 272    /**
 273    * Updates the provided resource in the database.
 274    *
 275    * @param res the resource to update.
 276    * @exception XMLDBException with expected error codes.<br />
 277    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 278    * specific errors that occur.<br />
 279    * <code>ErrorCodes.INVALID_RESOURCE</code> if the <code>Resource</code> is
 280    * not valid.<br/>
 281    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 282    * method has been called on the <code>Collection</code><br />
 283    */
 284  2 public void updateResource(Resource res) throws XMLDBException {
 285  2 if (res.getContent() == null) {
 286  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "No resource data");
 287    }
 288   
 289  2 if (res.getId() == null) {
 290  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "Resource must have valid ID.");
 291    }
 292   
 293  2 checkOpen();
 294   
 295  2 try {
 296  2 if (res instanceof BinaryResource) {
 297  0 byte[] bytes = getBinaryContent(res);
 298  0 col.updateBinary(res.getId(), bytes);
 299   
 300  2 } else if (res instanceof XMLResource) {
 301  2 Node content = getXMLContent(res);
 302  2 col.updateDocument(res.getId(), (Document) content);
 303   
 304    } else {
 305  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
 306    "Only XMLResource and BinaryResource supported");
 307    }
 308    } catch (DBException e) {
 309  1 throw FaultCodes.createXMLDBException(e.faultCode, e.getMessage(), e);
 310    } catch (XMLDBException e) {
 311  0 throw e;
 312    } catch (Exception e) {
 313  0 throw FaultCodes.createXMLDBException(ErrorCodes.INVALID_RESOURCE,
 314    "Invalid resource: " + res.getId(), e);
 315    }
 316    }
 317   
 318  4 private byte[] getBinaryContent(Resource res) throws XMLDBException {
 319  4 Object content = res.getContent();
 320  4 byte[] bytes;
 321  4 if (content instanceof byte[]) {
 322  4 bytes = (byte[]) content;
 323    } else {
 324  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
 325    "The contents of a binary resource must have type byte[].");
 326    }
 327  4 return bytes;
 328    }
 329   
 330  406 private Node getXMLContent(Resource res) throws XMLDBException {
 331  406 Node content = ((XMLResourceImpl) res).getContentAsDOM();
 332  406 if (content == null || !(content instanceof Document)) {
 333  0 throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
 334    "A resource must be a document in order to be stored.");
 335    }
 336  406 return content;
 337    }
 338   
 339    /* see superclass for documentation */
 340  1598 public boolean isOpen() {
 341  1598 return (col != null);
 342    }
 343   
 344    /* see superclass for documentation */
 345  0 public String getURI() {
 346  0 return "xmldb:" + DatabaseImpl.DRIVER_NAME + "://" + getCanonicalName();
 347    }
 348   
 349    /**
 350    * Returns a <code>Collection</code> instance for the requested child collection
 351    * if it exists.
 352    *
 353    * @param name the name of the child collection to retrieve.
 354    * @return the requested child collection or null if it couldn't be found.
 355    * @exception XMLDBException with expected error codes.<br />
 356    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 357    * specific errors that occur.<br />
 358    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 359    * method has been called on the <code>Collection</code><br />
 360    */
 361  127 public org.xmldb.api.base.Collection getChildCollection(String name) throws XMLDBException {
 362   
 363  127 if (name.indexOf('/') != -1) {
 364  1 throw new XMLDBException(ErrorCodes.INVALID_COLLECTION,
 365    "Invalid collection: " + name);
 366    }
 367   
 368  126 try {
 369  126 return new CollectionImpl(db, getCanonicalName() + "/" + name);
 370    } catch (XMLDBException e) {
 371  0 if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
 372    // per getChildCollection contract, return null if not found
 373  0 return null;
 374    }
 375  0 throw e;
 376    } catch (Exception e) {
 377  0 throw FaultCodes.createXMLDBException(ErrorCodes.INVALID_COLLECTION,
 378    "Invalid collection: " + name, e);
 379    }
 380    }
 381   
 382    /**
 383    * Creates a new unique ID within the context of the <code>Collection</code>
 384    *
 385    * @return the created id as a string.
 386    * @exception XMLDBException with expected error codes.<br />
 387    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 388    * specific errors that occur.<br />
 389    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 390    * method has been called on the <code>Collection</code><br />
 391    */
 392  4 public String createId() throws XMLDBException {
 393   
 394  4 checkOpen();
 395  4 return col.createNewOID().toString();
 396    }
 397   
 398    /**
 399    * Releases all resources consumed by the <code>Collection</code>.
 400    * The <code>close</code> method must
 401    * always be called when use of a <code>Collection</code> is complete. It is
 402    * not safe to use a <code>Collection</code> after the <code>close</code>
 403    * method has been called.
 404    *
 405    * @exception XMLDBException with expected error codes.<br />
 406    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 407    * specific errors that occur.<br />
 408    */
 409  1 public void close() throws XMLDBException {
 410  1 col = null;
 411    // FIXME Should not be necessary here:
 412  1 db.flushConfig();
 413    }
 414   
 415    /**
 416    * Returns the parent collection for this collection or null if no parent
 417    * collection exists.
 418    *
 419    * @return the parent <code>Collection</code> instance.
 420    * @exception XMLDBException with expected error codes.<br />
 421    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 422    * specific errors that occur.<br />
 423    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 424    * method has been called on the <code>Collection</code><br />
 425    */
 426  4 public org.xmldb.api.base.Collection getParentCollection() throws XMLDBException {
 427   
 428    // If there's only one slash then it's the root.
 429  4 if (collPath.lastIndexOf("/") == 0) {
 430  1 return null;
 431    }
 432   
 433  3 try {
 434  3 return new CollectionImpl(db, collPath.substring(0, collPath.lastIndexOf('/')));
 435    } catch (XMLDBException e) {
 436  0 if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
 437    // per getParentCollection contract, return null if no parent
 438  0 return null;
 439    }
 440  0 throw e;
 441    }
 442    }
 443   
 444    /**
 445    * Removes the <code>Resource</code> from the database.
 446    *
 447    * @param res the resource to remove.
 448    * @exception XMLDBException with expected error codes.<br />
 449    * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
 450    * specific errors that occur.<br />
 451    * <code>ErrorCodes.INVALID_RESOURCE</code> if the <code>Resource</code> is
 452    * not valid.<br />
 453    * <code>ErrorCodes.NO_SUCH_RESOURCE</code> if the <code>Resource</code> is
 454    * not known to this <code>Collection</code>.
 455    * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
 456    * method has been called on the <code>Collection</code><br />
 457    */
 458  153 public void removeResource(Resource res) throws XMLDBException {
 459