001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2011 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.config;
022    
023    import java.io.Externalizable;
024    import java.io.IOException;
025    import java.io.ObjectInput;
026    import java.io.ObjectOutput;
027    import java.lang.reflect.InvocationTargetException;
028    import java.util.List;
029    import java.util.concurrent.ConcurrentHashMap;
030    
031    import org.granite.messaging.amf.io.util.Property;
032    import org.granite.messaging.amf.io.util.externalizer.Externalizer;
033    import org.granite.messaging.amf.io.util.externalizer.annotation.ExternalizedBean;
034    import org.granite.util.ClassUtil;
035    import org.granite.util.XMap;
036    
037    /**
038     * @author Franck WOLFF
039     */
040    public class ExternalizerFactory implements ConfigurableFactory<Externalizer> {
041    
042        private static final Externalizer NULL_EXTERNALIZER = new Externalizer() {
043    
044            private final static String NOT_IMPLEMENTED = "Not implemented (null externalizer)";
045    
046            public void configure(XMap properties) {
047                throw new RuntimeException(NOT_IMPLEMENTED);
048                    }
049                    public List<Property> findOrderedFields(Class<?> clazz) {
050                throw new RuntimeException(NOT_IMPLEMENTED);
051            }
052            public Object newInstance(String type, ObjectInput in)
053                throws IOException, ClassNotFoundException, InstantiationException,
054                       InvocationTargetException, IllegalAccessException {
055                throw new RuntimeException(NOT_IMPLEMENTED);
056            }
057            public void readExternal(Object o, ObjectInput in)
058                throws IOException, ClassNotFoundException, IllegalAccessException {
059                throw new RuntimeException(NOT_IMPLEMENTED);
060            }
061            public void writeExternal(Object o, ObjectOutput out)
062                throws IOException, IllegalAccessException {
063                throw new RuntimeException(NOT_IMPLEMENTED);
064            }
065            public int accept(Class<?> clazz) {
066                return -1;
067            }
068        };
069        
070        private final ConcurrentHashMap<String, Externalizer> externalizersCache = new ConcurrentHashMap<String, Externalizer>();
071    
072        public Externalizer getNullInstance() {
073            return NULL_EXTERNALIZER;
074        }
075    
076        public Externalizer getInstance(String type, GraniteConfig config) throws GraniteConfigException {
077            return newInstance(type, config);
078        }
079    
080        public Externalizer getInstanceForBean(
081            List<Externalizer> scannedConfigurables,
082            Class<?> beanClass,
083            GraniteConfig config) throws GraniteConfigException {
084    
085            Externalizer externalizer = NULL_EXTERNALIZER;
086            
087            if (!Externalizable.class.isAssignableFrom(beanClass)) {
088                ExternalizedBean annotation = beanClass.getAnnotation(ExternalizedBean.class);
089    
090                Class<? extends Externalizer> type = null;
091                if (annotation != null && annotation.type() != null)
092                    type = annotation.type();
093                else {
094                    int maxWeight = -1;
095                    for (Externalizer e : scannedConfigurables) {
096                        int weight = e.accept(beanClass);
097                        if (weight > maxWeight) {
098                            maxWeight = weight;
099                            type = e.getClass();
100                        }
101                    }
102                }
103    
104                if (type != null)
105                    externalizer = newInstance(type.getName(), config);
106            }
107    
108            return externalizer;
109        }
110        
111        private Externalizer newInstance(String externalizerType, GraniteConfig config) {
112            Externalizer externalizer = externalizersCache.get(externalizerType);
113            if (externalizer == null) {
114                    try {
115                            externalizer = ClassUtil.newInstance(externalizerType, Externalizer.class);
116                    } catch (Exception e) {
117                            throw new GraniteConfigException("Could not instantiate externalizer: " + externalizerType, e);
118                    }
119                    Externalizer previous = externalizersCache.putIfAbsent(externalizerType, externalizer);
120                    if (previous != null)
121                            externalizer = previous;
122                    else
123                            externalizer.configure(config.getExternalizersConfiguration());
124            }
125            return externalizer;
126        }
127    }