001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2012 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    
021    package org.granite.client.messaging.codec;
022    
023    import java.lang.reflect.Constructor;
024    import java.lang.reflect.Method;
025    import java.util.concurrent.ConcurrentHashMap;
026    
027    import org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor;
028    import org.granite.util.TypeUtil;
029    
030    /**
031     * @author Franck WOLFF
032     */
033    public class ClientJavaClassDescriptor extends DefaultActionScriptClassDescriptor {
034    
035            private static final SunConstructorFactory factory = new SunConstructorFactory();
036        private static final ConcurrentHashMap<String, Constructor<?>> constructors =
037            new ConcurrentHashMap<String, Constructor<?>>();
038        
039        
040            public ClientJavaClassDescriptor(String type, byte encoding) {
041                    super(type, encoding);
042            }
043            
044            @Override
045            public Object newJavaInstance() {
046                    try {
047                            return super.newJavaInstance();
048                    }
049                    catch (RuntimeException e) {
050                            if (e.getCause() instanceof InstantiationException)
051                                    return findDefaultConstructor();
052                            throw e;
053                    }
054            }
055            
056            private Object findDefaultConstructor() {
057                    try {
058                            Constructor<?> defaultContructor = constructors.get(type);
059                            if (defaultContructor == null) {
060                                    defaultContructor = factory.findDefaultConstructor(TypeUtil.forName(type));
061                        Constructor<?> previousConstructor = constructors.putIfAbsent(type, defaultContructor);
062                        if (previousConstructor != null)
063                            defaultContructor = previousConstructor; // Should be the same instance, anyway...
064                            }
065                            return defaultContructor.newInstance();
066                    }
067                    catch (Exception e) {
068                            throw new RuntimeException("Could not create Proxy for: " + type);
069                    }
070            }
071    }
072    class SunConstructorFactory {
073    
074        private final Object reflectionFactory;
075        private final Method newConstructorForSerialization;
076    
077        public SunConstructorFactory() {
078            try {
079                Class<?> factoryClass = TypeUtil.forName("sun.reflect.ReflectionFactory");
080                Method getReflectionFactory = factoryClass.getDeclaredMethod("getReflectionFactory");
081                reflectionFactory = getReflectionFactory.invoke(null);
082                newConstructorForSerialization = factoryClass.getDeclaredMethod(
083                    "newConstructorForSerialization",
084                    new Class[]{Class.class, Constructor.class}
085                );
086            } catch (Exception e) {
087                throw new RuntimeException("Could not create Sun Factory", e);
088            }
089        }
090    
091        @SuppressWarnings("unchecked")
092        public <T> Constructor<T> findDefaultConstructor(Class<T> clazz) {
093            try {
094                Constructor<?> constructor = Object.class.getDeclaredConstructor();
095                constructor = (Constructor<?>)newConstructorForSerialization.invoke(
096                    reflectionFactory,
097                    new Object[]{clazz, constructor}
098                );
099                constructor.setAccessible(true);
100                return (Constructor<T>)constructor;
101            } catch (Exception e) {
102                throw new RuntimeException(e);
103            }
104        }
105    }