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.proxytoys;
35
36 import com.thoughtworks.proxy.ProxyFactory;
37 import com.thoughtworks.proxy.toys.decorate.Decorator;
38 import info.magnolia.i18nsystem.I18nable;
39 import info.magnolia.i18nsystem.I18nKeyGenerator;
40 import info.magnolia.i18nsystem.I18nKeyGeneratorFactory;
41 import info.magnolia.i18nsystem.I18nParentable;
42 import info.magnolia.i18nsystem.I18nText;
43 import info.magnolia.i18nsystem.I18nizer;
44 import info.magnolia.i18nsystem.LocaleProvider;
45 import info.magnolia.i18nsystem.TranslationService;
46
47 import javax.inject.Inject;
48
49 import net.sf.cglib.proxy.Enhancer;
50
51 import com.thoughtworks.proxy.factory.CglibProxyFactory;
52 import com.thoughtworks.proxy.toys.decorate.Decorating;
53 import com.thoughtworks.proxy.toys.dispatch.Dispatching;
54
55
56
57
58
59 public class ProxytoysI18nizer implements I18nizer {
60 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ProxytoysI18nizer.class);
61
62 private final TranslationService translationService;
63 private final LocaleProvider localeProvider;
64 private final ProxyFactory proxyFactory;
65
66 @Inject
67 public ProxytoysI18nizer(TranslationService translationService, LocaleProvider localeProvider) {
68 this.translationService = translationService;
69 this.localeProvider = localeProvider;
70 this.proxyFactory = new CglibProxyFactory(false);
71 }
72
73 @Override
74 public <C> C decorate(C child) {
75 if (child == null) {
76 return null;
77 }
78
79
80 if (Enhancer.isEnhanced(child.getClass())) {
81 throw new IllegalStateException(child + " has already been enhanced (presumably by ProxytoysI18nizer)");
82 }
83
84 return decorateChild(child, null);
85 }
86
87 protected <P, C> C decorateChild(C child, P parent) {
88 log.debug("About to decorate {} (parent: {})", child, parent);
89 if (child == null) {
90 return null;
91 }
92 if (child instanceof I18nParentable) {
93 log.debug(" - " + child + " is already an instance of I18nParentable - probably because we're in a list. Assuming it's also already decorated with i18n.");
94 return child;
95 }
96
97 final Class<C> originalClass = (Class<C>) child.getClass();
98 final C parentedChild = injectParentableInterface(originalClass, child, parent);
99
100 final C i18nd = (C) decorateI18nTextMethods(parentedChild, (Class<Object>) originalClass, I18nParentable.class);
101 return interceptGetters(i18nd, originalClass);
102 }
103
104 protected <T, P> T injectParentableInterface(Class<? extends T> ct, T object, P parent) {
105 final I18nParentableImpl<P> parentable = new I18nParentableImpl<P>(parent);
106 return Dispatching.proxy(ct, I18nParentable.class)
107 .with(object, parentable)
108 .build(proxyFactory);
109 }
110
111 protected <T> T decorateI18nTextMethods(T obj, Class<T> proxyPrimaryType, Class... proxyMoreTypes) {
112 final I18nKeyGenerator<T> keyGen = I18nKeyGeneratorFactory.newKeyGeneratorFor(obj);
113 final I18nTextMethodDecorator<T> decorator = newI18nTextMethodDecorator(keyGen);
114
115 return decorateI18nTextMethods(obj, proxyPrimaryType, proxyMoreTypes, decorator);
116 }
117
118 protected <T> I18nTextMethodDecorator<T> newI18nTextMethodDecorator(I18nKeyGenerator<T> keyGen) {
119 return new I18nTextMethodDecorator<T>(translationService, localeProvider, keyGen);
120 }
121
122 protected <T> T decorateI18nTextMethods(T obj, Class<T> proxyPrimaryType, Class[] proxyMoreTypes, Decorator<T> decorator) {
123 return Decorating.proxy(proxyPrimaryType, proxyMoreTypes)
124 .with(obj)
125 .visiting(new FilteringMethodDecorator<T>(decorator, new MethodsAnnotatedWith(I18nText.class)))
126 .build(proxyFactory);
127 }
128
129 protected <T> T interceptGetters(T o, Class<T> originalClass) {
130 final T proxy = Decorating.proxy(originalClass, new Class[] { I18nParentable.class })
131 .with(o)
132 .visiting(new FilteringMethodDecorator<T>(new ChildDecorator<T>(this), new ReturnsAnnotatedTypeArgument(I18nable.class)))
133 .build(proxyFactory);
134 log.debug("Proxied {} (and returning {})", o, proxy);
135 return proxy;
136 }
137
138 }