001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of Granite Data Services.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or modify
008     *   it under the terms of the GNU Library General Public License as published by
009     *   the Free Software Foundation; either version 2 of the License, or (at your
010     *   option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful, but
013     *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014     *   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015     *   for more details.
016     *
017     *   You should have received a copy of the GNU Library General Public License
018     *   along with this library; if not, see <http://www.gnu.org/licenses/>.
019     */
020    package org.granite.client.messaging.codec;
021    
022    import java.lang.reflect.Constructor;
023    import java.lang.reflect.Method;
024    import java.util.concurrent.ConcurrentHashMap;
025    
026    import org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor;
027    import org.granite.util.TypeUtil;
028    
029    /**
030     * @author Franck WOLFF
031     */
032    public class ClientJavaClassDescriptor extends DefaultActionScriptClassDescriptor {
033    
034            private static final SunConstructorFactory factory = new SunConstructorFactory();
035        private static final ConcurrentHashMap<String, Constructor<?>> constructors =
036            new ConcurrentHashMap<String, Constructor<?>>();
037        
038        
039            public ClientJavaClassDescriptor(String type, byte encoding) {
040                    super(type, encoding);
041            }
042            
043            @Override
044            public Object newJavaInstance() {
045                    try {
046                            return super.newJavaInstance();
047                    }
048                    catch (RuntimeException e) {
049                            if (e.getCause() instanceof InstantiationException)
050                                    return findDefaultConstructor();
051                            throw e;
052                    }
053            }
054            
055            private Object findDefaultConstructor() {
056                    try {
057                            Constructor<?> defaultContructor = constructors.get(type);
058                            if (defaultContructor == null) {
059                                    defaultContructor = factory.findDefaultConstructor(TypeUtil.forName(type));
060                        Constructor<?> previousConstructor = constructors.putIfAbsent(type, defaultContructor);
061                        if (previousConstructor != null)
062                            defaultContructor = previousConstructor; // Should be the same instance, anyway...
063                            }
064                            return defaultContructor.newInstance();
065                    }
066                    catch (Exception e) {
067                            throw new RuntimeException("Could not create Proxy for: " + type);
068                    }
069            }
070    }
071    class SunConstructorFactory {
072    
073        private final Object reflectionFactory;
074        private final Method newConstructorForSerialization;
075    
076        public SunConstructorFactory() {
077            try {
078                Class<?> factoryClass = TypeUtil.forName("sun.reflect.ReflectionFactory");
079                Method getReflectionFactory = factoryClass.getDeclaredMethod("getReflectionFactory");
080                reflectionFactory = getReflectionFactory.invoke(null);
081                newConstructorForSerialization = factoryClass.getDeclaredMethod(
082                    "newConstructorForSerialization",
083                    new Class[]{Class.class, Constructor.class}
084                );
085            } catch (Exception e) {
086                throw new RuntimeException("Could not create Sun Factory", e);
087            }
088        }
089    
090        @SuppressWarnings("unchecked")
091        public <T> Constructor<T> findDefaultConstructor(Class<T> clazz) {
092            try {
093                Constructor<?> constructor = Object.class.getDeclaredConstructor();
094                constructor = (Constructor<?>)newConstructorForSerialization.invoke(
095                    reflectionFactory,
096                    new Object[]{clazz, constructor}
097                );
098                constructor.setAccessible(true);
099                return (Constructor<T>)constructor;
100            } catch (Exception e) {
101                throw new RuntimeException(e);
102            }
103        }
104    }