001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.util.io;
016
017 import java.io.BufferedInputStream;
018 import java.io.BufferedOutputStream;
019 import java.io.ByteArrayInputStream;
020 import java.io.ByteArrayOutputStream;
021 import java.io.InputStream;
022 import java.io.ObjectInputStream;
023 import java.io.ObjectOutputStream;
024 import java.io.Serializable;
025 import java.util.zip.GZIPInputStream;
026 import java.util.zip.GZIPOutputStream;
027
028 import org.apache.commons.codec.binary.Base64;
029 import org.apache.hivemind.ApplicationRuntimeException;
030 import org.apache.hivemind.ClassResolver;
031 import org.apache.tapestry.services.DataSqueezer;
032
033 /**
034 * The most complicated of the adaptors, this one takes an arbitrary serializable object, serializes
035 * it to binary (possibly compressing the stream along the way), and encodes it in a Base64
036 * encoding. The first character of the squeezed stream indicates whether it is or is not encoded.
037 *
038 * @author Howard Lewis Ship
039 */
040
041 public class SerializableAdaptor implements SqueezeAdaptor
042 {
043 private ClassResolver _resolver;
044
045 private static final char BYTESTREAM_PREFIX = 'O';
046
047 private static final char GZIP_BYTESTREAM_PREFIX = 'Z';
048
049 // O is for an object stream rendered as MIME
050 // Z is for on object stream, compressed, rendered as MIME
051
052 private static final String PREFIX = "OZ";
053
054 public String getPrefix()
055 {
056 return PREFIX;
057 }
058
059 public Class getDataClass()
060 {
061 return Serializable.class;
062 }
063
064 public String squeeze(DataSqueezer squeezer, Object data)
065 {
066 try
067 {
068 ByteArrayOutputStream bosPlain = new ByteArrayOutputStream();
069 ByteArrayOutputStream bosCompressed = new ByteArrayOutputStream();
070
071 GZIPOutputStream gos = new GZIPOutputStream(bosCompressed);
072
073 TeeOutputStream tos = new TeeOutputStream(bosPlain, gos);
074
075 ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(tos));
076
077 oos.writeObject(data);
078
079 oos.close();
080
081 boolean useCompressed = bosCompressed.size() < bosPlain.size();
082
083 byte[] byteArray = useCompressed ? bosCompressed.toByteArray() : bosPlain.toByteArray();
084
085 byte[] encoded = Base64.encodeBase64(byteArray);
086
087 String prefix = Character.toString(useCompressed ? GZIP_BYTESTREAM_PREFIX
088 : BYTESTREAM_PREFIX);
089
090 return prefix + new String(encoded);
091 }
092 catch (Exception ex)
093 {
094 throw new ApplicationRuntimeException(IoMessages.encodeFailure(data, ex), ex);
095 }
096 }
097
098 public Object unsqueeze(DataSqueezer squeezer, String encoded)
099 {
100 char prefix = encoded.charAt(0);
101
102 try
103 {
104 // Strip off the prefix, feed that in as a MIME stream.
105
106 byte[] mimeData = encoded.substring(1).getBytes();
107
108 byte[] decoded = Base64.decodeBase64(mimeData);
109
110 InputStream is = new ByteArrayInputStream(decoded);
111
112 if (prefix == GZIP_BYTESTREAM_PREFIX)
113 is = new GZIPInputStream(is);
114
115 is = new BufferedInputStream(is);
116
117 ObjectInputStream ois = new ResolvingObjectInputStream(_resolver, is);
118
119 Object result = ois.readObject();
120
121 ois.close();
122
123 return result;
124 }
125 catch (Exception ex)
126 {
127 throw new ApplicationRuntimeException(IoMessages.decodeFailure(ex), ex);
128 }
129 }
130
131 public void setResolver(ClassResolver resolver)
132 {
133 _resolver = resolver;
134 }
135
136 }