package com.hundsun.jresplus.web.cache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.http.Cookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 页面镜像,用于描述响应的页面信息,该页面镜像做为存储到缓存中的值,同时从缓存中读取后用于还原响应过程
* @author XIE
*
*/
public class PageImage implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(PageImage.class);
private static final int FOUR_KB = 4196;
private static final int GZIP_MAGIC_NUMBER_BYTE_1 = 31;
private static final int GZIP_MAGIC_NUMBER_BYTE_2 = -117;
private final ArrayList<PageHeader<? extends Serializable>> headers = new ArrayList<PageHeader<? extends Serializable>>();
private final ArrayList<PageCookie> cookies = new ArrayList<PageCookie>();
private String contentType;
private byte[] gzippedBody;
private byte[] ungzippedBody;
private String snippet;
private int statusCode;
private boolean storeGzipped;
private Date created;
private int timeToLiveSeconds;
private int timeToDleSeconds;
public PageImage(int statusCode, String contentType,
Collection<Cookie> cookies,
Collection<PageHeader<? extends Serializable>> headers,
byte[] body, boolean storeGzipped) {
init(statusCode, contentType, headers, cookies, body, storeGzipped);
}
public PageImage(String snippet) {
this.snippet = snippet;
}
public String getSnippet() {
return snippet;
}
public void setSnippet(String snippet) {
this.snippet = snippet;
}
public int getTimeToLiveSeconds() {
return timeToLiveSeconds;
}
public int getTimeToDleSeconds() {
return timeToDleSeconds;
}
public void setTimeToDleSeconds(int timeToDleSeconds) {
this.timeToDleSeconds = timeToDleSeconds;
}
public void setTimeToLiveSeconds(int timeToLiveSeconds) {
this.timeToLiveSeconds = timeToLiveSeconds;
}
private void init(int statusCode, String contentType,
Collection<PageHeader<? extends Serializable>> headers,
Collection<Cookie> cookies, byte[] body, boolean storeGzipped) {
if (headers != null) {
this.headers.addAll(headers);
}
this.created = new Date();
this.contentType = contentType;
this.storeGzipped = storeGzipped;
this.statusCode = statusCode;
try {
if (storeGzipped) {
this.ungzippedBody = null;
if (isBodyParameterGzipped())
this.gzippedBody = body;
else
this.gzippedBody = gzip(body);
} else {
if (isBodyParameterGzipped()) {
throw new IllegalArgumentException(
"Non gzip content has been gzipped.");
}
this.ungzippedBody = body;
}
} catch (IOException e) {
LOG.error("Error ungzipping gzipped body", e);
}
}
private byte[] gzip(byte[] ungzipped) throws IOException {
if (isGzipped(ungzipped)) {
return ungzipped;
}
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(bytes);
gzipOutputStream.write(ungzipped);
gzipOutputStream.close();
return bytes.toByteArray();
}
private boolean isBodyParameterGzipped() {
for (PageHeader<? extends Serializable> header : this.headers) {
if ("gzip".equals(header.getValue())) {
return true;
}
}
return false;
}
public static boolean isGzipped(byte[] candidate) {
if ((candidate == null) || (candidate.length < 2)) {
return false;
}
return (candidate[0] == GZIP_MAGIC_NUMBER_BYTE_1)
&& (candidate[1] == GZIP_MAGIC_NUMBER_BYTE_2);
}
public String getContentType() {
return this.contentType;
}
public byte[] getGzippedBody() {
if (this.storeGzipped) {
return this.gzippedBody;
}
return null;
}
public List<PageHeader<? extends Serializable>> getHeaders() {
return this.headers;
}
public List<PageCookie> getCookies() {
return this.cookies;
}
public int getStatusCode() {
return this.statusCode;
}
public byte[] getUngzippedBody() throws IOException {
if (this.storeGzipped) {
return ungzip(this.gzippedBody);
}
return this.ungzippedBody;
}
private byte[] ungzip(byte[] gzipped) throws IOException {
GZIPInputStream inputStream = new GZIPInputStream(
new ByteArrayInputStream(gzipped));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(
gzipped.length);
byte[] buffer = new byte[FOUR_KB];
int bytesRead = 0;
while (bytesRead != -1) {
bytesRead = inputStream.read(buffer, 0, FOUR_KB);
if (bytesRead != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
}
}
byte[] ungzipped = byteArrayOutputStream.toByteArray();
inputStream.close();
byteArrayOutputStream.close();
return ungzipped;
}
public boolean hasGzippedBody() {
return this.gzippedBody != null;
}
public boolean hasUngzippedBody() {
return this.ungzippedBody != null;
}
public boolean isOk() {
return this.statusCode == 200;
}
public Date getCreated() {
return this.created;
}
}