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 }