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 }