Package org.jboss.serial.classmetamodel

Source Code of org.jboss.serial.classmetamodel.ClassMetamodelFactory

/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.serial.classmetamodel;

import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jboss.serial.util.ClassMetaConsts;
import org.jboss.serial.util.FastHashMap;
import org.jboss.serial.util.PartitionedWeakHashMap;

/**
* $Id: ClassMetamodelFactory.java 326 2006-07-28 04:57:13Z csuconic $
* @author clebert suconic
*/
public class ClassMetamodelFactory implements ClassMetaConsts
{
  private static final Logger log = Logger.getLogger(ClassMetamodelFactory.class);
     private static final boolean isDebug = log.isDebugEnabled();

    /** table mapping primitive type names to corresponding class objects.
     *  This code was created by Carlos de Wolf on a fix of EJBTHREE-440.
     *  By coincidence I needed to parse primitive values, and instead of reinventing the wheel I got the same code. */
    private static final HashMap primClasses = new HashMap(8, 1.0F);
    static {
       primClasses.put("boolean", boolean.class);
       primClasses.put("byte", byte.class);
       primClasses.put("char", char.class);
       primClasses.put("short", short.class);
       primClasses.put("int", int.class);
       primClasses.put("long", long.class);
       primClasses.put("float", float.class);
       primClasses.put("double", double.class);
       primClasses.put("void", void.class);
       primClasses.put("[Z", boolean[].class);
       primClasses.put("[B", byte[].class);
       primClasses.put("[C", char[].class);
       primClasses.put("[S", short[].class);
       primClasses.put("[I", int[].class);
       primClasses.put("[J", long[].class);
       primClasses.put("[F", float[].class);
       primClasses.put("[D", double[].class);
    }
    
    /** We are caching the getClassLoader operation, to avoid locks on the WeakHashMap */
    private static class CacheLoaderReference
    {
      WeakReference currentClassLoader;
      Map currentHashMap;
     
      public ClassLoader getCurrentClassLoader()
      {
        if (currentClassLoader==null)
          return null;
        else
          return (ClassLoader)currentClassLoader.get();
      }
     
      public void setCurrentClassLoader(ClassLoader loader)
      {
        currentClassLoader = new WeakReference(loader);
      }
     
      public Map getCurrentMap()
      {
        return currentHashMap;
      }
     
      public void setCurrentMap(Map currentMap)
      {
        this.currentHashMap = currentMap;
      }
    }
   

    /**
     * Method for ObjectStreamClass.lookup
     * */
    static Method methodLookup;

    /**
     * Method for ObjectStreamClass.getField
     */
    static Method methodGetField;


    /** The HashMap for SystemclassLoader */
    private static Map systemClassLoaderMap = new FastHashMap();

    private static ObjectStreamClass lookup(Class clazz) throws IllegalAccessException, InvocationTargetException
    {
        return (ObjectStreamClass) methodLookup.invoke(null,new Object[]{clazz,Boolean.TRUE});
    }

    private static Field getField(Object source) throws IllegalAccessException, InvocationTargetException
    {
        return (Field) methodGetField.invoke(source,EMPTY_OBJECT_ARRAY);
    }

    static ThreadLocal cacheLoader = new ThreadLocal();

    static
    {
        try
        {
            methodLookup = ObjectStreamClass.class.getDeclaredMethod("lookup",new Class[]{Class.class,Boolean.TYPE});
            methodLookup.setAccessible(true);
        }
        catch (Throwable e)
        {
            e.printStackTrace();
        }

        try
        {
            methodGetField = ObjectStreamField.class.getDeclaredMethod("getField",new Class[]{});
            methodGetField.setAccessible(true);
        }
        catch (Throwable e)
        {
            e.printStackTrace();
        }
    }


    public static void clear(boolean elimiteClassLoadersCached)
    {
      Iterator iter = cache.values().iterator();
      while (iter.hasNext())
      {
        Map map = (Map)iter.next();
        map.clear();
      }
      if (elimiteClassLoadersCached) cache.clear();
      systemClassLoaderMap.clear();
    }
   
    public static void clear()
    {
      clear(true);
    }
   
    public static Map getCache()
    {
      return cache;
    }
   
    public static void printCacheDebug()
    {
    java.util.Iterator iter = getCache().keySet().iterator();
   
    while (iter.hasNext())
    {
      Object loader = iter.next();
      log.debug("ClassLoader = " + loader);
      Map classesMap = (Map)getCache().get(loader);
      java.util.Iterator classesIterator = classesMap.keySet().iterator();
      while (classesIterator.hasNext())
      {
        log.debug("Class = " + classesIterator.next());
      }
     
    }
    }
   
   
    /** PartitionedWeakHashMap<ClassLoader,ConcurrentHashMap<String,ClassMetaData>>
     *  (The current implementation is using FastHashMap instead of ConcurrentHashMap)
     * **/
    static PartitionedWeakHashMap cache = new PartitionedWeakHashMap();
   
    static ClassMetaData proxyMetaData = null;

    static
    {
        try
        {
            proxyMetaData=getClassMetaData("java.lang.reflect.Proxy",Thread.currentThread().getContextClassLoader(),true);
            proxyMetaData.setProxy(true);
        }
        catch (Exception e)
        {
            e.printStackTrace();;
        }
    }
   
    private static Map getLoaderMap(ClassLoader loader)
    {
      if (loader==null)
      {
        return systemClassLoaderMap;
      }
     
      CacheLoaderReference loaderReference = (CacheLoaderReference)cacheLoader.get();
      if (loaderReference==null)
      {
        loaderReference = new CacheLoaderReference();
        cacheLoader.set(loaderReference);
      }
     
      if (loaderReference.getCurrentClassLoader()==loader)
      {
        return loaderReference.getCurrentMap();
      }
       
     
      Map hashMap = (Map)cache.get(loader);
     
      ClassLoader returnLoader = null;
      if (hashMap==null)
      {
        hashMap = new FastHashMap();
        cache.put(loader,hashMap);
        hashMap= (Map)cache.get(loader);
      }
     
      loaderReference.setCurrentClassLoader(loader);
      loaderReference.setCurrentMap(hashMap);
      return hashMap;
    }
    private static ClassMetaData getClassMetaData(String clazzName, ClassLoader loader, boolean checkSerializable) throws IOException
    {
      return getClassMetaData(clazzName,null,loader,checkSerializable);
    }
   

  private static Class resolveClassByName(String clazzName, ClassResolver resolver, ClassLoader loader) throws ClassNotFoundException
  {
    Class clazz = (Class)primClasses.get(clazzName);
   
    if (clazz==null)
    {
      if (resolver!=null)
      {
        clazz = resolver.resolveClass(clazzName);
        if (clazz==null)
        {
          clazz = Class.forName(clazzName,false,loader);
        }
      }
      else
      {
        clazz = Class.forName(clazzName,false,loader);
      }
    }
    return clazz;
  }
 
    public static ClassMetaData getClassMetaData(String clazzName, ClassResolver resolver, ClassLoader loader, boolean checkSerializable) throws IOException
    {
      try
      {
        Map loaderMap = getLoaderMap(loader);
        ClassMetaData classMetadata = (ClassMetaData)loaderMap.get(clazzName);
        if (classMetadata==null)
        {
         
          Class clazz = resolveClassByName(clazzName, resolver, loader);

              if (checkSerializable && !Serializable.class.isAssignableFrom(clazz))
              {
                  throw new NotSerializableException(clazz.getName());
              }
          classMetadata = new ClassMetaData(clazz);

          loaderMap = getLoaderMap(loader);
          loaderMap.put(clazzName,classMetadata);
          classMetadata = (ClassMetaData)loaderMap.get(clazzName);
        }
       
        if (classMetadata.getClazz()==null)
        {
          // this never happens, so, this is just in case
          // The only possibility for that would be crossed classLoader operations.
          // I tried to replicate this scenario on a testcase and it was not possible.
          // So, I decided to have this verification here to be safe
          if (isDebug)
          {
            log.debug("Rebuilding clazz due to cross Loader GC (getClassMetaData(String class, ClassLoader loader)");
          }
          Class clazz = resolveClassByName(clazzName,resolver,loader);
          loaderMap.remove(clazzName);
          classMetadata = new ClassMetaData(clazz);
          loaderMap.put(clazz.getName(),classMetadata);
          classMetadata = (ClassMetaData)loaderMap.get(clazzName);
        }
       
       
          // It looks dummy but doing Class.isProxy is a very expensive operation, so we just do it on a cached basis
          if (classMetadata.isProxy())
          {
              return proxyMetaData;
          } else
          {
              return classMetadata;
          }
      }
      catch (ClassNotFoundException e)
      {
       
        IOException ex = new IOException (e.getMessage());
        ex.initCause(e);
        throw ex;
      }

    }
   
   
    public static ClassMetaData getClassMetaData(Class clazz, boolean checkSerializable) throws IOException
    {
        if (checkSerializable && !Serializable.class.isAssignableFrom(clazz) && !clazz.isPrimitive())
        {
            throw new NotSerializableException(clazz.getName());
        }
      Map loaderMap = getLoaderMap(clazz.getClassLoader());
      ClassMetaData classMetadata = (ClassMetaData)loaderMap.get(clazz.getName());
      if (classMetadata==null)
      {
        classMetadata = new ClassMetaData(clazz);
        loaderMap.put(clazz.getName(),classMetadata);
        classMetadata = (ClassMetaData)loaderMap.get(clazz.getName());
      }
      if (classMetadata.getClazz()==null)
      {
        // this never happens, so, this is just in case
        // The only possibility for that would be crossed classLoader operations.
        // I tried to replicate this scenario on a testcase and it was not possible.
        // So, I decided to have this verification here to be safe
        if (isDebug)
        {
          log.debug("Rebuilding clazz due to cross Loader GC (getClassMetaData(Class clazz, ClassLoader loader)");
        }
        loaderMap.remove(clazz.getName());
        classMetadata = new ClassMetaData(clazz);
        loaderMap.put(clazz.getName(),classMetadata);
        classMetadata = (ClassMetaData)loaderMap.get(clazz.getName());
      }
     
        // It looks dummy but doing Class.isProxy is a very expensive operation, so we just do it on a cached basis
        if (classMetadata.isProxy())
        {
            return proxyMetaData;
        } else
        {
            return classMetadata;
        }
    }
   

    public static boolean isImmutable(Class clazz)
    {
        return (clazz==Character.class || clazz==String.class ||
                clazz == Long.class ||
                clazz == Byte.class ||
                clazz == Double.class ||
                clazz == Float.class ||
                clazz == Integer.class ||
                clazz == Short.class ||
                clazz == Boolean.class ||
                clazz.isPrimitive());
    }

}
TOP

Related Classes of org.jboss.serial.classmetamodel.ClassMetamodelFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.