001package org.apache.commons.jcs.utils.serialization;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.commons.jcs.engine.behavior.IElementSerializer;
023import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
024import org.apache.commons.jcs.utils.zip.CompressionUtil;
025
026import java.io.BufferedInputStream;
027import java.io.ByteArrayInputStream;
028import java.io.ByteArrayOutputStream;
029import java.io.IOException;
030import java.io.ObjectInputStream;
031import java.io.ObjectOutputStream;
032
033/**
034 * Performs default serialization and de-serialization. It gzips the value.
035 */
036public class CompressingSerializer
037    implements IElementSerializer
038{
039    /**
040     * Serializes an object using default serialization. Compresses the byte array.
041     * <p>
042     * @param obj object
043     * @return byte[]
044     * @throws IOException on i/o problem
045     */
046    @Override
047    public <T> byte[] serialize( T obj )
048        throws IOException
049    {
050        byte[] uncompressed = serializeObject( obj );
051        byte[] compressed = CompressionUtil.compressByteArray( uncompressed );
052        return compressed;
053    }
054
055    /**
056     * Does the basic serialization.
057     * <p>
058     * @param obj object
059     * @return byte[]
060     * @throws IOException on i/o problem
061     */
062    protected <T> byte[] serializeObject( T obj )
063        throws IOException
064    {
065        ByteArrayOutputStream baos = new ByteArrayOutputStream();
066        ObjectOutputStream oos = new ObjectOutputStream( baos );
067        try
068        {
069            oos.writeObject( obj );
070        }
071        finally
072        {
073            oos.close();
074        }
075        byte[] uncompressed = baos.toByteArray();
076        return uncompressed;
077    }
078
079    /**
080     * Uses default de-serialization to turn a byte array into an object. Decompresses the value
081     * first. All exceptions are converted into IOExceptions.
082     * <p>
083     * @param data bytes of data
084     * @return Object
085     * @throws IOException on i/o problem
086     * @throws ClassNotFoundException if class is not found during deserialization
087     */
088    @Override
089    public <T> T deSerialize( byte[] data, ClassLoader loader )
090        throws IOException, ClassNotFoundException
091    {
092        if ( data == null )
093        {
094            return null;
095        }
096        byte[] decompressedByteArray = CompressionUtil.decompressByteArray( data );
097        return deserializeObject( decompressedByteArray );
098    }
099
100    /**
101     * Does the standard deserialization.
102     * <p>
103     * @param decompressedByteArray array of decompressed bytes
104     * @return Object
105     * @throws IOException on i/o error
106     * @throws ClassNotFoundException if class is not found during deserialization
107     */
108    protected <T> T deserializeObject( byte[] decompressedByteArray )
109        throws IOException, ClassNotFoundException
110    {
111        ByteArrayInputStream bais = new ByteArrayInputStream( decompressedByteArray );
112        BufferedInputStream bis = new BufferedInputStream( bais );
113        ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( bis, null );
114
115        try
116        {
117            @SuppressWarnings("unchecked") // Need to cast from Object
118            T readObject = (T) ois.readObject();
119            return readObject;
120        }
121        finally
122        {
123            ois.close();
124        }
125    }
126}