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