
/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jcs.yajcache.file;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jcs.yajcache.annotate.*;
import org.apache.commons.lang.builder.*;


/**
 * Cache File Data Access Object.
 *
 * @author Hanson Char
 */
@CopyRightApache
public enum CacheFileDAO {
    inst;

    private volatile int countWriteIOException;
    private volatile int countWriteCloseException;
    private volatile int countReadIOException;
    private volatile int countReadCloseException;
    private volatile int countCorruptMinLength;
    private volatile int countCorruptLength;
    private volatile int countCorruptInvalid;
    
    private Log log = LogFactory.getLog(this.getClass());
    
    /**
     * Writes the specified cache item into the file system.
     *
     * @return true if successful; false otherwise.
     */
    public boolean writeCacheItem(
            @NonNullable String cacheName, @NonNullable CacheFileContentType type, 
            @NonNullable String key, @NonNullable byte[] val)
    {
        File file = CacheFileUtils.inst.getCacheFile(cacheName, key);
        RandomAccessFile raf = null;
        try {
            file.delete();
            file.createNewFile();
            raf = new RandomAccessFile(file, "rw");
            CacheFileContent.getInstance(type, val).write(raf);
            return true;
        } catch(IOException ex) {
            countWriteIOException++;
            log.error("", ex);
        } finally {
            if (raf != null) {
                try {
                    raf.close();
                } catch(Exception ex) {
                    countWriteCloseException++;
                    log.error("", ex);
                }
            }
        }
        return false;
    }
    /**
     * Reads the byte array of a specified cache item from the file system.
     * 
     * @return the byte array of a specified cache item from the file system;
     * or null if it can't.
     */
    public byte[] readCacheItem(@NonNullable String cacheName, @NonNullable String key) 
    {
        File file = CacheFileUtils.inst.getCacheFile(cacheName, key);
        
        if (!file.exists())
            return null;
        final long fileSize = file.length();
        
        if (fileSize <= CacheFileContent.MIN_FILE_LENGTH) {
            countCorruptMinLength++;
            log.warn("Corrupted file which failed the minimum length condition for cacheName=" 
                    + cacheName + " key=" + key);
            return null;
        }
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(file, "r");
            CacheFileContent cfc = CacheFileContent.getInstance(raf);
            
            if (cfc.isValid()) {
                final int contentLength = (int)fileSize - CacheFileContent.MIN_FILE_LENGTH;
                
                if (contentLength != cfc.getContentLength()) {
                    countCorruptLength++;
                    log.warn("Corrupted file with unexpected content length for cacheName=" 
                            + cacheName + " key=" + key);
                    return null;
                }
            }
            else
            {
                countCorruptInvalid++;
                log.warn("Corrupted file for cacheName=" + cacheName 
                        + " key=" + key);
                return null;
            }
            return cfc.getContent();
        } catch(IOException ex) {
            countReadIOException++;
            log.warn("", ex);
        } finally {
            if (raf != null) {
                try {
                    raf.close();
                } catch(Exception ex) {
                    countReadCloseException++;
                    log.error("", ex);
                }
            }
        }
        return null;
    }
    /**
     * Removes the specified cache item from the file system.
     *
     * @return true if successful; false otherwise.
     */
    public boolean removeCacheItem(@NonNullable String cacheName, @NonNullable String key)
    {
        File file = CacheFileUtils.inst.getCacheFile(cacheName, key);
        return file.delete();
    }

    @Override 
    public @NonNullable String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

@@ -739,33 +739,8 @@
 le;%0A
-import java.util.Arrays;%0A
 impo
@@ -855,16 +855,23 @@
 che.
+lang.
 annotat
-e
+ion
 .*;%0A
@@ -982,16 +982,19 @@
 har%0A */%0A
+// 
 @CopyRig
@@ -1002,16 +1002,72 @@
 tApache%0A
+// http://www.netbeans.org/issues/show_bug.cgi?id=53704%0A
 public e
@@ -2745,13 +2745,80 @@
  it 
-can't
+doesn't exist;%0A     * or CacheFileContent.CORRUPTED if file is corrupted
 .%0A  
@@ -2834,22 +2834,32 @@
  public 
-byte%5B%5D
+CacheFileContent
  readCac
@@ -3368,36 +3368,58 @@
          return 
-null
+CacheFileContent.CORRUPTED
 ;%0A        %7D%0A    
@@ -4016,36 +4016,58 @@
          return 
-null
+CacheFileContent.CORRUPTED
 ;%0A              
@@ -4281,36 +4281,58 @@
          return 
-null
+CacheFileContent.CORRUPTED
 ;%0A            %7D%0A
@@ -4357,21 +4357,8 @@
  cfc
-.getContent()
 ;%0A  
@@ -4365,32 +4365,188 @@
       %7D catch(IO
+Exception ex) %7B%0A            countReadIOException++;%0A            log.warn(ex.getClass().getName(), ex);%0A        %7D catch(org.apache.commons.lang.Serialization
 Exception ex) %7B%0A
@@ -4602,26 +4602,46 @@
 og.warn(
-%22%22
+ex.getClass().getName()
 , ex);%0A
- 
        %7D
@@ -4916,28 +4916,50 @@
      return 
-null
+CacheFileContent.CORRUPTED
 ;%0A    %7D%0A    

handle corrutped file content