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 protected static final String FIELDS = "fields";
63 private static final String LABEL = "label";
64
65
66
67
68
69 @Override
70 public String[] keysFor(String undecoratedResult, T object, AnnotatedElement el) {
71 final List<String> keys = new ArrayList<>();
72 keysFor(keys, object, el);
73 if (undecoratedResult != null) {
74 keys.add(0, undecoratedResult);
75 }
76 return keys.toArray(new String[keys.size()]);
77 }
78
79
80
81
82 @Deprecated
83 @Override
84 public String messageBundleNameFor(T object) {
85 return resolveMessageBundleNameUpwards(object);
86 }
87
88
89
90
91
92 @Deprecated
93 protected String resolveMessageBundleNameUpwards(Object object) {
94 String bundleName = null;
95
96 try {
97 Method getI18nBasename = object.getClass().getMethod("getI18nBasename");
98 bundleName = (String) getI18nBasename.invoke(object);
99 } catch (NoSuchMethodException e) {
100
101 } catch (SecurityException e) {
102 throw new RuntimeException(e);
103 } catch (IllegalArgumentException e) {
104 throw new RuntimeException(e);
105 } catch (IllegalAccessException e) {
106 throw new RuntimeException(e);
107 } catch (InvocationTargetException e) {
108 throw new RuntimeException(e);
109 }
110
111 if (bundleName == null) {
112 Object parent = getParentViaCast(object);
113 if (parent != null) {
114 bundleName = resolveMessageBundleNameUpwards(parent);
115 }
116 }
117
118 return bundleName;
119 }
120
121 protected abstract void keysFor(List<String> keys, T object, AnnotatedElement el);
122
123
124
125
126 protected String fieldOrGetterName(AnnotatedElement el) {
127 if (el instanceof Field) {
128 return ((Field) el).getName();
129 } else if (el instanceof Method) {
130 return getterToField((Method) el);
131 } else {
132 throw new IllegalArgumentException("Can't derive i18n key suffix from " + el);
133 }
134 }
135
136
137
138
139
140 protected <P, C> P getParentViaCast(C obj) {
141 if (!I18nParentable.class.isInstance(obj)) {
142 throw new IllegalStateException("Can't reach parent of " + obj);
143 }
144 final I18nParentable<P> cast = I18nParentable.class.cast(obj);
145 return cast.getI18nContextParent();
146 }
147
148
149
150
151
152
153
154 protected <C> List<Object> getAncestors(C obj) {
155 final ArrayList<Object> ancestors = new ArrayList<Object>();
156 Object p = getParentViaCast(obj);
157 while (p != null) {
158 ancestors.add(p);
159 p = getParentViaCast(p);
160 }
161 return ancestors;
162 }
163
164
165
166
167
168
169 protected <C> Object getRoot(C obj) {
170 Object root = null;
171 Object p = getParentViaCast(obj);
172 while (p != null) {
173 root = p;
174 p = getParentViaCast(p);
175 }
176 return root;
177 }
178
179
180
181
182
183
184 protected <C> List<I18nKeyGenerator> getAncestorKeyGenerators(C obj) {
185 return Lists.transform(getAncestors(obj), new Function<Object, I18nKeyGenerator>() {
186 @Override
187 public I18nKeyGenerator apply(Object input) {
188 return getKeyGenerator(input);
189 }
190 });
191 }
192
193
194
195
196
197
198 protected <C> I18nKeyGenerator getRootKeyGenerator(C obj) {
199 return getKeyGenerator(getRoot(obj));
200 }
201
202
203
204
205 protected <P> I18nKeyGenerator<P> getKeyGenerator(P obj) {
206 return I18nKeyGeneratorFactory.newKeyGeneratorFor(obj);
207 }
208
209
210
211
212
213
214 protected void addKey(List<String> keys, boolean stripLabelSuffix, String... parts) {
215 this.addKey(keys, keyify(parts));
216 if (stripLabelSuffix && LABEL.equals(parts[parts.length - 1])) {
217 this.addKey(keys, keyify(Arrays.copyOfRange(parts, 0, parts.length - 1)));
218 }
219 }
220
221 protected void addKey(List<String> keys, String... parts) {
222 this.addKey(keys, true, parts);
223 }
224
225 private void addKey(List<String> keys, String key) {
226 if (!keys.contains(key)) {
227 keys.add(key);
228 }
229 }
230
231
232
233
234 protected String keyify(String... parts) {
235 return StringUtils.join(parts, '.');
236 }
237
238
239
240
241 protected String keyify(String id) {
242 return StringUtils.replaceChars(id, ":/", "..");
243 }
244
245
246
247
248
249
250 protected String getIdOrNameForUnknownRoot(Object obj, boolean keyify) {
251
252 final Object root = getParentViaCast(obj) != null ? getRoot(obj) : obj;
253 @SuppressWarnings("unchecked")
254 final Set<Method> methods = ReflectionUtils.getMethods(root.getClass(), new Predicate<Method>() {
255
256 @Override
257 public boolean apply(Method input) {
258 if ("getId".equals(input.getName()) || "getName".equals(input.getName())) {
259 return true;
260 }
261 return false;
262 }
263 });
264
265 try {
266 String idOrName = null;
267 Iterator<Method> iterator = methods.iterator();
268
269 while (iterator.hasNext()) {
270 idOrName = (String) iterator.next().invoke(root);
271 if (StringUtils.isNotBlank(idOrName)) {
272 return keyify ? keyify(idOrName) : idOrName;
273 }
274 }
275 return null;
276
277 } catch (IllegalArgumentException e) {
278 throw new RuntimeException(e);
279 } catch (IllegalAccessException e) {
280 throw new RuntimeException(e);
281 } catch (InvocationTargetException e) {
282 throw new RuntimeException(e);
283 }
284 }
285
286 protected String getIdOrNameForUnknownRoot(Object obj) {
287 return getIdOrNameForUnknownRoot(obj, true);
288 }
289
290 protected String getModuleName(String id) {
291 return StringUtils.contains(id, ":") ? StringUtils.substringBefore(id, ":") : null;
292 }
293
294 protected String getIdWithoutModuleName(String id) {
295 return keyify(StringUtils.contains(id, ":") ? StringUtils.substringAfter(id, ":") : id);
296 }
297
298
299
300
301 private String getterToField(Method method) {
302 final String methodName = method.getName();
303 if (methodName.startsWith("get")) {
304 return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
305 } else {
306 throw new IllegalArgumentException(method + " is not a getter method");
307 }
308 }
309
310 }