1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.i18nsystem;
35
36 import java.lang.reflect.AnnotatedElement;
37 import java.lang.reflect.Field;
38 import java.lang.reflect.InvocationTargetException;
39 import java.lang.reflect.Method;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.Set;
45
46 import org.apache.commons.lang3.StringUtils;
47 import org.reflections.ReflectionUtils;
48
49 import com.google.common.base.Function;
50 import com.google.common.base.Predicate;
51 import com.google.common.collect.Lists;
52
53
54
55
56
57
58
59
60 public abstract class AbstractI18nKeyGenerator<T> implements I18nKeyGenerator<T> {
61
62
63
64
65
66 @Override
67 public String[] keysFor(String undecoratedResult, T object, AnnotatedElement el) {
68 final List<String> keys = new ArrayList<String>();
69 keysFor(keys, object, el);
70 if (undecoratedResult != null) {
71 keys.add(0, undecoratedResult);
72 }
73 return keys.toArray(new String[keys.size()]);
74 }
75
76 @Override
77 public String messageBundleNameFor(T object) {
78 return resolveMessageBundleNameUpwards(object);
79 }
80
81
82
83
84 protected String resolveMessageBundleNameUpwards(Object object) {
85 String bundleName = null;
86
87 try {
88 Method getI18nBasename = object.getClass().getMethod("getI18nBasename");
89 bundleName = (String) getI18nBasename.invoke(object);
90 } catch (NoSuchMethodException e) {
91
92 } catch (SecurityException e) {
93 throw new RuntimeException(e);
94 } catch (IllegalArgumentException e) {
95 throw new RuntimeException(e);
96 } catch (IllegalAccessException e) {
97 throw new RuntimeException(e);
98 } catch (InvocationTargetException e) {
99 throw new RuntimeException(e);
100 }
101
102 if (bundleName == null) {
103 Object parent = getParentViaCast(object);
104 if (parent != null) {
105 bundleName = resolveMessageBundleNameUpwards(parent);
106 }
107 }
108
109 return bundleName;
110 }
111
112 protected abstract void keysFor(List<String> keys, T object, AnnotatedElement el);
113
114
115
116
117 protected String fieldOrGetterName(AnnotatedElement el) {
118 if (el instanceof Field) {
119 return ((Field) el).getName();
120 } else if (el instanceof Method) {
121 return getterToField((Method) el);
122 } else {
123 throw new IllegalArgumentException("Can't derive i18n key suffix from " + el);
124 }
125 }
126
127
128
129
130
131 protected <P, C> P getParentViaCast(C obj) {
132 if (!I18nParentable.class.isInstance(obj)) {
133 throw new IllegalStateException("Can't reach parent of " + obj);
134 }
135 final I18nParentable<P> cast = I18nParentable.class.cast(obj);
136 return cast.getI18nContextParent();
137 }
138
139
140
141
142
143
144
145 protected <C> List<Object> getAncestors(C obj) {
146 final ArrayList<Object> ancestors = new ArrayList<Object>();
147 Object p = getParentViaCast(obj);
148 while (p != null) {
149 ancestors.add(p);
150 p = getParentViaCast(p);
151 }
152 return ancestors;
153 }
154
155
156
157
158
159
160 protected <C> Object getRoot(C obj) {
161 Object root = null;
162 Object p = getParentViaCast(obj);
163 while (p != null) {
164 root = p;
165 p = getParentViaCast(p);
166 }
167 return root;
168 }
169
170
171
172
173
174
175 protected <C> List<I18nKeyGenerator> getAncestorKeyGenerators(C obj) {
176 return Lists.transform(getAncestors(obj), new Function<Object, I18nKeyGenerator>() {
177 @Override
178 public I18nKeyGenerator apply(Object input) {
179 return getKeyGenerator(input);
180 }
181 });
182 }
183
184
185
186
187
188
189 protected <C> I18nKeyGenerator getRootKeyGenerator(C obj) {
190 return getKeyGenerator(getRoot(obj));
191 }
192
193
194
195
196 protected <P> I18nKeyGenerator<P> getKeyGenerator(P obj) {
197 return I18nKeyGeneratorFactory.newKeyGeneratorFor(obj);
198 }
199
200
201
202
203
204
205 protected void addKey(List<String> keys, String... parts) {
206 keys.add(keyify(parts));
207 if ("label".equals(parts[parts.length - 1])) {
208 keys.add(keyify(Arrays.copyOfRange(parts, 0, parts.length - 1)));
209 }
210 }
211
212
213
214
215 protected String keyify(String... parts) {
216 return StringUtils.join(parts, '.');
217 }
218
219
220
221
222
223
224 protected String getIdOrNameForUnknownRoot(Object obj) {
225
226 final Object root = getParentViaCast(obj) != null ? getRoot(obj) : obj;
227 @SuppressWarnings("unchecked")
228 final Set<Method> methods = ReflectionUtils.getMethods(root.getClass(), new Predicate<Method>() {
229
230 @Override
231 public boolean apply(Method input) {
232 if ("getId".equals(input.getName()) || "getName".equals(input.getName())) {
233 return true;
234 }
235 return false;
236 }
237 });
238
239 try {
240 String idOrName = null;
241 Iterator<Method> iterator = methods.iterator();
242
243 while (iterator.hasNext()) {
244 idOrName = (String) iterator.next().invoke(root);
245 if (StringUtils.isNotBlank(idOrName)) {
246 return idOrName.replaceAll(":", ".").replaceAll("/", ".");
247 }
248 }
249 return null;
250
251 } catch (IllegalArgumentException e) {
252 throw new RuntimeException(e);
253 } catch (IllegalAccessException e) {
254 throw new RuntimeException(e);
255 } catch (InvocationTargetException e) {
256 throw new RuntimeException(e);
257 }
258 }
259
260
261
262
263 private String getterToField(Method method) {
264 final String methodName = method.getName();
265 if (methodName.startsWith("get")) {
266 return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
267 } else {
268 throw new IllegalArgumentException(method + " is not a getter method");
269 }
270 }
271
272 }