Skip to content

Commit

Permalink
fixed issues with serializability
Browse files Browse the repository at this point in the history
  • Loading branch information
Burt Beckwith committed Apr 16, 2012
1 parent 2bddde3 commit da73d8a
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 27 deletions.
109 changes: 109 additions & 0 deletions src/java/grails/plugin/cache/SerializableByteArrayOutputStream.java
@@ -0,0 +1,109 @@
/* Copyright 2012 SpringSource.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package grails.plugin.cache;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

/**
* A Serializable version of java.io.ByteArrayOutputStream.
*
* @author Burt Beckwith
*/
public class SerializableByteArrayOutputStream extends SerializableOutputStream {

private static final long serialVersionUID = 1;

protected byte[] buf;
protected int count;

public SerializableByteArrayOutputStream() {
this(32);
}

public SerializableByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: " + size);
}
buf = new byte[size];
}

@Override
public synchronized void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = copyOf(Math.max(buf.length << 1, newcount));
}
buf[count] = (byte)b;
count = newcount;
}

@Override
public synchronized void write(byte[] b, int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}

if (len == 0) {
return;
}

int newcount = count + len;
if (newcount > buf.length) {
buf = copyOf(Math.max(buf.length << 1, newcount));
}
System.arraycopy(b, off, buf, count, len);
count = newcount;
}

public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}

public synchronized void reset() {
count = 0;
}

public synchronized byte[] toByteArray() {
return copyOf(count);
}

// ByteArrayOutputStream uses Arrays.copyOf which is only in Java 6, that's inlined here.
protected byte[] copyOf(int newLength) {
byte[] copy = new byte[newLength];
System.arraycopy(buf, 0, copy, 0, Math.min(buf.length, newLength));
return copy;
}

public synchronized int size() {
return count;
}

@Override
public synchronized String toString() {
return new String(buf, 0, count);
}

public synchronized String toString(String charsetName) throws UnsupportedEncodingException {
return new String(buf, 0, count, charsetName);
}

@Override
public void close() throws IOException {
// no-op
}
}
28 changes: 28 additions & 0 deletions src/java/grails/plugin/cache/SerializableOutputStream.java
@@ -0,0 +1,28 @@
/* Copyright 2012 SpringSource.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package grails.plugin.cache;

import java.io.OutputStream;
import java.io.Serializable;

/**
* Abstract base class for serializable OutputStream classes.
*
* @author Burt Beckwith
*/
@SuppressWarnings("serial")
public abstract class SerializableOutputStream extends OutputStream implements Serializable {
// no methods
}
11 changes: 4 additions & 7 deletions src/java/grails/plugin/cache/web/GenericResponseWrapper.java
Expand Up @@ -14,11 +14,11 @@
*/
package grails.plugin.cache.web;

import grails.plugin.cache.SerializableOutputStream;
import grails.plugin.cache.web.Header.Type;
import grails.plugin.cache.web.filter.FilterServletOutputStream;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Serializable;
Expand All @@ -34,7 +34,6 @@
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
Expand All @@ -54,22 +53,20 @@ public class GenericResponseWrapper extends HttpServletResponseWrapper implement

private static final long serialVersionUID = 1;

private final Logger log = LoggerFactory.getLogger(getClass());

private int statusCode = SC_OK;
private int contentLength;
private String contentType;
private final Map<String, List<Serializable>> headersMap = new TreeMap<String, List<Serializable>>(
String.CASE_INSENSITIVE_ORDER);
private final List<Cookie> cookies = new ArrayList<Cookie>();
private ServletOutputStream out;
private PrintWriter writer;
private transient PrintWriter writer;
private boolean disableFlushBuffer = true;

/**
* Creates a GenericResponseWrapper
*/
public GenericResponseWrapper(final HttpServletResponse response, final OutputStream outputStream) {
public GenericResponseWrapper(final HttpServletResponse response, final SerializableOutputStream outputStream) {
super(response);
out = new FilterServletOutputStream(outputStream);
}
Expand Down Expand Up @@ -128,7 +125,7 @@ public void sendRedirect(String string) throws IOException {
@Override
public void setStatus(final int code, final String msg) {
statusCode = code;
log.warn("Discarding message because this method is deprecated.");
LoggerFactory.getLogger(getClass()).warn("Discarding message because this method is deprecated.");
super.setStatus(code);
}

Expand Down
9 changes: 5 additions & 4 deletions src/java/grails/plugin/cache/web/HttpDateFormatter.java
Expand Up @@ -14,13 +14,13 @@
*/
package grails.plugin.cache.web;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
Expand Down Expand Up @@ -52,9 +52,9 @@
* @author Greg Luck
* @author Burt Beckwith
*/
public class HttpDateFormatter {
public class HttpDateFormatter implements Serializable {

protected final Logger log = LoggerFactory.getLogger(getClass());
private static final long serialVersionUID = 1;

protected final SimpleDateFormat httpDateFormat;

Expand Down Expand Up @@ -92,7 +92,8 @@ public synchronized Date parseDateFromHttpDate(String date) {
return httpDateFormat.parse(date);
}
catch (ParseException e) {
log.debug("ParseException on date {}. 1/1/1970 will be returned", date);
LoggerFactory.getLogger(getClass()).debug(
"ParseException on date {}. 1/1/1970 will be returned", date);
return new Date(0);
}
}
Expand Down
53 changes: 45 additions & 8 deletions src/java/grails/plugin/cache/web/PageInfo.java
Expand Up @@ -34,11 +34,17 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.cglib.proxy.Callback;

import org.codehaus.groovy.grails.plugins.web.api.ControllersApi;
import org.codehaus.groovy.grails.web.servlet.GrailsFlashScope;
import org.codehaus.groovy.grails.web.servlet.HttpHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.TargetSource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.FlashMap;

/**
* A Serializable representation of a {@link HttpServletResponse}.
Expand All @@ -59,12 +65,10 @@ public class PageInfo implements Serializable {
protected static final int GZIP_MAGIC_NUMBER_BYTE_2 = -117;
protected static final long ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;

private final Logger log = LoggerFactory.getLogger(getClass());

private final HttpDateFormatter httpDateFormatter = new HttpDateFormatter();
private final List<Header<? extends Serializable>> responseHeaders = new ArrayList<Header<? extends Serializable>>();
private final List<SerializableCookie> serializableCookies = new ArrayList<SerializableCookie>();
private Map<String, ? extends Serializable> requestAttributes;
private Map<String, Serializable> requestAttributes;
private String contentType;
private byte[] gzippedBody;
private byte[] ungzippedBody;
Expand All @@ -90,7 +94,7 @@ public class PageInfo implements Serializable {
public PageInfo(final int statusCode, final String contentType, final byte[] body,
boolean storeGzipped, long timeToLiveSeconds, final Collection<Header<? extends Serializable>> headers,
@SuppressWarnings("unused") final Collection<Cookie> cookies,
Map<String, ? extends Serializable> requestAttributes) throws AlreadyGzippedException {
Map<String, Serializable> requestAttributes) throws AlreadyGzippedException {

if (headers != null) {
responseHeaders.addAll(headers);
Expand All @@ -101,7 +105,8 @@ public PageInfo(final int statusCode, final String contentType, final byte[] bod
this.contentType = contentType;
this.storeGzipped = storeGzipped;
this.statusCode = statusCode;
this.requestAttributes = requestAttributes;
setCacheableRequestAttributes(requestAttributes);

// bug 2630970
// extractCookies(cookies);

Expand All @@ -122,7 +127,7 @@ public PageInfo(final int statusCode, final String contentType, final byte[] bod
}
}
catch (IOException e) {
log.error("Error ungzipping gzipped body", e);
LoggerFactory.getLogger(getClass()).error("Error ungzipping gzipped body", e);
}
}

Expand Down Expand Up @@ -306,7 +311,7 @@ public long getTimeToLiveSeconds() {
return timeToLiveSeconds;
}

public Map<String, ? extends Serializable> getRequestAttributes() {
public Map<String, Serializable> getRequestAttributes() {
return Collections.unmodifiableMap(requestAttributes);
}

Expand Down Expand Up @@ -388,4 +393,36 @@ public Map<String, Object> getCacheDirectives() {
}
return directives;
}

private void setCacheableRequestAttributes(Map<String, Serializable> attributes) {
requestAttributes = new HashMap<String, Serializable>();

for (Map.Entry<String, Serializable> entry : attributes.entrySet()) {
Serializable value = entry.getValue();

if (value instanceof GrailsFlashScope) {
continue;
}
if (value instanceof FlashMap) {
continue;
}
if (value instanceof HttpServletResponse) {
continue;
}
if (value instanceof ControllersApi) {
continue;
}
if (value instanceof PointcutAdvisor || value instanceof PointcutAdvisor[]) {
continue;
}
if (value instanceof Callback || value instanceof Callback[]) {
continue;
}
if (value instanceof TargetSource) {
continue;
}

requestAttributes.put(entry.getKey(), value);
}
}
}
Expand Up @@ -14,8 +14,10 @@
*/
package grails.plugin.cache.web.filter;

import grails.plugin.cache.SerializableOutputStream;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;

import javax.servlet.ServletOutputStream;

Expand All @@ -27,11 +29,13 @@
* @author Greg Luck
* @author Burt Beckwith
*/
public class FilterServletOutputStream extends ServletOutputStream {
public class FilterServletOutputStream extends ServletOutputStream implements Serializable {

private static final long serialVersionUID = 1;

protected OutputStream stream;
protected SerializableOutputStream stream;

public FilterServletOutputStream(final OutputStream stream) {
public FilterServletOutputStream(final SerializableOutputStream stream) {
this.stream = stream;
}

Expand Down

0 comments on commit da73d8a

Please sign in to comment.