/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included with this distribution in
 * the docs/licenses/apache-1.1.txt file.
 */
package org.jboss.axis.attachments;

import org.jboss.logging.Logger;

import javax.activation.DataSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileNotFoundException;

/**
 * This class allows small attachments to be cached in memory.
 *
 * @author Thomas.Diesler@jboss.org
 */
public class ManagedMemoryDataSource implements DataSource
{
   private static Logger log = Logger.getLogger(ManagedMemoryDataSource.class);

   /** Field contentType */
   protected String contentType = "application/octet-stream";    // Is the default.

   // The memory cache
   private byte[] contentData;

   // The file cache
   private File cacheFile;

   // Memory is allocated in these size chunks.

   /** Field READ_CHUNK_SZ */
   public static final int READ_CHUNK_SZ = 32 * 1024;

   /** Field READ_CHUNK_SZ */
   public static final int MAX_MEMORY_SZ = 64 * 1024;

   /** Create a new in memory data source
    *
    * @param inputStream is the source input stream that is used to create this data source..
    * @param contentType the mime type for this data stream
    */
   public ManagedMemoryDataSource(InputStream inputStream, String contentType) throws IOException
   {
      if (contentType != null)
         this.contentType = contentType;

      ByteArrayOutputStream baos = new ByteArrayOutputStream(READ_CHUNK_SZ);
      OutputStream os = baos;

      byte[] bytes = new byte[READ_CHUNK_SZ];
      int read = inputStream.read(bytes);
      while (read > 0)
      {
         os.write(bytes, 0, read);

         if (baos != null && baos.size() > MAX_MEMORY_SZ)
         {
            // Create a cache file
            cacheFile = File.createTempFile("attachment", ".dat");
            cacheFile.deleteOnExit();

            log.debug("Created cache file: " + cacheFile.toURL());
            os = new FileOutputStream(cacheFile);
            os.write(baos.toByteArray());
            baos = null;
         }

         read = inputStream.read(bytes);
      }
      os.flush();
      os.close();

      if (baos != null)
      {
         log.debug("Using in memory cache: " + baos.size());
         this.contentData = baos.toByteArray();
      }
   }

   public String getContentType()
   {
      return contentType;
   }

   public InputStream getInputStream() throws IOException
   {
      if (contentData != null)
         return new ByteArrayInputStream(contentData);
      else if (cacheFile != null)
         return new TempFileInputStream(cacheFile);
      else
         throw new IllegalStateException("No cache available");
   }

   public String getName()
   {
      return null;
   }

   public OutputStream getOutputStream() throws IOException
   {
      return null;
   }


   /** Delete the cache file when the InputStream is closed
    * [TDI] 21-Apr-2005
    */
   class TempFileInputStream extends FileInputStream
   {
      public TempFileInputStream(File file) throws FileNotFoundException
      {
         super(file);
      }

      public void close() throws IOException
      {
         super.close();
         if (cacheFile != null)
         {
            cacheFile.delete();
            cacheFile = null;
         }
      }
   }
}