001// Licensed under the Apache License, Version 2.0 (the "License"); 002// you may not use this file except in compliance with the License. 003// You may obtain a copy of the License at 004// 005// http://www.apache.org/licenses/LICENSE-2.0 006// 007// Unless required by applicable law or agreed to in writing, software 008// distributed under the License is distributed on an "AS IS" BASIS, 009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 010// See the License for the specific language governing permissions and 011// limitations under the License. 012 013package org.apache.tapestry5.ioc; 014 015import org.apache.tapestry5.ioc.util.ExceptionUtils; 016 017import java.io.Closeable; 018import java.io.IOException; 019import java.io.InputStream; 020import java.net.URL; 021import java.util.Enumeration; 022import java.util.jar.Manifest; 023 024import static org.apache.tapestry5.ioc.IOCConstants.MODULE_BUILDER_MANIFEST_ENTRY_NAME; 025 026/** 027 * A collection of utility methods for a couple of different areas, including creating the initial {@link 028 * org.apache.tapestry5.ioc.Registry}. 029 */ 030public final class IOCUtilities 031{ 032 private IOCUtilities() 033 { 034 } 035 036 /** 037 * Construct a default Registry, including modules identifed via the Tapestry-Module-Classes Manifest entry. The 038 * registry will have been {@linkplain Registry#performRegistryStartup() started up} before it is returned. 039 * 040 * @return constructed Registry, after startup 041 * @see #addDefaultModules(RegistryBuilder) 042 */ 043 public static Registry buildDefaultRegistry() 044 { 045 RegistryBuilder builder = new RegistryBuilder(); 046 047 addDefaultModules(builder); 048 049 Registry registry = builder.build(); 050 051 registry.performRegistryStartup(); 052 053 return registry; 054 } 055 056 /** 057 * Scans the classpath for JAR Manifests that contain the Tapestry-Module-Classes attribute and adds each 058 * corresponding class to the RegistryBuilder. In addition, looks for a system property named "tapestry.modules" and 059 * adds all of those modules as well. The tapestry.modules approach is intended for development. 060 * 061 * @param builder 062 * the builder to which modules will be added 063 * @see org.apache.tapestry5.ioc.annotations.ImportModule 064 * @see RegistryBuilder#add(String) 065 */ 066 public static void addDefaultModules(RegistryBuilder builder) 067 { 068 try 069 { 070 Enumeration<URL> urls = builder.getClassLoader().getResources("META-INF/MANIFEST.MF"); 071 072 while (urls.hasMoreElements()) 073 { 074 URL url = urls.nextElement(); 075 076 addModulesInManifest(builder, url); 077 } 078 079 addModulesInList(builder, System.getProperty("tapestry.modules")); 080 081 } catch (IOException ex) 082 { 083 throw new RuntimeException(ex.getMessage(), ex); 084 } 085 } 086 087 private static void addModulesInManifest(RegistryBuilder builder, URL url) 088 { 089 InputStream in = null; 090 091 Throwable fail = null; 092 093 try 094 { 095 in = url.openStream(); 096 097 Manifest mf = new Manifest(in); 098 099 in.close(); 100 101 in = null; 102 103 String list = mf.getMainAttributes().getValue(MODULE_BUILDER_MANIFEST_ENTRY_NAME); 104 105 addModulesInList(builder, list); 106 } catch (RuntimeException ex) 107 { 108 fail = ex; 109 } catch (IOException ex) 110 { 111 fail = ex; 112 } finally 113 { 114 close(in); 115 } 116 117 if (fail != null) 118 throw new RuntimeException(String.format("Exception loading module(s) from manifest %s: %s", 119 url.toString(), 120 ExceptionUtils.toMessage(fail)), fail); 121 122 } 123 124 static void addModulesInList(RegistryBuilder builder, String list) 125 { 126 if (list == null) return; 127 128 String[] classnames = list.split(","); 129 130 for (String classname : classnames) 131 { 132 builder.add(classname.trim()); 133 } 134 } 135 136 /** 137 * Closes an input stream (or other Closeable), ignoring any exception. 138 * 139 * @param closeable 140 * the thing to close, or null to close nothing 141 */ 142 private static void close(Closeable closeable) 143 { 144 if (closeable != null) 145 { 146 try 147 { 148 closeable.close(); 149 } catch (IOException ex) 150 { 151 // Ignore. 152 } 153 } 154 } 155}