/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gopivotal.manager;

import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.session.StandardSession;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * Utilities for serializing and deserializing {@link Session}s
 */
public final class SessionSerializationUtils {

    private final Manager manager;

    /**
     * Creates a new instance
     *
     * @param manager the manager to use when recreating sessions
     */
    public SessionSerializationUtils(Manager manager) {
        this.manager = manager;
    }

    /**
     * Deserialize a {@link Session}
     *
     * @param session a {@code byte[]} representing the serialized {@link Session}
     * @return the deserialized {@link Session} or {@code null} if the session data is {@code null}
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public Session deserialize(byte[] session) throws ClassNotFoundException, IOException {
        if (session == null) {
            return null;
        }

        ByteArrayInputStream bytes = null;
        ObjectInputStream in = null;

        try {
            bytes = new ByteArrayInputStream(session);
            in = new ObjectInputStream(bytes);

            StandardSession standardSession = (StandardSession) this.manager.createEmptySession();
            standardSession.readObjectData(in);

            return standardSession;
        } finally {
            closeQuietly(in, bytes);
        }
    }

    /**
     * Serialize a {@link Session}
     *
     * @param session the {@link Session} to serialize
     * @return a {@code byte[]} representing the serialized {@link Session}
     * @throws IOException
     */
    public byte[] serialize(Session session) throws IOException {
        ByteArrayOutputStream bytes = null;
        ObjectOutputStream out = null;

        try {
            bytes = new ByteArrayOutputStream();
            out = new ObjectOutputStream(bytes);

            StandardSession standardSession = (StandardSession) session;
            standardSession.writeObjectData(out);

            out.flush();
            bytes.flush();

            return bytes.toByteArray();
        } finally {
            closeQuietly(out, bytes);
        }

    }

    private void closeQuietly(Closeable... closeables) {
        for (Closeable closeable : closeables) {
            try {
                closeable.close();
            } catch (Exception e) {
                // Nothing to do
            }
        }
    }

}

@@ -646,133 +646,8 @@
 r;%0A%0A
-import org.apache.catalina.Manager;%0Aimport org.apache.catalina.Session;%0Aimport org.apache.catalina.session.StandardSession;%0A%0A
 impo
@@ -671,32 +671,32 @@
 rayInputStream;%0A
+
 import java.io.B
@@ -839,16 +839,175 @@
 tStream;
+%0Aimport java.io.ObjectStreamClass;%0A%0Aimport org.apache.catalina.Manager;%0Aimport org.apache.catalina.Session;%0Aimport org.apache.catalina.session.StandardSession;
 %0A%0A/**%0A *
@@ -2024,32 +2024,491 @@
 putStream(bytes)
+ %7B%0A                @Override%0A                protected Class%3C?%3E resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException %7B%0A                    try %7B%0A                        return Class.forName(desc.getName(), false, Thread.currentThread().getContextClassLoader());%0A                    %7D catch (ClassNotFoundException cnfe) %7B%0A                        return super.resolveClass(desc);%0A                    %7D%0A                %7D%0A            %7D
 ;%0A%0A            S
@@ -3776,17 +3776,16 @@
       %7D%0A
+
     %7D%0A
-%0A
 %7D%0A

Use current Thread classloader deserialization