/*
** Module   : InMemoryClassLoader.java
** Abstract : in-memory class loader
**
** Copyright (c) 2009, Golden Code Development Corporation.
**
** -#- -I- --Date-- -----------------------Description------------------------
** 001 GES 20090302 Provides an in-memory class loader.
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.goldencode.compile;

import java.util.*;

/**
 * This class extends <code>ClassLoader</code> to enable the loading of
 * a class file stored as a byte array in memory.  When a class file is
 * generated by the compiler, it should be stored under its fully qualified
 * class name using {@link #register}.
 */
public class InMemoryClassLoader
extends ClassLoader
{
   /** Stores in-memory classes loaded by this instance. */ 
   private Map<String, Class<?>> loaded = new HashMap<String, Class<?>>();
   
   /**
    * Convert the given class data into a loaded class object and store it
    * under the given fully qualified class name. Subsequent calls to
    * {@link #findClass} will match this class when given this same name.
    *
    * @param    name
    *           Fully qualified class name (includes package and any inner
    *           class extensions) in proper Java Language Specification format.
    *           If this is <code>null</code>, then the class will be loaded
    *           (if possible) but it cannot be stored for subsequent find
    *           processing.
    * @param    clazz
    *           The binary form of the class file format that properly encodes
    *           the class to be loaded.
    *
    * @return   The previously loaded class of the given name or the newly
    *           loaded class if no such class was previously loaded.
    *
    * @throws   ClassFormatException
    *           If the given class data is not in the correct format.
    */
   public synchronized Class<?> register(String name, byte[] clazz)
   {
      Class<?> result = loaded.get(name);
      
      if (result == null)
      {
         result = defineClass(name, clazz, 0, clazz.length);
         loaded.put(name, result);
      }
      
      return result;
   }
   
   /**
    * Search the previously loaded/registered classes of this instance for
    * the given named class and return it if found.
    *
    * @param    name
    *           Fully qualified class name (includes package and any inner
    *           class extensions) in proper Java Language Specification format.
    *           Must not be <code>null</code>.
    *
    * @return   The class.
    *
    * @throws   ClassNotFoundException
    *           If the given class name cannot be found by this instance.
    */
   public synchronized Class<?> findClass(String name)
   throws ClassNotFoundException
   {
      Class<?> result = loaded.get(name);
      
      if (result == null)
      {
         throw new ClassNotFoundException(name);
      }
      
      return result;
   }
}
