1 /**
2 *
3 * Copyright 2005 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.geronimo.kernel.config;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.io.PrintWriter;
23 import java.io.File;
24 import java.net.URL;
25 import java.util.Collection;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.Set;
29 import java.util.List;
30 import java.util.Collections;
31 import java.util.ArrayList;
32 import java.util.Properties;
33 import java.util.Map;
34 import java.util.LinkedHashSet;
35
36 import org.apache.geronimo.gbean.AbstractName;
37 import org.apache.geronimo.gbean.AbstractNameQuery;
38 import org.apache.geronimo.gbean.GAttributeInfo;
39 import org.apache.geronimo.gbean.GBeanData;
40 import org.apache.geronimo.gbean.GReferenceInfo;
41 import org.apache.geronimo.gbean.InvalidConfigurationException;
42 import org.apache.geronimo.gbean.ReferencePatterns;
43 import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
44 import org.apache.geronimo.kernel.GBeanNotFoundException;
45 import org.apache.geronimo.kernel.Kernel;
46 import org.apache.geronimo.kernel.ClassLoading;
47 import org.apache.geronimo.kernel.InternalKernelException;
48 import org.apache.geronimo.kernel.basic.BasicKernel;
49 import org.apache.geronimo.kernel.management.State;
50 import org.apache.geronimo.kernel.repository.Artifact;
51 import org.apache.commons.logging.Log;
52 import org.apache.commons.logging.LogFactory;
53
54 /**
55 * @version $Rev:386276 $ $Date: 2006-11-06 02:28:54 -0800 (Mon, 06 Nov 2006) $
56 */
57 public final class ConfigurationUtil {
58 private static final Log log = LogFactory.getLog(ConfigurationUtil.class);
59 private static final ConfigurationMarshaler configurationMarshaler;
60
61 static {
62 ConfigurationMarshaler marshaler = null;
63 String marshalerClass = System.getProperty("Xorg.apache.geronimo.kernel.config.Marshaler");
64 if (marshalerClass != null) {
65 try {
66 marshaler = createConfigurationMarshaler(marshalerClass);
67 } catch (Exception e) {
68 log.error("Error creating configuration marshaler class " + marshalerClass , e);
69 }
70 }
71
72
73
74
75
76
77
78
79
80 if (marshaler == null) {
81 marshaler = new SerializedConfigurationMarshaler();
82 }
83
84 configurationMarshaler = marshaler;
85 }
86
87 public static ConfigurationMarshaler createConfigurationMarshaler(String marshalerClass) throws Exception {
88 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
89 Class clazz = null;
90 if (classLoader != null) {
91 try {
92 clazz = ClassLoading.loadClass(marshalerClass, classLoader);
93 } catch (ClassNotFoundException ignored) {
94
95 }
96 }
97 if (clazz == null) {
98 classLoader = ConfigurationUtil.class.getClassLoader();
99 try {
100 clazz = ClassLoading.loadClass(marshalerClass, classLoader);
101 } catch (ClassNotFoundException ignored) {
102
103 }
104 }
105
106 if (clazz != null) {
107 Object object = clazz.newInstance();
108 if (object instanceof ConfigurationMarshaler) {
109 return (ConfigurationMarshaler) object;
110 } else {
111 log.warn("Configuration marshaler class is not an instance of ConfigurationMarshaler " + marshalerClass + ": using default configuration ");
112 }
113 }
114 return null;
115 }
116
117 private ConfigurationUtil() {
118 }
119
120 public static GBeanState newGBeanState(Collection gbeans) {
121 return configurationMarshaler.newGBeanState(gbeans);
122 }
123
124 public static AbstractName loadBootstrapConfiguration(Kernel kernel, InputStream in, ClassLoader classLoader) throws Exception {
125 ConfigurationData configurationData = readConfigurationData(in);
126 return loadBootstrapConfiguration(kernel, configurationData, classLoader);
127 }
128
129 public static AbstractName loadBootstrapConfiguration(Kernel kernel, ConfigurationData configurationData, ClassLoader classLoader) throws Exception {
130 if (kernel == null) throw new NullPointerException("kernel is null");
131 if (configurationData == null) throw new NullPointerException("configurationData is null");
132 if (classLoader == null) throw new NullPointerException("classLoader is null");
133
134
135 List dependencies = configurationData.getEnvironment().getDependencies();
136 if (!dependencies.isEmpty()) {
137 configurationData.getEnvironment().setDependencies(Collections.EMPTY_SET);
138
139 }
140
141
142 Artifact configId = configurationData.getId();
143 AbstractName abstractName = Configuration.getConfigurationAbstractName(configId);
144 GBeanData gbeanData = new GBeanData(abstractName, Configuration.GBEAN_INFO);
145 gbeanData.setAttribute("configurationData", configurationData);
146 gbeanData.setAttribute("configurationResolver", new ConfigurationResolver(configurationData, null, null));
147
148
149 kernel.loadGBean(gbeanData, classLoader);
150 kernel.startGBean(gbeanData.getAbstractName());
151
152 Configuration configuration = (Configuration) kernel.getGBean(gbeanData.getAbstractName());
153
154
155 startConfigurationGBeans(configuration.getAbstractName(), configuration, kernel);
156
157 ConfigurationManager configurationManager = getConfigurationManager(kernel);
158 configurationManager.loadConfiguration(configId);
159 return gbeanData.getAbstractName();
160 }
161
162 public static void writeConfigurationData(ConfigurationData configurationData, OutputStream out) throws IOException {
163 configurationMarshaler.writeConfigurationData(configurationData, out);
164 }
165
166 public static ConfigurationData readConfigurationData(InputStream in) throws IOException, ClassNotFoundException {
167 return configurationMarshaler.readConfigurationData(in);
168 }
169
170 public static void writeConfigInfo(PrintWriter writer, ConfigurationData configurationData) {
171 writeConfigInfo("", writer, configurationData);
172 }
173 private static void writeConfigInfo(String prefix, PrintWriter writer, ConfigurationData configurationData) {
174 writer.println(prefix+"id=" + configurationData.getId());
175 writer.println(prefix+"type=" + configurationData.getModuleType());
176 writer.println(prefix+"created=" + configurationData.getCreated());
177 Set ownedConfigurations = configurationData.getOwnedConfigurations();
178 int i = 0;
179 for (Iterator iterator = ownedConfigurations.iterator(); iterator.hasNext();) {
180 Artifact ownedConfiguration = (Artifact) iterator.next();
181 writer.println(prefix+"owned." + i++ + "=" + ownedConfiguration);
182 }
183 i = 0;
184 for (Iterator it = configurationData.getChildConfigurations().values().iterator(); it.hasNext(); i++) {
185 ConfigurationData data = (ConfigurationData) it.next();
186 writeConfigInfo("child."+i+".", writer, data);
187 }
188 writer.flush();
189 }
190
191 public static ConfigurationInfo readConfigurationInfo(InputStream in, AbstractName storeName, File inPlaceLocation) throws IOException {
192 Properties properties = new Properties();
193 properties.load(in);
194 return readConfigurationInfo("", properties, storeName, inPlaceLocation);
195 }
196 private static ConfigurationInfo readConfigurationInfo(String prefix, Properties properties, AbstractName storeName, File inPlaceLocation) throws IOException {
197 String id = properties.getProperty(prefix+"id");
198 Artifact configId = Artifact.create(id);
199
200 String type = properties.getProperty(prefix+"type");
201 ConfigurationModuleType moduleType = ConfigurationModuleType.getByName(type);
202 if (moduleType == null) {
203 throw new IllegalArgumentException("Unknown module type: " + type);
204 }
205
206 String created = properties.getProperty(prefix+"created");
207 long time;
208 try {
209 time = Long.parseLong(created);
210 } catch (NumberFormatException e) {
211 throw new IllegalArgumentException("Invalid created time: " + created);
212 }
213
214 LinkedHashSet ownedConfigurations = new LinkedHashSet();
215 for (Iterator iterator = properties.entrySet().iterator(); iterator.hasNext();) {
216 Map.Entry entry = (Map.Entry) iterator.next();
217 String name = (String) entry.getKey();
218 if (name.startsWith(prefix+"owned.")) {
219 String value = (String) entry.getValue();
220 Artifact ownedConfiguration = Artifact.create(value);
221 ownedConfigurations.add(ownedConfiguration);
222 }
223 }
224 LinkedHashSet childConfigurations = new LinkedHashSet();
225 int test = 0;
226 while(true) {
227 String next = prefix+"child."+test+".";
228 String value = properties.getProperty(next+".id");
229 if(value == null) {
230 break;
231 }
232 childConfigurations.add(readConfigurationInfo(next, properties, storeName, inPlaceLocation));
233 ++test;
234 }
235
236 return new ConfigurationInfo(storeName, configId, moduleType, time, ownedConfigurations, childConfigurations, inPlaceLocation);
237 }
238
239 /**
240 * Gets a reference or proxy to the ConfigurationManager running in the specified kernel.
241 *
242 * @return The ConfigurationManager
243 * @throws IllegalStateException Occurs if a ConfigurationManager cannot be identified
244 */
245 public static ConfigurationManager getConfigurationManager(Kernel kernel) {
246 Set names = kernel.listGBeans(new AbstractNameQuery(ConfigurationManager.class.getName()));
247 for (Iterator iterator = names.iterator(); iterator.hasNext();) {
248 AbstractName abstractName = (AbstractName) iterator.next();
249 if (!kernel.isRunning(abstractName)) {
250 iterator.remove();
251 }
252 }
253 if (names.isEmpty()) {
254 throw new IllegalStateException("A Configuration Manager could not be found in the kernel");
255 }
256 if (names.size() > 1) {
257 throw new IllegalStateException("More than one Configuration Manager was found in the kernel");
258 }
259 AbstractName configurationManagerName = (AbstractName) names.iterator().next();
260 return (ConfigurationManager) kernel.getProxyManager().createProxy(configurationManagerName, ConfigurationManager.class);
261 }
262
263 /**
264 * Gets a reference or proxy to an EditableConfigurationManager running in the specified kernel, if there is one.
265 *
266 * @return The EdtiableConfigurationManager, or none if there is not one available.
267 * @throws IllegalStateException Occurs if there are multiple EditableConfigurationManagers in the kernel.
268 */
269 public static EditableConfigurationManager getEditableConfigurationManager(Kernel kernel) {
270 Set names = kernel.listGBeans(new AbstractNameQuery(EditableConfigurationManager.class.getName()));
271 for (Iterator iterator = names.iterator(); iterator.hasNext();) {
272 AbstractName abstractName = (AbstractName) iterator.next();
273 if (!kernel.isRunning(abstractName)) {
274 iterator.remove();
275 }
276 }
277 if (names.isEmpty()) {
278 return null;
279 }
280 if (names.size() > 1) {
281 throw new IllegalStateException("More than one Configuration Manager was found in the kernel");
282 }
283 AbstractName configurationManagerName = (AbstractName) names.iterator().next();
284 return (EditableConfigurationManager) kernel.getProxyManager().createProxy(configurationManagerName, EditableConfigurationManager.class);
285 }
286
287 public static void releaseConfigurationManager(Kernel kernel, ConfigurationManager configurationManager) {
288 kernel.getProxyManager().destroyProxy(configurationManager);
289 }
290
291 static void preprocessGBeanData(AbstractName configurationName, Configuration configuration, GBeanData gbeanData) throws InvalidConfigException {
292 for (Iterator references = gbeanData.getReferencesNames().iterator(); references.hasNext();) {
293 String referenceName = (String) references.next();
294 GReferenceInfo referenceInfo = gbeanData.getGBeanInfo().getReference(referenceName);
295 if (referenceInfo == null) {
296 throw new InvalidConfigException("No reference named " + referenceName + " in gbean " + gbeanData.getAbstractName());
297 }
298 boolean isSingleValued = !referenceInfo.getProxyType().equals(Collection.class.getName());
299 if (isSingleValued) {
300 ReferencePatterns referencePatterns = gbeanData.getReferencePatterns(referenceName);
301 AbstractName abstractName;
302 try {
303 abstractName = configuration.findGBean(referencePatterns);
304 } catch (GBeanNotFoundException e) {
305 throw new InvalidConfigException("Unable to resolve reference \"" + referenceName + "\" in gbean " + gbeanData.getAbstractName() + " to a gbean matching the pattern " + referencePatterns, e);
306 }
307 gbeanData.setReferencePatterns(referenceName, new ReferencePatterns(abstractName));
308 }
309 }
310
311 Set newDependencies = new HashSet();
312 for (Iterator dependencyIterator = gbeanData.getDependencies().iterator(); dependencyIterator.hasNext();) {
313 ReferencePatterns referencePatterns = (ReferencePatterns) dependencyIterator.next();
314 AbstractName abstractName;
315 try {
316 abstractName = configuration.findGBean(referencePatterns);
317 } catch (GBeanNotFoundException e) {
318 throw new InvalidConfigException("Unable to resolve dependency in gbean " + gbeanData.getAbstractName(), e);
319 }
320 newDependencies.add(new ReferencePatterns(abstractName));
321 }
322 gbeanData.setDependencies(newDependencies);
323
324
325
326 GAttributeInfo attribute = gbeanData.getGBeanInfo().getAttribute("configurationBaseUrl");
327 if (attribute != null && attribute.getType().equals("java.net.URL")) {
328 try {
329 Set set = configuration.getConfigurationResolver().resolve("");
330 if (set.size() != 1) {
331 throw new AssertionError("Expected one match for pattern \".\", but got " + set.size() + " matches");
332 }
333 URL baseURL = (URL) set.iterator().next();
334 gbeanData.setAttribute("configurationBaseUrl", baseURL);
335 } catch (Exception e) {
336 throw new InvalidConfigException("Unable to set attribute named " + "configurationBaseUrl" + " in gbean " + gbeanData.getAbstractName(), e);
337 }
338 }
339
340
341 gbeanData.addDependency(configurationName);
342 }
343
344 static void startConfigurationGBeans(AbstractName configurationName, Configuration configuration, Kernel kernel) throws InvalidConfigException {
345 List gbeans = new ArrayList(configuration.getGBeans().values());
346 Collections.sort(gbeans, new GBeanData.PriorityComparator());
347
348 List loaded = new ArrayList(gbeans.size());
349 List started = new ArrayList(gbeans.size());
350
351 try {
352
353 for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) {
354 GBeanData gbeanData = (GBeanData) iterator.next();
355
356
357 gbeanData = new GBeanData(gbeanData);
358
359
360 preprocessGBeanData(configurationName, configuration, gbeanData);
361
362 try {
363 kernel.loadGBean(gbeanData, configuration.getConfigurationClassLoader());
364 loaded.add(gbeanData.getAbstractName());
365 } catch (GBeanAlreadyExistsException e) {
366 throw new InvalidConfigException(e);
367 }
368 }
369
370 try {
371
372 for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) {
373 GBeanData gbeanData = (GBeanData) iterator.next();
374 AbstractName gbeanName = gbeanData.getAbstractName();
375 kernel.startRecursiveGBean(gbeanName);
376 started.add(gbeanName);
377 }
378
379
380 List unstarted = new ArrayList();
381 for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) {
382 GBeanData gbeanData = (GBeanData) iterator.next();
383 AbstractName gbeanName = gbeanData.getAbstractName();
384 if (State.RUNNING_INDEX != kernel.getGBeanState(gbeanName)) {
385 String stateReason = null;
386 if (kernel instanceof BasicKernel) {
387 stateReason = ((BasicKernel) kernel).getStateReason(gbeanName);
388 }
389 String name = gbeanName.toURI().getQuery();
390 if (stateReason != null) {
391 unstarted.add("The service " + name + " did not start because " + stateReason);
392 } else {
393 unstarted.add("The service " + name + " did not start for an unknown reason");
394 }
395 }
396 }
397 if (!unstarted.isEmpty()) {
398 StringBuffer message = new StringBuffer();
399 message.append("Configuration ").append(configuration.getId()).append(" failed to start due to the following reasons:\n");
400 for (Iterator iterator = unstarted.iterator(); iterator.hasNext();) {
401 String reason = (String) iterator.next();
402 message.append(" ").append(reason).append("\n");
403 }
404 throw new InvalidConfigurationException(message.toString());
405 }
406 } catch (GBeanNotFoundException e) {
407 throw new InvalidConfigException(e);
408 }
409
410 for (Iterator iterator = configuration.getChildren().iterator(); iterator.hasNext();) {
411 Configuration childConfiguration = (Configuration) iterator.next();
412 ConfigurationUtil.startConfigurationGBeans(configurationName, childConfiguration, kernel);
413 }
414 } catch (Throwable e) {
415 for (Iterator iterator = started.iterator(); iterator.hasNext();) {
416 AbstractName gbeanName = (AbstractName) iterator.next();
417 try {
418 kernel.stopGBean(gbeanName);
419 } catch (GBeanNotFoundException ignored) {
420 } catch (IllegalStateException ignored) {
421 } catch (InternalKernelException kernelException) {
422 log.debug("Error cleaning up after failed start of configuration " + configuration.getId() + " gbean " + gbeanName, kernelException);
423 }
424 }
425 for (Iterator iterator = loaded.iterator(); iterator.hasNext();) {
426 AbstractName gbeanName = (AbstractName) iterator.next();
427 try {
428 kernel.unloadGBean(gbeanName);
429 } catch (GBeanNotFoundException ignored) {
430 } catch (IllegalStateException ignored) {
431 } catch (InternalKernelException kernelException) {
432 log.debug("Error cleaning up after failed start of configuration " + configuration.getId() + " gbean " + gbeanName, kernelException);
433 }
434 }
435 if (e instanceof Error) {
436 throw (Error) e;
437 }
438 if (e instanceof InvalidConfigException) {
439 throw (InvalidConfigException) e;
440 }
441 throw new InvalidConfigException("Unknown start exception", e);
442 }
443 }
444 }