001/* 002@license.text@ 003 */ 004package com.hammurapi.common; 005 006import java.io.IOException; 007import java.io.InputStream; 008import java.net.URL; 009import java.util.HashMap; 010import java.util.Locale; 011import java.util.Map; 012import java.util.Properties; 013 014import com.hammurapi.convert.ConversionException; 015import com.hammurapi.convert.ConvertingService; 016 017 018public class ResourceLoaderImpl implements ResourceLoader { 019 020 private ResourceSet resourceSet; 021 private String[] resolutionPaths; 022 023 public ResourceLoaderImpl(ResourceSet resourceSet, String... resolutionPaths) { 024 this.resourceSet = resourceSet; 025 this.resolutionPaths = resolutionPaths; 026 } 027 028 /** 029 * 030 * @param profile Profile, can be null 031 * @param extension Extension, can be null 032 * @return 033 */ 034 public InputStream getResourceStream(String scriptName, String extension) { 035 return getResourceStream(scriptName, Locale.getDefault(), extension); 036 } 037 038 @Override 039 public URL getResource(String scriptName, String extension) { 040 return getResource(scriptName, Locale.getDefault(), extension); 041 } 042 043 private enum Variant { 044 LOCALE, LANG_COUNTRY, LANG, GENERIC 045 } 046 047 /** 048 * @param scriptName 049 * @param extension 050 * @return 051 */ 052 public InputStream getResourceStream(final String scriptName, final Locale locale, final String extension) { 053 Locale actualLocale = locale==null ? Locale.getDefault() : locale; 054 for (String path: resolutionPaths) { 055 for (Variant v: Variant.values()) { 056 String variant=path; 057 if (scriptName!=null) { 058 variant+="!"+scriptName; 059 } 060 061 switch (v) { 062 case LOCALE: 063 variant+="_"+actualLocale; 064 break; 065 case LANG_COUNTRY: 066 variant+="_"+actualLocale.getLanguage(); 067 if (actualLocale.getCountry().length()!=0) { 068 variant+="_"+actualLocale.getCountry(); 069 } 070 break; 071 case LANG: 072 variant+="_"+actualLocale.getLanguage(); 073 break; 074 case GENERIC: 075 break; 076 } 077 078 if (extension!=null) { 079 variant+="."+extension; 080 } 081 082 InputStream ret = resourceSet.getResourceStream(variant); 083 if (ret!=null) { 084 return ret; 085 } 086 } 087 } 088 089 return null; 090 } 091 092 /** 093 * @param scriptName 094 * @param extension 095 * @return 096 */ 097 public URL getResource(final String scriptName, final Locale locale, final String extension) { 098 Locale actualLocale = locale==null ? Locale.getDefault() : locale; 099 for (String path: resolutionPaths) { 100 for (Variant v: Variant.values()) { 101 String variant=path; 102 if (scriptName!=null) { 103 variant+="!"+scriptName; 104 } 105 106 switch (v) { 107 case LOCALE: 108 variant+="_"+actualLocale; 109 break; 110 case LANG_COUNTRY: 111 variant+="_"+actualLocale.getLanguage(); 112 if (actualLocale.getCountry().length()!=0) { 113 variant+="_"+actualLocale.getCountry(); 114 } 115 break; 116 case LANG: 117 variant+="_"+actualLocale.getLanguage(); 118 break; 119 case GENERIC: 120 break; 121 } 122 123 if (extension!=null) { 124 variant+="."+extension; 125 } 126 127 URL ret = resourceSet.getResource(variant); 128 if (ret!=null) { 129 return ret; 130 } 131 } 132 } 133 134 return null; 135 } 136 137 /** 138 * Collects properties from class hierarchy. 139 * @param profile Profile, can be null 140 * @param extension Extension, can be null 141 * @return 142 */ 143 public Map<String, Object> getProperties(String profile, String extension) { 144 return getProperties(profile, Locale.getDefault(), extension); 145 } 146 147 /** 148 * Collects properties from class hierarchy. 149 * @param profile 150 * @param extension 151 * @return 152 */ 153 public Map<String, Object> getProperties(final String profile, final Locale locale, final String extension) { 154 return getProperties(profile, locale, extension, Thread.currentThread().getContextClassLoader()); 155 } 156 157 /** 158 * Collects properties from class hierarchy. Property can have type. Type name is enclosed into parenthesis, e.g. 159 * <code>attempts(java.lang.Integer)=33</code>. If property is defined with type then string value of the property is converted to the 160 * target type. If not, property type is String. 161 * @param profile 162 * @param extension 163 * @return 164 */ 165 public Map<String, Object> getProperties(final String profile, final Locale locale, final String extension, ClassLoader classLoader) { 166 Map<String, Object> ret = new HashMap<String, Object>(); 167 Locale actualLocale = locale==null ? Locale.getDefault() : locale; 168 for (String path: resolutionPaths) { 169 for (Variant v: Variant.values()) { 170 String variant=path; 171 if (profile!=null) { 172 variant+="!"+profile; 173 } 174 175 switch (v) { 176 case LOCALE: 177 variant+="_"+actualLocale; 178 break; 179 case LANG_COUNTRY: 180 variant+="_"+actualLocale.getLanguage(); 181 if (actualLocale.getCountry().length()!=0) { 182 variant+="_"+actualLocale.getCountry(); 183 } 184 break; 185 case LANG: 186 variant+="_"+actualLocale.getLanguage(); 187 break; 188 case GENERIC: 189 break; 190 } 191 if (extension!=null) { 192 variant+="."+extension; 193 } 194 195 InputStream s = resourceSet.getResourceStream(variant); 196 if (s!=null) { 197 Properties cp=new Properties(); 198 try { 199 cp.load(s); 200 for (Map.Entry<Object, Object> entry: cp.entrySet()) { 201 String key = (String) entry.getKey(); 202 Object value = entry.getValue(); 203 int idx = key.charAt(key.length()-1)==')' ? key.lastIndexOf('(') : -1; 204 String propertyClassName = null; 205 if (idx>0) { 206 propertyClassName = key.substring(idx+1, key.length()-1); 207 key = key.substring(0, idx); 208 } 209 if (!ret.containsKey(key)) { 210 if (propertyClassName!=null) { 211 try { 212 Class<?> propertyClass = classLoader.loadClass(propertyClassName); 213 value = ConvertingService.convert(value, propertyClass, classLoader); 214 } catch (ClassNotFoundException e) { 215 throw new ConversionException(e); 216 } 217 } 218 ret.put(key, value); 219 } 220 } 221 } catch (IOException e) { 222 throw new RuntimeException("Cannot load properties from resource "+variant, e); 223 } 224 225 break; 226 } 227 } 228 } 229 230 231 return ret; 232 } 233}