001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.hivemind.impl;
016    
017    import java.lang.reflect.Constructor;
018    import java.util.HashMap;
019    import java.util.Iterator;
020    import java.util.List;
021    import java.util.Map;
022    
023    import org.apache.commons.logging.Log;
024    import org.apache.commons.logging.LogFactory;
025    import org.apache.hivemind.ApplicationRuntimeException;
026    import org.apache.hivemind.ErrorHandler;
027    import org.apache.hivemind.Location;
028    import org.apache.hivemind.internal.RegistryInfrastructure;
029    import org.apache.hivemind.schema.Translator;
030    import org.apache.hivemind.schema.rules.ClassTranslator;
031    import org.apache.hivemind.schema.rules.InstanceTranslator;
032    import org.apache.hivemind.schema.rules.ServiceTranslator;
033    import org.apache.hivemind.schema.rules.SmartTranslator;
034    
035    /**
036     * Manages translators for {@link org.apache.hivemind.impl.RegistryInfrastructureImpl}.
037     * 
038     * @author Howard Lewis Ship
039     */
040    public class TranslatorManager
041    {
042        static final Log LOG = LogFactory.getLog(TranslatorManager.class);
043    
044        public static final String TRANSLATORS_CONFIGURATION_ID = "hivemind.Translators";
045    
046        private ErrorHandler _errorHandler;
047    
048        private RegistryInfrastructure _registry;
049    
050        /**
051         * Map of Class, keyed on translator name, used to instantiate new
052         * {@link org.apache.hivemind.schema.Translator}s. Loaded from the
053         * <code>hivemind.Translators</code> configuration point;
054         */
055        private Map _translatorClasses = new HashMap();
056    
057        private Map _translatorsCache = new HashMap();
058    
059        private boolean _translatorsLoaded;
060    
061        public TranslatorManager(RegistryInfrastructure registry, ErrorHandler errorHandler)
062        {
063            _registry = registry;
064            _errorHandler = errorHandler;
065    
066            // Seed the basic translators used to "bootstrap" the
067            // processing of the hivemind.Translators configuration point.
068    
069            _translatorsCache.put("class", new ClassTranslator());
070            _translatorsCache.put("service", new ServiceTranslator());
071            _translatorsCache.put("smart", new SmartTranslator());
072            _translatorsCache.put("instance", new InstanceTranslator());
073    
074            // smart may take an initializer, so we need to put it into the classes as
075            // well.
076    
077            _translatorClasses.put("smart", SmartTranslator.class);
078    
079        }
080    
081        public synchronized Translator getTranslator(String constructor)
082        {
083            // The cache is preloaded with the hardcoded translators.
084    
085            if (!_translatorsLoaded && !_translatorsCache.containsKey(constructor))
086                loadTranslators();
087    
088            Translator result = (Translator) _translatorsCache.get(constructor);
089    
090            if (result == null)
091            {
092                result = constructTranslator(constructor);
093                _translatorsCache.put(constructor, result);
094            }
095    
096            return result;
097        }
098    
099        private Translator constructTranslator(String constructor)
100        {
101            String name = constructor;
102            String initializer = null;
103    
104            int commax = constructor.indexOf(',');
105    
106            if (commax > 0)
107            {
108                name = constructor.substring(0, commax);
109                initializer = constructor.substring(commax + 1);
110            }
111    
112            Class translatorClass = findTranslatorClass(name);
113    
114            // TODO: check for null class, meaning that the translator is a service.
115    
116            return createTranslator(translatorClass, initializer);
117        }
118    
119        private Translator createTranslator(Class translatorClass, String initializer)
120        {
121            try
122            {
123    
124                if (initializer == null)
125                    return (Translator) translatorClass.newInstance();
126    
127                Constructor c = translatorClass.getConstructor(new Class[]
128                { String.class });
129    
130                return (Translator) c.newInstance(new Object[]
131                { initializer });
132            }
133            catch (Exception ex)
134            {
135                throw new ApplicationRuntimeException(ImplMessages.translatorInstantiationFailure(
136                        translatorClass,
137                        ex), ex);
138            }
139        }
140    
141        private Class findTranslatorClass(String translatorName)
142        {
143            Class result = (Class) _translatorClasses.get(translatorName);
144    
145            if (result == null)
146                throw new ApplicationRuntimeException(ImplMessages.unknownTranslatorName(
147                        translatorName,
148                        TRANSLATORS_CONFIGURATION_ID));
149    
150            return result;
151        }
152    
153        private void loadTranslators()
154        {
155            // Prevent endless recursion!
156    
157            _translatorsLoaded = true;
158    
159            List contributions = _registry.getConfiguration(TRANSLATORS_CONFIGURATION_ID, null);
160    
161            Map locations = new HashMap();
162            locations.put("class", null);
163    
164            Iterator i = contributions.iterator();
165            while (i.hasNext())
166            {
167                TranslatorContribution c = (TranslatorContribution) i.next();
168    
169                String name = c.getName();
170                Location oldLocation = (Location) locations.get(name);
171    
172                if (oldLocation != null)
173                {
174                    _errorHandler.error(LOG, ImplMessages.duplicateTranslatorName(name, oldLocation), c
175                            .getLocation(), null);
176    
177                    continue;
178                }
179    
180                locations.put(name, c.getLocation());
181    
182                Translator t = c.getTranslator();
183    
184                if (t != null)
185                {
186                    _translatorsCache.put(name, t);
187                    continue;
188                }
189    
190                Class tClass = c.getTranslatorClass();
191    
192                if (tClass == null)
193                {
194                    _errorHandler.error(
195                            LOG,
196                            ImplMessages.incompleteTranslator(c),
197                            c.getLocation(),
198                            null);
199                    continue;
200                }
201    
202                _translatorClasses.put(name, tClass);
203            }
204    
205        }
206    
207    }