001    /*
002    @license.text@
003     */
004    package com.hammurapi.util;
005    
006    import java.io.IOException;
007    import java.io.InputStream;
008    import java.net.URL;
009    import java.util.Locale;
010    import java.util.Map;
011    import java.util.Properties;
012    
013    
014    /**
015     * Utility class which searches class hierarchy for a resource.
016     * Resource shall be named after class name, profile name is separated from
017     * class name by ! and locale separated from class name/profile by _.
018     * @author Pavel Vlasov
019     * @revision $Revision$
020     */
021    public class ClassResourceLoader {
022            private Visitable<Class<?>> visitable;
023            private String prefix;
024            private ClassLoader classLoader;
025            
026            public ClassResourceLoader(Class<?> clazz, String prefix, ClassLoader classLoader) {
027                    this.visitable=new ClassHierarchyVisitable(clazz);
028                    this.classLoader = classLoader==null ? clazz.getClassLoader() : classLoader;
029                    this.prefix = prefix;
030            }
031            
032            /**
033             * 
034             * @param profile Profile, can be null
035             * @param extension Extension, can be null
036             * @return
037             */
038            public URL getResource(String profile, String extension) {
039                    return getResource(profile, Locale.getDefault(), extension);
040            }
041    
042            /**
043             * @param profile
044             * @param extension
045             * @return
046             */
047            public URL getResource(final String profile, final Locale locale, final String extension) {             
048                    final URL[] ret={null};
049                    visitable.accept(new Visitor<Class<?>>() {
050                            Locale actualLocale = locale==null ? Locale.getDefault() : locale;
051    
052                            public boolean visit(Class<?> currentClass) {
053                                    for (int i=0; i<4; i++) {
054                                            String variant=currentClass.getName().replace('.','/');
055                                            if (prefix!=null) {
056                                                    variant = prefix + variant;
057                                            }
058                                            if (profile!=null) {
059                                                    variant+="!"+profile;
060                                            }
061                                            
062                                            switch (i) {
063                                                    case 0:
064                                                            variant+="_"+actualLocale;
065                                                            break;
066                                                    case 1:
067                                                            variant+="_"+actualLocale.getLanguage();
068                                                            if (actualLocale.getCountry().length()!=0) {
069                                                                    variant+="_"+actualLocale.getCountry();
070                                                            }
071                                                            break;
072                                                    case 2:
073                                                            variant+="_"+actualLocale.getLanguage();
074                                                            break;
075                                                    case 3:
076                                                            break;                                                  
077                                            }
078                                            
079                                            if (extension!=null) {
080                                                    variant+="."+extension;
081                                            }
082                                            
083                                            
084                                            ret[0]=classLoader.getResource(variant);
085                                            if (ret[0]!=null) {
086                                                    return false;
087                                            }
088                                    }
089                                                                                                                            
090                                    return true;
091                            }
092                            
093                    });
094                    
095                    return ret[0];
096            }
097    
098            /**
099             * Collects properties from class hierarchy.  
100             * @param profile Profile, can be null
101             * @param extension Extension, can be null
102             * @return
103             */
104            public Properties getProperties(String profile, String extension) {
105                    return getProperties(profile, Locale.getDefault(), extension);
106            }
107    
108            /**
109             * Collects properties from class hierarchy.  
110             * @param profile
111             * @param extension
112             * @return
113             */
114            public Properties getProperties(final String profile, final Locale locale, final String extension) {
115                    final Properties ret=new Properties();
116                    visitable.accept(new Visitor<Class<?>>() {
117    
118                            public boolean visit(Class<?> currentClass) {
119                                    for (int i=0; i<4; i++) {
120                                            String variant=currentClass.getName().replace('.','/');
121                                            if (prefix!=null) {
122                                                    variant = prefix + variant;
123                                            }
124                                            if (profile!=null) {
125                                                    variant+=profile;
126                                            }
127                                            
128                                            switch (i) {
129                                                    case 0:
130                                                            variant+="_"+locale;
131                                                            break;
132                                                    case 1:
133                                                            variant+="_"+locale.getLanguage();
134                                                            if (locale.getCountry().length()!=0) {
135                                                                    variant+="_"+locale.getCountry();
136                                                            }
137                                                            break;
138                                                    case 2:
139                                                            variant+="_"+locale.getLanguage();
140                                                            break;
141                                                    case 3:
142                                                            break;                                                  
143                                            }
144                                            
145                                            if (extension!=null) {
146                                                    variant+="."+extension;
147                                            }
148                                            
149                                            
150                                            InputStream s=classLoader.getResourceAsStream(variant);
151                                            if (s!=null) {
152                                                    Properties cp=new Properties();
153                                                    try {
154                                                            cp.load(s);
155                                                            for (Map.Entry<Object, Object> entry: cp.entrySet()) {
156                                                                    if (!ret.containsKey(entry.getKey())) {
157                                                                            ret.setProperty((String) entry.getKey(), (String) entry.getValue());
158                                                                    }
159                                                            }
160                                                    } catch (IOException e) {
161                                                            throw new RuntimeException("Cannot load properties from resource "+variant, e);
162                                                    }
163                                                    
164                                                    break;
165                                            }
166                                    }
167                                    
168                                                                                            
169                                    return true;
170                            }
171                            
172                    });
173                    
174                    return ret;
175            }
176            
177    }