Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 301   Methods: 27
NCLOC: 223   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
FSFiler.java 52.9% 73% 77.8% 69.6%
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: FSFiler.java 541516 2007-05-25 02:46:51Z vgritsenko $
 18    */
 19   
 20    package org.apache.xindice.core.filer;
 21   
 22    import org.apache.xindice.core.DBException;
 23    import org.apache.xindice.core.FaultCodes;
 24    import org.apache.xindice.core.data.Key;
 25    import org.apache.xindice.core.data.Record;
 26    import org.apache.xindice.core.data.RecordSet;
 27    import org.apache.xindice.core.data.Value;
 28    import org.apache.xindice.util.Configuration;
 29    import org.apache.xindice.util.FileCache;
 30    import org.apache.xindice.util.LockManager;
 31    import org.apache.xindice.util.SimpleConfigurable;
 32    import org.apache.xindice.util.XindiceException;
 33   
 34    import java.io.File;
 35    import java.io.FileFilter;
 36    import java.io.FileOutputStream;
 37    import java.io.IOException;
 38    import java.util.HashMap;
 39    import java.util.HashSet;
 40    import java.util.Set;
 41    import java.util.StringTokenizer;
 42   
 43    /**
 44    * FSFiler allows you to use existing file systems withing Xindice.
 45    *
 46    * @version $Revision: 541516 $, $Date: 2007-05-24 19:46:51 -0700 (Thu, 24 May 2007) $
 47    */
 48    public final class FSFiler extends SimpleConfigurable implements Filer {
 49   
 50    // private static final Log log = LogFactory.getLog(FSFiler.class);
 51   
 52    private static final String LOCATION = "location";
 53    private static final String EXT = "ext";
 54    private static final String READONLY = "readonly";
 55   
 56    private FileCache cache = new FileCache();
 57    private LockManager locks = new LockManager(16);
 58   
 59    private Set extensions;
 60   
 61    private String location;
 62    private File dir;
 63    private boolean opened;
 64    private boolean readOnly;
 65   
 66   
 67  19 public FSFiler() {
 68    }
 69   
 70  19 public String getName() {
 71  19 return "FSFiler";
 72    }
 73   
 74  19 public void setLocation(File root, String location) {
 75    }
 76   
 77  19 public void setConfig(Configuration config) throws XindiceException {
 78  19 super.setConfig(config);
 79  19 location = config.getAttribute(LOCATION);
 80  19 readOnly = config.getBooleanAttribute(READONLY, readOnly);
 81  19 String exts = config.getAttribute(EXT);
 82  19 if (exts != null && exts.trim().length() > 0) {
 83  0 extensions = new HashSet();
 84  0 StringTokenizer st = new StringTokenizer(exts);
 85  0 while (st.hasMoreTokens()) {
 86  0 extensions.add(st.nextToken());
 87    }
 88    }
 89  19 dir = new File(location);
 90  19 opened = false;
 91    }
 92   
 93  6056 private void checkOpened() throws DBException {
 94  6057 if (!opened) {
 95  0 throw new FilerException(FaultCodes.COL_COLLECTION_CLOSED,
 96    "Filer is closed");
 97    }
 98    }
 99   
 100  4027 private void checkReadOnly() throws DBException {
 101  4027 if (readOnly) {
 102  0 throw new FilerException(FaultCodes.COL_COLLECTION_READ_ONLY,
 103    "Filer is read-only");
 104    }
 105    }
 106   
 107  19 public boolean close() {
 108  19 opened = false;
 109  19 return true;
 110    }
 111   
 112  19 public boolean open() {
 113  19 opened = (dir.exists() && dir.isDirectory());
 114  19 return opened;
 115    }
 116   
 117  0 public boolean drop() {
 118  0 opened = false;
 119  0 return true;
 120    }
 121   
 122  0 public boolean isOpened() {
 123  0 return opened;
 124    }
 125   
 126  19 public boolean exists() {
 127  19 return dir.exists();
 128    }
 129   
 130  0 public boolean create() {
 131  0 if (!dir.exists()) {
 132  0 return dir.mkdirs();
 133    } else {
 134  0 return true;
 135    }
 136    }
 137   
 138  1 public void flush() {
 139    }
 140   
 141  0 public Record readRecord(Key key) throws DBException {
 142  0 return readRecord(key, false);
 143    }
 144   
 145  1963 public Record readRecord(Key key, boolean metaOnly) throws DBException {
 146  1963 if (key == null || key.getLength() == 0) {
 147  2 return null;
 148    }
 149   
 150  1961 checkOpened();
 151   
 152  1961 String fname = key.toString();
 153  1961 if (!isExtensionValid(fname)) {
 154  0 return null;
 155    }
 156   
 157  1961 File file = new File(dir, fname);
 158  1961 try {
 159  1961 locks.acquireSharedLock(file);
 160   
 161  1961 HashMap meta = new HashMap(2, 1.5F);
 162  1961 meta.put(Record.MODIFIED, new Long(file.lastModified()));
 163   
 164  1961 if (metaOnly && file.exists()) {
 165  0 return new Record(key, null, meta);
 166    } else {
 167  1961 byte[] valueData = cache.getFile(file);
 168  1961 if (valueData != null) {
 169  1958 return new Record(key, new Value(valueData), meta);
 170    }
 171    }
 172    } catch (IOException e) {
 173  0 throw new FilerException(FaultCodes.DBE_CANNOT_READ,
 174    "Can't read record '" + key + "': " + e.getMessage(), e);
 175    } finally {
 176  1961 locks.releaseSharedLock(file);
 177    }
 178  3 return null;
 179    }
 180   
 181  3020 public Record writeRecord(Key key, Value value) throws DBException {
 182  3020 if (key == null || key.getLength() == 0) {
 183  2 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid key: '" + key + "'");
 184    }
 185  3018 if (value == null) {
 186  1 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid null value");
 187    }
 188   
 189  3016 checkOpened();
 190  3016 checkReadOnly();
 191   
 192  3017 String fname = key.toString();
 193  3017 if (!isExtensionValid(fname)) {
 194  0 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid extention");
 195    }
 196   
 197  3017 File file = new File(dir, fname);
 198  3016 try {
 199  3016 locks.acquireExclusiveLock(file);
 200  3017 FileOutputStream fos = new FileOutputStream(file);
 201  3017 value.streamTo(fos);
 202  3013 fos.close();
 203   
 204  3017 HashMap meta = new HashMap(2);
 205  3017 meta.put(Record.MODIFIED, new Long(file.lastModified()));
 206   
 207  3016 return new Record(key, value, meta);
 208    } catch (IOException e) {
 209  0 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE,
 210    "Can't write record '" + key + "': " + e.getMessage(), e);
 211    } finally {
 212  3017 locks.releaseExclusiveLock(file);
 213    }
 214    }
 215   
 216  1012 public boolean deleteRecord(Key key) throws DBException {
 217  1012 if (key == null || key.getLength() == 0) {
 218  2 return false;
 219    }
 220  1010 checkOpened();
 221  1010 checkReadOnly();
 222   
 223  1010 String fname = key.toString();
 224  1010 if (!isExtensionValid(fname)) {
 225  0 return false;
 226    }
 227   
 228  1010 File file = new File(dir, fname);
 229  1010 try {
 230  1010 locks.acquireExclusiveLock(file);
 231    // TODO: Should Exception (SecurityException) be catched here or not?
 232  1010 return file.delete();
 233    } finally {
 234  1010 locks.releaseExclusiveLock(file);
 235    }
 236    }
 237   
 238  46 public long getRecordCount() throws DBException {
 239  46 checkOpened();
 240   
 241  46 File[] files = dir.listFiles(new FileFilter() {
 242  2974 public boolean accept(File file) {
 243  2974 return file.isFile() && isExtensionValid(file.getName());
 244    }
 245    });
 246  46 return files.length;
 247    }
 248   
 249  23 public RecordSet getRecordSet() throws DBException {
 250  23 checkOpened();
 251  23 return new FSRecordSet();
 252    }
 253   
 254  8966 private boolean isExtensionValid(String fname) {
 255  8966 if (extensions != null) {
 256  0 int idx = fname.lastIndexOf('.');
 257  0 if (idx == -1) {
 258  0 return false;
 259    }
 260  0 String ext = fname.substring(idx + 1);
 261  0 if (!extensions.contains(ext)) {
 262  0 return false;
 263    }
 264    }
 265  8966 return true;
 266    }
 267   
 268    /**
 269    * FSRecordSet
 270    */
 271   
 272    private class FSRecordSet implements RecordSet {
 273    public File[] files;
 274    public int pos = 0;
 275   
 276  23 public FSRecordSet() {
 277  23 files = dir.listFiles(new FileFilter() {
 278  4 public boolean accept(File file) {
 279  4 return file.isFile() && isExtensionValid(file.getName());
 280    }
 281    });
 282    }
 283   
 284  26 public synchronized boolean hasMoreRecords() {
 285  26 return pos < files.length;
 286    }
 287   
 288  4 public synchronized Record getNextRecord() throws DBException {
 289  4 File file = files[pos++];
 290  4 return readRecord(new Key(file.getName()), false);
 291    }
 292   
 293  0 public synchronized Value getNextValue() throws DBException {
 294  0 return getNextRecord().getValue();
 295    }
 296   
 297  0 public synchronized Key getNextKey() {
 298  0 return new Key(files[pos++].getName());
 299    }
 300    }
 301    }