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 org.apache.commons.codec.binary.Base64; 018 import org.apache.hivemind.ApplicationRuntimeException; 019 import org.apache.hivemind.ClassResolver; 020 import org.apache.tapestry.services.DataSqueezer; 021 022 import java.io.*; 023 import java.util.zip.GZIPInputStream; 024 import java.util.zip.GZIPOutputStream; 025 026 /** 027 * The most complicated of the adaptors, this one takes an arbitrary serializable object, serializes 028 * it to binary (possibly compressing the stream along the way), and encodes it in a Base64 029 * encoding. The first character of the squeezed stream indicates whether it is or is not encoded. 030 * 031 * @author Howard Lewis Ship 032 */ 033 034 public class SerializableAdaptor implements SqueezeAdaptor 035 { 036 private static final char BYTESTREAM_PREFIX = 'O'; 037 038 private static final char GZIP_BYTESTREAM_PREFIX = 'Z'; 039 040 // O is for an object stream rendered as MIME 041 // Z is for on object stream, compressed, rendered as MIME 042 043 private static final String PREFIX = "OZ"; 044 045 private ClassResolver _resolver; 046 047 public String getPrefix() 048 { 049 return PREFIX; 050 } 051 052 public Class getDataClass() 053 { 054 return Serializable.class; 055 } 056 057 public String squeeze(DataSqueezer squeezer, Object data) 058 { 059 try 060 { 061 ByteArrayOutputStream bosPlain = new ByteArrayOutputStream(); 062 ByteArrayOutputStream bosCompressed = new ByteArrayOutputStream(); 063 064 GZIPOutputStream gos = new GZIPOutputStream(bosCompressed); 065 066 TeeOutputStream tos = new TeeOutputStream(bosPlain, gos); 067 068 ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(tos)); 069 070 oos.writeObject(data); 071 072 oos.close(); 073 074 boolean useCompressed = bosCompressed.size() < bosPlain.size(); 075 076 byte[] byteArray = useCompressed ? bosCompressed.toByteArray() : bosPlain.toByteArray(); 077 078 byte[] encoded = Base64.encodeBase64(byteArray); 079 080 String prefix = Character.toString(useCompressed ? GZIP_BYTESTREAM_PREFIX : BYTESTREAM_PREFIX); 081 082 return prefix + new String(encoded); 083 } 084 catch (Exception ex) 085 { 086 throw new ApplicationRuntimeException(IoMessages.encodeFailure(data, ex), ex); 087 } 088 } 089 090 public Object unsqueeze(DataSqueezer squeezer, String encoded) 091 { 092 char prefix = encoded.charAt(0); 093 094 try 095 { 096 // Strip off the prefix, feed that in as a MIME stream. 097 098 byte[] mimeData = encoded.substring(1).getBytes(); 099 100 byte[] decoded = Base64.decodeBase64(mimeData); 101 102 InputStream is = new ByteArrayInputStream(decoded); 103 104 if (prefix == GZIP_BYTESTREAM_PREFIX) 105 is = new GZIPInputStream(is); 106 107 is = new BufferedInputStream(is); 108 109 ObjectInputStream ois = new ResolvingObjectInputStream(_resolver, is); 110 111 Object result = ois.readObject(); 112 113 ois.close(); 114 115 return result; 116 } 117 catch (Exception ex) 118 { 119 throw new ApplicationRuntimeException(IoMessages.decodeFailure(ex), ex); 120 } 121 } 122 123 public void setResolver(ClassResolver resolver) 124 { 125 _resolver = resolver; 126 } 127 128 }