001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.util; 005 006 import java.io.IOException; 007 import java.io.InputStream; 008 import java.util.ArrayList; 009 import java.util.Collection; 010 import java.util.Iterator; 011 import java.util.Locale; 012 import java.util.Map; 013 import java.util.Properties; 014 015 import biz.hammurapi.config.ConfigurationException; 016 import biz.hammurapi.config.Context; 017 import biz.hammurapi.config.DomConfigFactory; 018 import biz.hammurapi.config.RuntimeConfigurationException; 019 020 /** 021 * Utility class which searches class hierarchy for a resource. 022 * Resource shall be named after class name, profile name is separated from 023 * class name by ! and locale separated from class name/profile by _. 024 * @author Pavel Vlasov 025 * @revision $Revision$ 026 */ 027 public class ClassResourceLoader { 028 private Visitable visitable; 029 private Class clazz; 030 031 /** 032 * 033 */ 034 public ClassResourceLoader(Class clazz) { 035 this.visitable=new ClassHierarchyVisitable(clazz); 036 this.clazz=clazz; 037 } 038 039 /** 040 * 041 * @param profile Profile, can be null 042 * @param extension Extension, can be null 043 * @return 044 */ 045 public InputStream getResourceAsStream(String profile, String extension) { 046 return getResourceAsStream(profile, Locale.getDefault(), extension); 047 } 048 049 /** 050 * @param profile 051 * @param extension 052 * @return 053 */ 054 public InputStream getResourceAsStream(final String profile, final Locale locale, final String extension) { 055 final InputStream[] ret={null}; 056 visitable.accept(new Visitor() { 057 Locale actualLocale = locale==null ? Locale.getDefault() : locale; 058 059 public boolean visit(Object target) { 060 Class currentClass=(Class) target; 061 for (int i=0; i<4; i++) { 062 String variant=currentClass.getName().replace('.','/'); 063 if (profile!=null) { 064 variant+="!"+profile; 065 } 066 067 switch (i) { 068 case 0: 069 variant+="_"+actualLocale; 070 break; 071 case 1: 072 variant+="_"+actualLocale.getLanguage(); 073 if (actualLocale.getCountry().length()!=0) { 074 variant+="_"+actualLocale.getCountry(); 075 } 076 break; 077 case 2: 078 variant+="_"+actualLocale.getLanguage(); 079 break; 080 case 3: 081 break; 082 } 083 084 if (extension!=null) { 085 variant+="."+extension; 086 } 087 088 089 ret[0]=clazz.getClassLoader().getResourceAsStream(variant); 090 if (ret[0]!=null) { 091 return false; 092 } 093 } 094 095 return true; 096 } 097 098 }); 099 100 return ret[0]; 101 } 102 103 /** 104 * 105 * @param profile Profile, can be null 106 * @param extension Extension, can be null 107 * @return 108 */ 109 public Properties getProperties(String profile, String extension) { 110 return getProperties(profile, Locale.getDefault(), extension); 111 } 112 113 /** 114 * @param profile 115 * @param extension 116 * @return 117 */ 118 public Properties getProperties(final String profile, final Locale locale, final String extension) { 119 final Properties ret=new Properties(); 120 visitable.accept(new Visitor() { 121 122 public boolean visit(Object target) { 123 Class currentClass=(Class) target; 124 for (int i=0; i<4; i++) { 125 String variant=currentClass.getName().replace('.','/'); 126 if (profile!=null) { 127 variant+=profile; 128 } 129 130 switch (i) { 131 case 0: 132 variant+="_"+locale; 133 break; 134 case 1: 135 variant+="_"+locale.getLanguage(); 136 if (locale.getCountry().length()!=0) { 137 variant+="_"+locale.getCountry(); 138 } 139 break; 140 case 2: 141 variant+="_"+locale.getLanguage(); 142 break; 143 case 3: 144 break; 145 } 146 147 if (extension!=null) { 148 variant+="."+extension; 149 } 150 151 152 InputStream s=clazz.getClassLoader().getResourceAsStream(variant); 153 if (s!=null) { 154 Properties cp=new Properties(); 155 try { 156 cp.load(s); 157 Iterator it=cp.entrySet().iterator(); 158 while (it.hasNext()) { 159 Map.Entry entry=(Map.Entry) it.next(); 160 if (!ret.containsKey(entry.getKey())) { 161 ret.setProperty((String) entry.getKey(), (String) entry.getValue()); 162 } 163 } 164 } catch (IOException e) { 165 throw new RuntimeConfigurationException("Cannot load properties from resource "+variant, e); 166 } 167 168 break; 169 } 170 } 171 172 173 return true; 174 } 175 176 }); 177 178 return ret; 179 } 180 181 /** 182 * @param profile 183 * @param extension 184 * @return 185 */ 186 public Context getContext(final String profile, Locale locale, final String extension) { 187 final Locale actualLocale = locale==null ? Locale.getDefault() : locale; 188 final Collection contexts=new ArrayList(); 189 final DomConfigFactory dcf=new DomConfigFactory(); 190 visitable.accept(new Visitor() { 191 192 public boolean visit(Object target) { 193 Class currentClass=(Class) target; 194 for (int i=0; i<4; i++) { 195 String variant=currentClass.getName().replace('.','/'); 196 if (profile!=null) { 197 variant+=profile; 198 } 199 200 switch (i) { 201 case 0: 202 variant+="_"+actualLocale; 203 break; 204 case 1: 205 variant+="_"+actualLocale.getLanguage(); 206 if (actualLocale.getCountry().length()!=0) { 207 variant+="_"+actualLocale.getCountry(); 208 } 209 break; 210 case 2: 211 variant+="_"+actualLocale.getLanguage(); 212 break; 213 case 3: 214 break; 215 } 216 217 if (extension!=null) { 218 variant+="."+extension; 219 } 220 221 222 InputStream s=clazz.getClassLoader().getResourceAsStream(variant); 223 if (s!=null) { 224 try { 225 contexts.add(dcf.create(s, null)); 226 } catch (ConfigurationException e) { 227 throw new RuntimeConfigurationException(e); 228 } catch (IOException e) { 229 throw new RuntimeConfigurationException(e); 230 } 231 break; 232 } 233 } 234 235 return true; 236 } 237 238 }); 239 240 return contexts.isEmpty() ? null : new Context() { 241 242 public Object get(String name) { 243 Iterator it=contexts.iterator(); 244 while (it.hasNext()) { 245 Object ret=((Context) it.next()).get(name); 246 if (ret!=null) { 247 return ret; 248 } 249 } 250 return null; 251 } 252 253 }; 254 } 255 }