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    }