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 }