001/* 
002    Licensed to the Apache Software Foundation (ASF) under one
003    or more contributor license agreements.  See the NOTICE file
004    distributed with this work for additional information
005    regarding copyright ownership.  The ASF licenses this file
006    to you under the Apache License, Version 2.0 (the
007    "License"); you may not use this file except in compliance
008    with the License.  You may obtain a copy of the License at
009
010       http://www.apache.org/licenses/LICENSE-2.0
011
012    Unless required by applicable law or agreed to in writing,
013    software distributed under the License is distributed on an
014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015    KIND, either express or implied.  See the License for the
016    specific language governing permissions and limitations
017    under the License.  
018 */
019package org.apache.wiki.util;
020
021import java.io.ByteArrayInputStream;
022import java.io.ByteArrayOutputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.ObjectInputStream;
026import java.io.ObjectOutputStream;
027import java.io.Serializable;
028import java.util.HashMap;
029import java.util.Map;
030
031import org.apache.commons.codec.binary.Base64;
032
033/**
034 *  Provides static helper functions for serializing different objects.
035 *  
036 *  @since 2.8
037 */
038public final class Serializer
039{
040    /**
041     * Prefix used to indicated that a serialized item was encoded with Base64.
042     */
043    protected static final String BASE64_PREFIX = "base64 ";
044
045    /**
046     *  Prevent instantiation.
047     */
048    private Serializer()
049    {}
050    
051    /**
052     * Deserializes a Base64-encoded String into a HashMap. Both the keys and values
053     * must implement {@link java.io.Serializable}.
054     * @param rawString the String contents containing the map to be deserialized
055     * @return the attributes, parsed into a Map
056     * @throws IOException if the contents cannot be parsed for any reason
057     */
058    @SuppressWarnings("unchecked")
059    public static Map<String,? extends Serializable> deserializeFromBase64( String rawString ) throws IOException
060    {
061        // Decode from Base64-encoded String to byte array
062        byte[] decodedBytes = Base64.decodeBase64( rawString.getBytes("UTF-8") );
063        
064        // Deserialize from the input stream to the Map
065        InputStream bytesIn = new ByteArrayInputStream( decodedBytes );
066        ObjectInputStream in = new ObjectInputStream( bytesIn );
067        HashMap<String,Serializable> attributes;
068        try
069        {
070            attributes = (HashMap<String,Serializable>)in.readObject();
071        }
072        catch ( ClassNotFoundException e )
073        {
074            throw new IOException( "Could not deserialiaze user profile attributes. Reason: " + e.getMessage() );
075        }
076        finally
077        {
078            in.close();
079        }
080        return attributes;
081    }
082
083    /**
084     * Serializes a Map and formats it into a Base64-encoded String. For ease of serialization, the Map contents
085     * are first copied into a HashMap, then serialized into a byte array that is encoded as a Base64 String.
086     * @param map the Map to serialize
087     * @return a String representing the serialized form of the Map
088     * @throws IOException If serialization cannot be done
089     */
090    public static String serializeToBase64( Map<String,Serializable> map ) throws IOException
091    {
092        // Load the Map contents into a defensive HashMap
093        HashMap<String,Serializable> serialMap = new HashMap<String,Serializable>();
094        serialMap.putAll( map );
095        
096        // Serialize the Map to an output stream
097        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
098        ObjectOutputStream out = new ObjectOutputStream( bytesOut );
099        out.writeObject( serialMap );
100        out.close();
101        
102        // Transform to Base64-encoded String
103        byte[] result = Base64.encodeBase64( bytesOut.toByteArray() );
104        return new String( result ) ;
105    }
106
107}