1 // Copyright 2006, 2007, 2008 The Apache Software Foundation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package org.apache.tapestry5.ioc;
16
17 import static org.apache.tapestry5.ioc.IOCConstants.MODULE_BUILDER_MANIFEST_ENTRY_NAME;
18 import org.apache.tapestry5.ioc.annotations.SubModule;
19 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
20
21 import java.io.Closeable;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URL;
25 import java.util.Enumeration;
26 import java.util.jar.Manifest;
27
28 /**
29 * A collection of utility methods for a couple of different areas, including creating the initial {@link
30 * org.apache.tapestry5.ioc.Registry}.
31 */
32 public final class IOCUtilities
33 {
34 private IOCUtilities()
35 {
36 }
37
38 /**
39 * Construct a default Registry, including modules identifed via the Tapestry-Module-Classes Manifest entry. The
40 * registry will have been {@linkplain Registry#performRegistryStartup() started up} before it is returned.
41 *
42 * @return constructed Registry, after startup
43 * @see #addDefaultModules(RegistryBuilder)
44 */
45 public static Registry buildDefaultRegistry()
46 {
47 RegistryBuilder builder = new RegistryBuilder();
48
49 addDefaultModules(builder);
50
51 Registry registry = builder.build();
52
53 registry.performRegistryStartup();
54
55 return registry;
56 }
57
58 /**
59 * Scans the classpath for JAR Manifests that contain the Tapestry-Module-Classes attribute and adds each
60 * corresponding class to the RegistryBuilder. In addition, looks for a system property named "tapestry.modules" and
61 * adds all of those modules as well. The tapestry.modules approach is intended for development.
62 *
63 * @param builder the builder to which modules will be added
64 * @see SubModule
65 * @see RegistryBuilder#add(String)
66 */
67 public static void addDefaultModules(RegistryBuilder builder)
68 {
69 try
70 {
71 Enumeration<URL> urls = builder.getClassLoader().getResources("META-INF/MANIFEST.MF");
72
73 while (urls.hasMoreElements())
74 {
75 URL url = urls.nextElement();
76
77 addModulesInManifest(builder, url);
78 }
79
80 addModulesInList(builder, System.getProperty("tapestry.modules"));
81
82 }
83 catch (IOException ex)
84 {
85 throw new RuntimeException(ex.getMessage(), ex);
86 }
87 }
88
89 private static void addModulesInManifest(RegistryBuilder builder, URL url)
90 {
91 InputStream in = null;
92
93 Throwable fail = null;
94
95 try
96 {
97 in = url.openStream();
98
99 Manifest mf = new Manifest(in);
100
101 in.close();
102
103 in = null;
104
105 String list = mf.getMainAttributes().getValue(MODULE_BUILDER_MANIFEST_ENTRY_NAME);
106
107 addModulesInList(builder, list);
108 }
109 catch (RuntimeException ex)
110 {
111 fail = ex;
112 }
113 catch (IOException ex)
114 {
115 fail = ex;
116 }
117 finally
118 {
119 close(in);
120 }
121
122 if (fail != null)
123 throw new RuntimeException(String.format("Exception loading module(s) from manifest %s: %s",
124 url.toString(),
125 InternalUtils.toMessage(fail)), fail);
126
127 }
128
129 static void addModulesInList(RegistryBuilder builder, String list)
130 {
131 if (list == null) return;
132
133 String[] classnames = list.split(",");
134
135 for (String classname : classnames)
136 {
137 builder.add(classname.trim());
138 }
139 }
140
141 /**
142 * Closes an input stream (or other Closeable), ignoring any exception.
143 *
144 * @param closeable the thing to close, or null to close nothing
145 */
146 private static void close(Closeable closeable)
147 {
148 if (closeable != null)
149 {
150 try
151 {
152 closeable.close();
153 }
154 catch (IOException ex)
155 {
156 // Ignore.
157 }
158 }
159 }
160 }