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.nio.charset.StandardCharsets;
029import java.util.Base64;
030import java.util.HashMap;
031import java.util.Map;
032
033
034/**
035 *  Provides static helper functions for serializing different objects.
036 *  
037 *  @since 2.8
038 */
039public final class Serializer
040{
041    /**
042     * Prefix used to indicated that a serialized item was encoded with Base64.
043     */
044    static final String BASE64_PREFIX = "base64 ";
045
046    /**
047     *  Prevent instantiation.
048     */
049    private Serializer()
050    {}
051    
052    /**
053     * Deserializes a Base64-encoded String into a HashMap. Both the keys and values
054     * must implement {@link java.io.Serializable}.
055     * @param rawString the String contents containing the map to be deserialized
056     * @return the attributes, parsed into a Map
057     * @throws IOException if the contents cannot be parsed for any reason
058     */
059    @SuppressWarnings("unchecked")
060    public static Map< String, ? extends Serializable > deserializeFromBase64(final String rawString ) throws IOException {
061        // Decode from Base64-encoded String to byte array
062        final byte[] decodedBytes = Base64.getDecoder().decode( rawString.getBytes( StandardCharsets.UTF_8 ) );
063        
064        // Deserialize from the input stream to the Map
065        final InputStream bytesIn = new ByteArrayInputStream( decodedBytes );
066        try(final ObjectInputStream in = new ObjectInputStream( bytesIn ) ) {
067            return ( HashMap< String, Serializable > )in.readObject();
068        } catch ( final ClassNotFoundException e ) {
069            throw new IOException( "Could not deserialiaze user profile attributes. Reason: " + e.getMessage() );
070        }
071    }
072
073    /**
074     * Serializes a Map and formats it into a Base64-encoded String. For ease of serialization, the Map contents
075     * are first copied into a HashMap, then serialized into a byte array that is encoded as a Base64 String.
076     * @param map the Map to serialize
077     * @return a String representing the serialized form of the Map
078     * @throws IOException If serialization cannot be done
079     */
080    public static String serializeToBase64(final Map< String, Serializable > map ) throws IOException {
081        // Load the Map contents into a defensive HashMap
082        final Map<String, Serializable> serialMap = new HashMap<>(map);
083        
084        // Serialize the Map to an output stream
085        final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
086        final ObjectOutputStream out = new ObjectOutputStream( bytesOut );
087        out.writeObject( serialMap );
088        out.close();
089        
090        // Transform to Base64-encoded String
091        final byte[] result = Base64.getEncoder().encode( bytesOut.toByteArray() );
092        return new String( result ) ;
093    }
094
095}