1 15 package org.apache.tapestry.util.io; 16 17 import java.io.ByteArrayInputStream ; 18 import java.io.ByteArrayOutputStream ; 19 import java.io.IOException ; 20 import java.io.InputStream ; 21 import java.io.ObjectInputStream ; 22 import java.io.ObjectOutputStream ; 23 import java.io.OutputStream ; 24 import java.io.Serializable ; 25 import java.util.zip.GZIPInputStream ; 26 import java.util.zip.GZIPOutputStream ; 27 28 import org.apache.tapestry.Tapestry; 29 import org.apache.tapestry.services.DataSqueezer; 30 31 45 46 class SerializableAdaptor implements ISqueezeAdaptor 47 { 48 private static final String PREFIX = "O"; 49 50 55 56 private static final char PAD = '.'; 57 58 62 63 private static final char CH_62 = '-'; 64 65 69 70 private static final char CH_63 = '_'; 71 72 public String squeeze(DataSqueezer squeezer, Object data) throws IOException 73 { 74 ByteArrayOutputStream bos = null; 75 GZIPOutputStream gos = null; 76 ObjectOutputStream oos = null; 77 byte[] byteData = null; 78 79 try 80 { 81 bos = new ByteArrayOutputStream (); 82 gos = new GZIPOutputStream (bos); 83 oos = new ObjectOutputStream (gos); 84 85 oos.writeObject(data); 86 oos.close(); 87 } 88 finally 89 { 90 close(oos); 91 close(gos); 92 close(bos); 93 } 94 95 byteData = bos.toByteArray(); 96 97 StringBuffer encoded = new StringBuffer (2 * byteData.length); 98 char[] base64 = new char[4]; 99 100 encoded.append(PREFIX); 101 102 for (int i = 0; i < byteData.length; i += 3) 103 { 104 encodeBlock(byteData, i, base64); 105 encoded.append(base64); 106 } 107 108 return encoded.toString(); 109 } 110 111 private void close(OutputStream stream) 112 { 113 if (stream != null) 114 { 115 try 116 { 117 stream.close(); 118 } 119 catch (IOException ex) 120 { 121 } 123 } 124 } 125 126 private void close(InputStream stream) 127 { 128 if (stream != null) 129 { 130 try 131 { 132 stream.close(); 133 } 134 catch (IOException ex) 135 { 136 } 138 } 139 } 140 public Object unsqueeze(DataSqueezer squeezer, String string) throws IOException 141 { 142 ByteArrayInputStream bis = null; 143 GZIPInputStream gis = null; 144 ObjectInputStream ois = null; 145 byte[] byteData; 146 147 149 byteData = decode(string.substring(1)); 150 151 try 152 { 153 bis = new ByteArrayInputStream (byteData); 154 gis = new GZIPInputStream (bis); 155 ois = new ResolvingObjectInputStream(squeezer.getResolver(), gis); 156 157 return ois.readObject(); 158 } 159 catch (ClassNotFoundException ex) 160 { 161 163 throw new IOException ( 164 Tapestry.format("SerializableAdaptor.class-not-found", ex.getMessage())); 165 } 166 finally 167 { 168 close(ois); 169 close(gis); 170 close(bis); 171 } 172 } 173 174 public void register(DataSqueezer squeezer) 175 { 176 squeezer.register(PREFIX, Serializable .class, this); 177 } 178 179 private static void encodeBlock(byte[] raw, int offset, char[] base64) throws IOException 180 { 181 int block = 0; 182 int slack = raw.length - offset - 1; 183 int end = (slack >= 2) ? 2 : slack; 184 185 for (int i = 0; i <= end; i++) 186 { 187 byte b = raw[offset + i]; 188 int neuter = (b < 0) ? b + 256 : b; 189 block += neuter << (8 * (2 - i)); 190 } 191 192 for (int i = 0; i < 4; i++) 193 { 194 int sixbit = (block >>> (6 * (3 - i))) & 0x3f; 195 base64[i] = getChar(sixbit); 196 } 197 198 if (slack < 1) 199 base64[2] = PAD; 200 201 if (slack < 2) 202 base64[3] = PAD; 203 } 204 205 protected static char getChar(int sixBit) throws IOException 206 { 207 if (sixBit >= 0 && sixBit <= 25) 208 return (char) ('A' + sixBit); 209 210 if (sixBit >= 26 && sixBit <= 51) 211 return (char) ('a' + (sixBit - 26)); 212 213 if (sixBit >= 52 && sixBit <= 61) 214 return (char) ('0' + (sixBit - 52)); 215 216 if (sixBit == 62) 217 return CH_62; 218 219 if (sixBit == 63) 220 return CH_63; 221 222 throw new IOException ( 223 Tapestry.format("SerializableAdaptor.unable-to-convert", Integer.toString(sixBit))); 224 } 225 226 public static byte[] decode(String string) throws IOException 227 { 228 int pad = 0; 229 char[] base64 = string.toCharArray(); 230 231 for (int i = base64.length - 1; base64[i] == PAD; i--) 232 pad++; 233 234 int length = base64.length * 6 / 8 - pad; 235 byte[] raw = new byte[length]; 236 int rawIndex = 0; 237 238 for (int i = 0; i < base64.length; i += 4) 239 { 240 int block = 241 (getValue(base64[i]) << 18) 242 + (getValue(base64[i + 1]) << 12) 243 + (getValue(base64[i + 2]) << 6) 244 + (getValue(base64[i + 3])); 245 246 for (int j = 0; j < 3 && rawIndex + j < raw.length; j++) 247 raw[rawIndex + j] = (byte) ((block >> (8 * (2 - j))) & 0xff); 248 249 rawIndex += 3; 250 } 251 252 return raw; 253 } 254 255 private static int getValue(char c) throws IOException 256 { 257 if (c >= 'A' && c <= 'Z') 258 return c - 'A'; 259 260 if (c >= 'a' && c <= 'z') 261 return c - 'a' + 26; 262 263 if (c >= '0' && c <= '9') 264 return c - '0' + 52; 265 266 if (c == CH_62) 267 return 62; 268 269 if (c == CH_63) 270 return 63; 271 272 274 if (c == PAD) 275 return 0; 276 277 throw new IOException ( 278 Tapestry.format( 279 "SerializableAdaptor.unable-to-interpret-char", 280 new String (new char[] { c }))); 281 } 282 283 } | Popular Tags |