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.objectfactory;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.HierarchyManager;
38 import info.magnolia.cms.util.ObservationUtil;
39 import info.magnolia.content2bean.Content2BeanException;
40 import info.magnolia.content2bean.Content2BeanTransformer;
41 import info.magnolia.content2bean.Content2BeanUtil;
42 import info.magnolia.content2bean.TransformationState;
43 import info.magnolia.content2bean.impl.Content2BeanTransformerImpl;
44 import info.magnolia.context.MgnlContext;
45 import org.apache.commons.proxy.ObjectProvider;
46 import org.apache.commons.proxy.factory.cglib.CglibProxyFactory;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import javax.jcr.RepositoryException;
51 import javax.jcr.observation.EventIterator;
52 import javax.jcr.observation.EventListener;
53 import java.lang.reflect.Modifier;
54 import java.util.Map;
55
56
57
58
59
60
61
62
63 public class ObservedComponentFactory<T> implements ComponentFactory<T>, EventListener {
64 private static final Logger log = LoggerFactory.getLogger(ObservedComponentFactory.class);
65
66 private static final int DEFAULT_MAX_DELAY = 5000;
67 private static final int DEFAULT_DELAY = 1000;
68
69
70
71
72 private final String repository;
73
74
75
76
77 private final String path;
78
79
80
81
82
83 protected final Class<T> interf;
84
85
86
87
88
89 protected T observedObject;
90
91 public ObservedComponentFactory(String repository, String path, Class<T> type) {
92 this.repository = repository;
93 this.path = path;
94 this.interf = type;
95 load();
96 startObservation(path);
97 }
98
99 @SuppressWarnings("unchecked")
100 public T newInstance() {
101 if (getObservedObject() == null) {
102
103
104 log.warn("An instance of {} couldn't be loaded from {}:{} yet, returning null.", new Object[]{interf, repository, path});
105 return null;
106 }
107
108 return (T) new CglibProxyFactory().createDelegatorProxy(new ObjectProvider() {
109 public Object getObject() {
110 return getObservedObject();
111 }
112 }, new Class[]{
113
114 getObservedObject().getClass()
115 });
116 }
117
118 protected void startObservation(String handle) {
119 ObservationUtil.registerDeferredChangeListener(repository, handle, this, DEFAULT_DELAY, DEFAULT_MAX_DELAY);
120 }
121
122 public void onEvent(EventIterator events) {
123 reload();
124 }
125
126 protected void reload() {
127 load();
128 }
129
130 protected void load() {
131 final HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(repository);
132 if (hm.isExist(path)) {
133 try {
134 final Content node = hm.getContent(path);
135 onRegister(node);
136 } catch (RepositoryException e) {
137 log.error("Can't read configuration for " + interf + " from [" + repository + ":" + path + "], will return null.", e);
138 }
139 } else {
140 log.debug("{} does not exist, will return a default implementation for {}.", path, interf);
141 instantiateDefault();
142 }
143 }
144
145 protected void instantiateDefault() {
146 if (isConcrete(interf)) {
147 log.info("{} does not exist, will return a new instance of {}.", path, interf);
148 final ClassFactory classFactory = Classes.getClassFactory();
149 this.observedObject = classFactory.newInstance(interf);
150 } else {
151 log.warn("{} does not exist, default implementation for {} is unknown, will return null.", path, interf);
152 }
153 }
154
155 protected boolean isConcrete(Class<?> clazz) {
156 return !Modifier.isAbstract(clazz.getModifiers());
157 }
158
159 protected void onRegister(Content node) {
160 try {
161 final T instance = transformNode(node);
162
163 if (this.observedObject != null) {
164 log.info("Re-loaded {} from {}", interf.getName(), node.getHandle());
165 } else {
166 log.debug("Loading {} from {}", interf.getName(), node.getHandle());
167 }
168 this.observedObject = instance;
169
170 } catch (Content2BeanException e) {
171 log.error("Can't transform [" + repository + ":" + path + "] to " + interf, e);
172 }
173 }
174
175 protected T transformNode(Content node) throws Content2BeanException {
176 return (T) Content2BeanUtil.toBean(node, true, getContent2BeanTransformer());
177 }
178
179 protected Content2BeanTransformer getContent2BeanTransformer() {
180
181 return new Content2BeanTransformerImpl() {
182 public Object newBeanInstance(TransformationState state, Map properties) throws Content2BeanException {
183 if (state.getCurrentType().getType().equals(interf)) {
184 final ClassFactory classFactory = Classes.getClassFactory();
185 return classFactory.newInstance(interf);
186 }
187 return super.newBeanInstance(state, properties);
188 }
189 };
190 }
191
192 protected Class<T> getComponentType() {
193 return interf;
194 }
195
196
197
198
199
200
201
202
203 public T getObservedObject() {
204 return this.observedObject;
205 }
206
207 public String toString() {
208 return super.toString() + ":" + interf + "(Observing: " + repository + ":" + path + ")";
209 }
210 }