view src/cachingfilter/FileHandler.java @ 21:aba8ed4c8a06

semiprivate
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 13 Jun 2020 22:30:48 -0600
parents 7ecd1a4ef557
children
line wrap: on
line source

package cachingfilter;

import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import javax.servlet.ServletOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
import org.eclipse.jetty.server.AbstractHttpConnection;


public abstract class FileHandler {
	abstract void close();
	abstract InputStream getInputStream();
	abstract void writeTo(ServletOutputStream out) throws IOException;

	public interface Factory {
		public FileHandler newInstance(File file) throws IOException;
	}

	private static final Logger logger = LoggerFactory.getLogger(FileHandler.class);

	private static abstract class BufferedFactory implements Factory {
		abstract DirectNIOBuffer getDirectNIOBuffer(File file) throws IOException;

		public FileHandler newInstance(File file) throws IOException {
			final DirectNIOBuffer fileBuffer = getDirectNIOBuffer(file);

			return new FileHandler() {

				void close() {}

				InputStream getInputStream() {
					return new BufferInputStream(fileBuffer);
				}

				void writeTo(ServletOutputStream out) throws IOException {
					if (out instanceof AbstractHttpConnection.Output) {
						logger.trace("sendFileContent using AbstractHttpConnection.Output");
						((AbstractHttpConnection.Output)out).sendContent(fileBuffer);
					} else {
						fileBuffer.writeTo(out);
					}
				}
			};
		}
	}

	public static final Factory mappedFile = new BufferedFactory() {

		private MappedByteBuffer map(File file) throws IOException {
			FileInputStream fis = new FileInputStream(file);
			try {
				return fis.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
			} finally {
				fis.close();
			}
		}

		DirectNIOBuffer getDirectNIOBuffer(File file) throws IOException {
			return new DirectNIOBuffer(map(file),true);
		}

	};

	public static final Factory memFile = new BufferedFactory() {

		DirectNIOBuffer getDirectNIOBuffer(File file) throws IOException {
			int len = (int)file.length();
			DirectNIOBuffer buffer = new DirectNIOBuffer(len);
			InputStream is = new FileInputStream(file);
			buffer.readFrom(is,len);
			is.close();
			return buffer;
		}

	};

	public static final Factory ioFile = new Factory() {

		public FileHandler newInstance(File file) throws IOException {
			final InputStream in = new BufferedInputStream(new FileInputStream(file));

			return new FileHandler() {

				void close() {
					try {
						in.close();
					} catch(IOException e) {
						logger.error("",e);
					}
				}

				InputStream getInputStream() {
					return in;
				}

				void writeTo(ServletOutputStream out) throws IOException {
					byte[] a = new byte[8192];
					while(true) {
						int n;
						try {
							n = in.read(a);
						} catch(IOException e) {
							throw new RuntimeException(e);
						}
						if( n == -1 )
							break;
						out.write(a,0,n);
					}
				}
			};
		}

	};

	public static final Factory mappedOrIoFile = new Factory() {

		public FileHandler newInstance(File file) throws IOException {
			try {
				return mappedFile.newInstance(file);
			} catch(IOException e) {
				if( !"Operation not permitted".equals(e.getMessage()) )
					throw e;
				logger.warn("couldn't map "+file+" length="+file.length(),e);
				return ioFile.newInstance(file);
			}
		}

	};

	public static Factory factory = mappedFile;  // change for other implementations
}