001 // Copyright 2006, 2007, 2008 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.tapestry5.ioc;
016
017 import static org.apache.tapestry5.ioc.IOCConstants.MODULE_BUILDER_MANIFEST_ENTRY_NAME;
018 import org.apache.tapestry5.ioc.annotations.SubModule;
019 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
020
021 import java.io.Closeable;
022 import java.io.IOException;
023 import java.io.InputStream;
024 import java.net.URL;
025 import java.util.Enumeration;
026 import java.util.jar.Manifest;
027
028 /**
029 * A collection of utility methods for a couple of different areas, including creating the initial {@link
030 * org.apache.tapestry5.ioc.Registry}.
031 */
032 public final class IOCUtilities
033 {
034 private IOCUtilities()
035 {
036 }
037
038 /**
039 * Construct a default Registry, including modules identifed via the Tapestry-Module-Classes Manifest entry. The
040 * registry will have been {@linkplain Registry#performRegistryStartup() started up} before it is returned.
041 *
042 * @return constructed Registry, after startup
043 * @see #addDefaultModules(RegistryBuilder)
044 */
045 public static Registry buildDefaultRegistry()
046 {
047 RegistryBuilder builder = new RegistryBuilder();
048
049 addDefaultModules(builder);
050
051 Registry registry = builder.build();
052
053 registry.performRegistryStartup();
054
055 return registry;
056 }
057
058 /**
059 * Scans the classpath for JAR Manifests that contain the Tapestry-Module-Classes attribute and adds each
060 * corresponding class to the RegistryBuilder. In addition, looks for a system property named "tapestry.modules" and
061 * adds all of those modules as well. The tapestry.modules approach is intended for development.
062 *
063 * @param builder the builder to which modules will be added
064 * @see SubModule
065 * @see RegistryBuilder#add(String)
066 */
067 public static void addDefaultModules(RegistryBuilder builder)
068 {
069 try
070 {
071 Enumeration<URL> urls = builder.getClassLoader().getResources("META-INF/MANIFEST.MF");
072
073 while (urls.hasMoreElements())
074 {
075 URL url = urls.nextElement();
076
077 addModulesInManifest(builder, url);
078 }
079
080 addModulesInList(builder, System.getProperty("tapestry.modules"));
081
082 }
083 catch (IOException ex)
084 {
085 throw new RuntimeException(ex.getMessage(), ex);
086 }
087 }
088
089 private static void addModulesInManifest(RegistryBuilder builder, URL url)
090 {
091 InputStream in = null;
092
093 Throwable fail = null;
094
095 try
096 {
097 in = url.openStream();
098
099 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 }