package de.renew.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

import org.apache.log4j.Logger;

import de.renew.plugin.PluginManager;

/**
 * Use the {@link de.renew.plugin.BottomClassLoader} to resolve
 * the class loaded from the ObjectInputStream.
 * <p>
 * Without this class, the loaded Object will be resolved using
 * the first class loader up the execution stack, which is
 * unreliable for Renew. We need to ensure that all external
 * classes are loaded with a class loader that knows all class
 * instances currently present in the runtime.
 */
public class ObjectInputStreamUsingBottomLoader extends ObjectInputStream {

    /**
     * the class-wide all-instances logger for this Class 
     */
    public final static Logger logger = Logger.getLogger(ObjectInputStreamUsingBottomLoader.class);

    /**
     * Instantiate a regular {@link ObjectInputStream}. The
     * {@link de.renew.plugin.BottomClassLoader} will be used to resolve
     * the loaded object's class.
     * @param in a regular {@link InputStream}
     * @throws IOException if an I/O error occurs while reading stream header
     */
    public ObjectInputStreamUsingBottomLoader(InputStream in) throws IOException {
        super(in);
    }

    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc)
        throws IOException, ClassNotFoundException
    {
        try {
            return Class
                .forName(desc.getName(), true, PluginManager.getInstance().getBottomClassLoader());
        } catch (ClassNotFoundException e) {
            logger.warn(
                "Using ObjectInputStream's default class loader to resolve " + desc.getName()
                    + ".");
            logger.warn(
                "Please make sure the class you are trying to load is known to the class loader "
                    + "of a module, the " + de.renew.plugin.PluginClassLoader.class.getSimpleName()
                    + ", or" + "the " + de.renew.plugin.BottomClassLoader.class.getSimpleName()
                    + ".");
            return super.resolveClass(desc);
        }
    }
}
