package fi.internetix.smvc.controllers;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import fi.internetix.smvc.StatusCode;
import fi.internetix.smvc.dispatcher.RequestDispatchContext;
/**
* Request context for all binary requests in the application.
*/
public class BinaryRequestContext extends RequestContext {
/** Create a new binary request context.
*
* @param dispatchContext The dispatch context, passed to RequestContext constructor
* @param servletRequest The servlet request, passed to RequestContext constructor
* @param servletResponse The servlet response, passed to RequestContext constructor
* @param servletContext The servlet context, passed to RequestContext constructor
*/
public BinaryRequestContext(RequestDispatchContext dispatchContext, HttpServletRequest servletRequest, HttpServletResponse servletResponse, ServletContext servletContext) {
super(dispatchContext, servletRequest, servletResponse, servletContext);
}
/** Sets the content of the binary response, with the given MIME content type.
*
* @param content The content to send to the client.
* @param contentType The MIME type of the content to send.
*/
public void setResponseContent(byte[] content, String contentType) {
this.content = content;
this.contentType = contentType;
}
/** Sets the URL of the content.
*
* @param contentUrl The new content of the URL.
*/
public void setContentUrl(String contentUrl) {
this.contentUrl = contentUrl;
}
/** Returns the URL of the content.
*
* @return The URL of the content.
*/
public String getContentUrl() {
return contentUrl;
}
/** Sets the filename for the content.
*
* @param fileName The new filename for the content.
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
@Override
public void writePreCommitResponse(int statusCode) throws Exception {
if (getRedirectURL() != null) {
getResponse().sendRedirect(getRedirectURL());
}
}
/**
* Writes the response to the binary request.
*
* @throws Exception If writing the response fails for any reason
*/
@Override
public void writePostCommitResponse(int statusCode) throws Exception {
if (statusCode == StatusCode.OK) {
if (fileName != null) {
getResponse().setHeader("Content-Disposition", "attachment; filename=" + fileName);
}
if (contentType != null && content != null) {
getResponse().setContentType(contentType);
getResponse().getOutputStream().write(content);
} else if (!StringUtils.isBlank(contentUrl)) {
handleContentUrl();
}
}
else {
// TODO Error handing
switch (statusCode) {
case StatusCode.UNAUTHORIZED:
case StatusCode.NOT_LOGGED_IN:
getResponse().setStatus(403);
break;
default:
getResponse().setStatus(500);
break;
}
}
}
private void handleContentUrl() throws IOException {
String contentUrl = getContentUrl();
URL includeURL;
boolean isExternal = contentUrl.startsWith("http://")||contentUrl.startsWith("https://");
if (isExternal) {
includeURL = new URL(contentUrl);
} else {
boolean isRelative = !contentUrl.startsWith("/");
// TODO: This is not quite correct because if this request is secure it doesn't mean that include request would be
String protocol = "http";
if (getRequest().isSecure()) {
protocol = "https";
}
String serverName = getRequest().getServerName();
StringBuilder urlBuilder = new StringBuilder();
if (isRelative) {
urlBuilder
.append(getRequest().getContextPath())
.append(getRequest().getPathInfo())
.append('/')
.append(contentUrl);
} else {
urlBuilder.append(contentUrl);
}
includeURL = new URL(protocol, serverName, getRequest().getLocalPort(), urlBuilder.toString());
}
HttpURLConnection connection = (HttpURLConnection) includeURL.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
getResponse().setContentType(connection.getContentType());
OutputStream outputStream = getResponse().getOutputStream();
InputStream inputStream = connection.getInputStream();
byte[] buf = new byte[1024];
int l;
while ((l = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, l);
}
outputStream.flush();
outputStream.close();
}
private String fileName;
private byte[] content;
private String contentType;
private String contentUrl;
}