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
021package org.granite.config;
022
023import java.io.Externalizable;
024import java.io.IOException;
025import java.io.ObjectInput;
026import java.io.ObjectOutput;
027import java.lang.reflect.InvocationTargetException;
028import java.util.List;
029import java.util.concurrent.ConcurrentHashMap;
030
031import org.granite.messaging.amf.io.util.Property;
032import org.granite.messaging.amf.io.util.externalizer.Externalizer;
033import org.granite.messaging.amf.io.util.externalizer.annotation.ExternalizedBean;
034import org.granite.util.TypeUtil;
035import org.granite.util.XMap;
036
037/**
038 * @author Franck WOLFF
039 */
040public 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 = TypeUtil.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}