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 }