
org.ocpsoft.rewrite.servlet.config.Stream Maven / Gradle / Ivy
package org.ocpsoft.rewrite.servlet.config;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import org.ocpsoft.logging.Logger;
import org.ocpsoft.rewrite.config.ConfigurationRuleParameterBuilder;
import org.ocpsoft.rewrite.config.Operation;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.ocpsoft.rewrite.exception.RewriteException;
import org.ocpsoft.rewrite.param.ParameterStore;
import org.ocpsoft.rewrite.param.Parameterized;
import org.ocpsoft.rewrite.param.ParameterizedPattern;
import org.ocpsoft.rewrite.param.ParameterizedPatternBuilder;
import org.ocpsoft.rewrite.param.RegexParameterizedPatternBuilder;
import org.ocpsoft.rewrite.servlet.config.response.ResponseStreamWrapper;
import org.ocpsoft.rewrite.servlet.http.event.HttpServletRewrite;
import org.ocpsoft.rewrite.util.Transpositions;
/**
* An {@link Operation} responsible for streaming a {@link File} on the host file-system to the
* {@link HttpServletResponse#getOutputStream()}.
*
* @author Lincoln Baxter, III
*/
public abstract class Stream extends HttpOperation implements Parameterized
{
public static final Logger log = Logger.getLogger(Stream.class);
// TODO TEST ME!!!
public final static String STREAM_KEY = Stream.class.getName() + "_STREAM";
protected RegexParameterizedPatternBuilder target;
private Stream(File target)
{
this.target = new RegexParameterizedPatternBuilder(target.getAbsolutePath());
}
/**
* Create an {@link Operation} that streams the given {@link File} to the
* {@link HttpServletResponse#getOutputStream()}.
*
*
* The given {@link File} path may be parameterized:
*
*
* new File("/tmp/file.txt")
* new File("c:\tmp\{param}.txt")
* ...
*
*
*
* @param location {@link ParameterizedPattern} specifying the location of the {@link File}.
*
* @see {@link ConfigurationRuleParameterBuilder#where(String)}
*/
public static Stream from(File file)
{
return new Stream(file) {
@Override
public void performHttp(HttpServletRewrite event, EvaluationContext context)
{
InputStream stream = null;
try {
File file = new File(target.build(event, context, Transpositions.encodePath()));
stream = new BufferedInputStream(new FileInputStream(file));
log.debug("Streaming from file [" + file + "] to response.");
Response.write(stream).perform(event, context);
}
catch (Exception e) {
throw new RewriteException("Error streaming file.", e);
}
finally
{
if (stream != null)
try {
stream.close();
}
catch (IOException e) {
throw new RewriteException("Error closing stream.", e);
}
}
}
@Override
public String toString()
{
return "Stream.from(\"" + target.getPattern() + "\")";
}
};
}
/**
* Create an {@link Operation} that duplicates content written to {@link HttpServletResponse#getOutputStream()} and
* writes it to the given {@link File}.
*/
public static Operation to(File file)
{
return new Stream(file) {
@Override
public void performHttp(HttpServletRewrite event, EvaluationContext context)
{
final File file = new File(target.build(event, context, Transpositions.encodePath()));
if (!file.exists())
{
file.mkdirs();
file.delete();
try {
file.createNewFile();
}
catch (IOException e) {
throw new RewriteException("Could not create file for Stream operation", e);
}
}
Response.withOutputStreamWrappedBy(new ResponseStreamWrapper() {
@Override
public OutputStream wrap(HttpServletRewrite rewrite, OutputStream outputStream)
{
try {
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(file));
rewrite.getRequest().setAttribute(STREAM_KEY, stream);
log.debug("Cloning response OutputStream to file [" + file + "]");
return new MultiOutputStream(stream, outputStream);
}
catch (FileNotFoundException e) {
throw new RewriteException("Could not wrap stream", e);
}
}
@Override
public void finish(HttpServletRewrite rewrite)
{
try {
OutputStream stream = (OutputStream) rewrite.getRequest().getAttribute(STREAM_KEY);
if (stream != null)
{
log.debug("Closing cloned file [" + file + "] OutputStream");
stream.flush();
stream.close();
}
}
catch (Exception e) {
throw new RewriteException("Could not close stream", e);
}
}
}).perform(event, context);
}
@Override
public String toString()
{
return "Stream.to(\"" + target.getPattern() + "\")";
}
};
}
private static class MultiOutputStream extends OutputStream
{
private OutputStream[] streams;
public MultiOutputStream(OutputStream... streams)
{
this.streams = streams;
}
@Override
public void close() throws IOException
{
for (int i = 0; i < streams.length; i++)
streams[i].close();
}
@Override
public void flush() throws IOException
{
for (int i = 0; i < streams.length; i++)
streams[i].flush();
}
@Override
public void write(int b) throws IOException
{
for (int i = 0; i < streams.length; i++)
streams[i].write(b);
}
@Override
public void write(byte[] b) throws IOException
{
for (int i = 0; i < streams.length; i++)
streams[i].write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException
{
for (int i = 0; i < streams.length; i++)
streams[i].write(b, off, len);
}
}
@Override
public Set getRequiredParameterNames()
{
return target.getRequiredParameterNames();
}
@Override
public void setParameterStore(ParameterStore store)
{
target.setParameterStore(store);
}
public ParameterizedPatternBuilder getExpression()
{
return target;
}
}