Clover coverage report - Code Coverage for tapestry release 3.1-alpha-1
Coverage timestamp: Mon Feb 21 2005 09:16:14 EST
file stats: LOC: 283   Methods: 9
NCLOC: 183   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
SerializableAdaptor.java 91.3% 96.8% 100% 95.3%
coverage coverage
 1   
 // Copyright 2004, 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 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   
 /**
 32   
  *  The most complicated of the adaptors, this one takes an arbitrary serializable
 33   
  *  object, serializes it to binary, and encodes it in a Base64 encoding.
 34   
  *
 35   
  *  <p>Encoding and decoding of Base64 strings uses code adapted from work in the public
 36   
  *  domain originally written by Jonathan Knudsen and published in
 37   
  *  O'reilly's "Java Cryptography". Note that we use a <em>modified</em> form of Base64 encoding,
 38   
  *  with URL-safe characters to encode the 62 and 63 values and the pad character.
 39   
  *
 40   
  *  <p>TBD:  Work out some class loader issues involved in deserializing.
 41   
  *
 42   
  *  @author Howard Lewis Ship
 43   
  * 
 44   
  **/
 45   
 
 46   
 class SerializableAdaptor implements ISqueezeAdaptor
 47   
 {
 48   
     private static final String PREFIX = "O";
 49   
 
 50   
     /**
 51   
      *  The PAD character, appended to the end of the string to make things
 52   
      *  line up.  In normal Base64, this is the character '='.
 53   
      *
 54   
      **/
 55   
 
 56   
     private static final char PAD = '.';
 57   
 
 58   
     /**
 59   
      *  Representation for the 6-bit code 63, normally '+' in Base64.
 60   
      *
 61   
      **/
 62   
 
 63   
     private static final char CH_62 = '-';
 64   
 
 65   
     /**
 66   
      *  Representation for the 6-bit code 64, normally '/' in Base64.
 67   
      *
 68   
      **/
 69   
 
 70   
     private static final char CH_63 = '_';
 71   
 
 72  1
     public String squeeze(DataSqueezer squeezer, Object data) throws IOException
 73   
     {
 74  1
         ByteArrayOutputStream bos = null;
 75  1
         GZIPOutputStream gos = null;
 76  1
         ObjectOutputStream oos = null;
 77  1
         byte[] byteData = null;
 78   
 
 79  1
         try
 80   
         {
 81  1
             bos = new ByteArrayOutputStream();
 82  1
             gos = new GZIPOutputStream(bos);
 83  1
             oos = new ObjectOutputStream(gos);
 84   
 
 85  1
             oos.writeObject(data);
 86  1
             oos.close();
 87   
         }
 88   
         finally
 89   
         {
 90  1
             close(oos);
 91  1
             close(gos);
 92  1
             close(bos);
 93   
         }
 94   
 
 95  1
         byteData = bos.toByteArray();
 96   
 
 97  1
         StringBuffer encoded = new StringBuffer(2 * byteData.length);
 98  1
         char[] base64 = new char[4];
 99   
 
 100  1
         encoded.append(PREFIX);
 101   
 
 102  1
         for (int i = 0; i < byteData.length; i += 3)
 103   
         {
 104  170
             encodeBlock(byteData, i, base64);
 105  170
             encoded.append(base64);
 106   
         }
 107   
 
 108  1
         return encoded.toString();
 109   
     }
 110   
 
 111  3
     private void close(OutputStream stream)
 112   
     {
 113  3
         if (stream != null)
 114   
         {
 115  3
             try
 116   
             {
 117  3
                 stream.close();
 118   
             }
 119   
             catch (IOException ex)
 120   
             {
 121   
                 // Ignore.
 122   
             }
 123   
         }
 124   
     }
 125   
 
 126  3
     private void close(InputStream stream)
 127   
     {
 128  3
         if (stream != null)
 129   
         {
 130  3
             try
 131   
             {
 132  3
                 stream.close();
 133   
             }
 134   
             catch (IOException ex)
 135   
             {
 136   
                 // Ignore.
 137   
             }
 138   
         }
 139   
     }
 140  1
     public Object unsqueeze(DataSqueezer squeezer, String string) throws IOException
 141   
     {
 142  1
         ByteArrayInputStream bis = null;
 143  1
         GZIPInputStream gis = null;
 144  1
         ObjectInputStream ois = null;
 145  1
         byte[] byteData;
 146   
 
 147   
         // Strip off the first character and decode the rest.
 148   
 
 149  1
         byteData = decode(string.substring(1));
 150   
 
 151  1
         try
 152   
         {
 153  1
             bis = new ByteArrayInputStream(byteData);
 154  1
             gis = new GZIPInputStream(bis);
 155  1
             ois = new ResolvingObjectInputStream(squeezer.getResolver(), gis);
 156   
 
 157  1
             return ois.readObject();
 158   
         }
 159   
         catch (ClassNotFoundException ex)
 160   
         {
 161   
             // The message is the name of the class.
 162   
 
 163  0
             throw new IOException(
 164   
                 Tapestry.format("SerializableAdaptor.class-not-found", ex.getMessage()));
 165   
         }
 166   
         finally
 167   
         {
 168  1
             close(ois);
 169  1
             close(gis);
 170  1
             close(bis);
 171   
         }
 172   
     }
 173   
 
 174  43
     public void register(DataSqueezer squeezer)
 175   
     {
 176  43
         squeezer.register(PREFIX, Serializable.class, this);
 177   
     }
 178   
 
 179  170
     private static void encodeBlock(byte[] raw, int offset, char[] base64) throws IOException
 180   
     {
 181  170
         int block = 0;
 182  170
         int slack = raw.length - offset - 1;
 183  170
         int end = (slack >= 2) ? 2 : slack;
 184   
 
 185  170
         for (int i = 0; i <= end; i++)
 186   
         {
 187  508
             byte b = raw[offset + i];
 188  508
             int neuter = (b < 0) ? b + 256 : b;
 189  508
             block += neuter << (8 * (2 - i));
 190   
         }
 191   
 
 192  170
         for (int i = 0; i < 4; i++)
 193   
         {
 194  680
             int sixbit = (block >>> (6 * (3 - i))) & 0x3f;
 195  680
             base64[i] = getChar(sixbit);
 196   
         }
 197   
 
 198  170
         if (slack < 1)
 199  1
             base64[2] = PAD;
 200   
 
 201  170
         if (slack < 2)
 202  1
             base64[3] = PAD;
 203   
     }
 204   
 
 205  680
     protected static char getChar(int sixBit) throws IOException
 206   
     {
 207  680
         if (sixBit >= 0 && sixBit <= 25)
 208  290
             return (char) ('A' + sixBit);
 209   
 
 210  390
         if (sixBit >= 26 && sixBit <= 51)
 211  262
             return (char) ('a' + (sixBit - 26));
 212   
 
 213  128
         if (sixBit >= 52 && sixBit <= 61)
 214  105
             return (char) ('0' + (sixBit - 52));
 215   
 
 216  23
         if (sixBit == 62)
 217  12
             return CH_62;
 218   
 
 219  11
         if (sixBit == 63)
 220  11
             return CH_63;
 221   
 
 222  0
         throw new IOException(
 223   
             Tapestry.format("SerializableAdaptor.unable-to-convert", Integer.toString(sixBit)));
 224   
     }
 225   
 
 226  1
     public static byte[] decode(String string) throws IOException
 227   
     {
 228  1
         int pad = 0;
 229  1
         char[] base64 = string.toCharArray();
 230   
 
 231  1
         for (int i = base64.length - 1; base64[i] == PAD; i--)
 232  2
             pad++;
 233   
 
 234  1
         int length = base64.length * 6 / 8 - pad;
 235  1
         byte[] raw = new byte[length];
 236  1
         int rawIndex = 0;
 237   
 
 238  1
         for (int i = 0; i < base64.length; i += 4)
 239   
         {
 240  170
             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  170
             for (int j = 0; j < 3 && rawIndex + j < raw.length; j++)
 247  508
                 raw[rawIndex + j] = (byte) ((block >> (8 * (2 - j))) & 0xff);
 248   
 
 249  170
             rawIndex += 3;
 250   
         }
 251   
 
 252  1
         return raw;
 253   
     }
 254   
 
 255  680
     private static int getValue(char c) throws IOException
 256   
     {
 257  680
         if (c >= 'A' && c <= 'Z')
 258  288
             return c - 'A';
 259   
 
 260  392
         if (c >= 'a' && c <= 'z')
 261  262
             return c - 'a' + 26;
 262   
 
 263  130
         if (c >= '0' && c <= '9')
 264  105
             return c - '0' + 52;
 265   
 
 266  25
         if (c == CH_62)
 267  12
             return 62;
 268   
 
 269  13
         if (c == CH_63)
 270  11
             return 63;
 271   
 
 272   
         // Pad character
 273   
 
 274  2
         if (c == PAD)
 275  2
             return 0;
 276   
 
 277  0
         throw new IOException(
 278   
             Tapestry.format(
 279   
                 "SerializableAdaptor.unable-to-interpret-char",
 280   
                 new String(new char[] { c })));
 281   
     }
 282   
 
 283   
 }