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 }