package org.riotfamily.cachius.http.content;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.riotfamily.cachius.CacheContext;
import org.riotfamily.cachius.http.support.IOUtils;
public class ChunkedContent implements Content {
private File file;
private List<Chunk> chunks = new LinkedList<Chunk>();
private transient int lastEnd = -1;
public ChunkedContent(File file) {
this.file = file;
}
public void addFragment(int start, int end, ContentFragment fragment) {
int gap = start - (lastEnd + 1);
if (gap > 0) {
chunks.add(new Chunk(gap));
}
chunks.add(new FragmentChunk(end - start + 1, fragment));
lastEnd = end;
}
public void addTail() {
int gap = ((int) file.length()) - (lastEnd + 1);
if (gap > 0) {
chunks.add(new Chunk(gap));
}
}
public int getLength(HttpServletRequest request, HttpServletResponse response) {
int length = 0;
if (chunks != null) {
for (Chunk chunk : chunks) {
int chunkLength = chunk.getLength(request, response);
if (chunkLength < 0) {
return -1;
}
length += chunkLength;
}
}
return length;
}
public void serve(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Reader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(file), "UTF-8"));
try {
if (chunks != null) {
for (Chunk chunk : chunks) {
chunk.serve(reader, request, response);
}
}
}
finally {
IOUtils.closeReader(reader);
}
}
public void delete() {
file.delete();
}
private static class Chunk implements Serializable {
protected int length;
public Chunk(int length) {
this.length = length;
}
public int getLength(HttpServletRequest request, HttpServletResponse response) {
return length;
}
public void serve(Reader reader, HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
IOUtils.copy(reader, response.getWriter(), length);
}
}
private class FragmentChunk extends Chunk {
private ContentFragment fragment;
public FragmentChunk(int length, ContentFragment fragment) {
super(length);
this.fragment = fragment;
}
@Override
public int getLength(HttpServletRequest request,
HttpServletResponse response) {
return fragment.getLength(request, response);
}
@Override
public void serve(Reader reader, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (CacheContext.exists()) {
IOUtils.copy(reader, response.getWriter(), length);
}
else {
reader.skip(length);
fragment.serve(request, response);
}
}
}
}