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.security.SilentSessionOp;
38 import info.magnolia.cms.util.ContentUtil;
39 import info.magnolia.cms.util.ObservationUtil;
40 import info.magnolia.context.MgnlContext;
41 import info.magnolia.jcr.node2bean.Node2BeanException;
42 import info.magnolia.jcr.node2bean.Node2BeanProcessor;
43 import info.magnolia.jcr.node2bean.Node2BeanTransformer;
44 import info.magnolia.jcr.node2bean.impl.Node2BeanTransformerImpl;
45
46 import javax.jcr.Node;
47 import javax.jcr.RepositoryException;
48 import javax.jcr.Session;
49 import javax.jcr.observation.EventIterator;
50 import javax.jcr.observation.EventListener;
51
52 import org.apache.commons.proxy.ObjectProvider;
53 import org.apache.commons.proxy.factory.cglib.CglibProxyFactory;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58
59
60
61
62
63
64 public class ObservedComponentFactory<T> implements ComponentFactory<T>, EventListener {
65 private static final Logger log = LoggerFactory.getLogger(ObservedComponentFactory.class);
66
67 private static final int DEFAULT_MAX_DELAY = 5000;
68 private static final int DEFAULT_DELAY = 1000;
69
70
71
72
73 private final String repository;
74
75
76
77
78 private final String path;
79
80
81
82
83
84 @Deprecated
85 protected final Class<T> interf;
86
87
88
89
90
91 @Deprecated
92 protected T observedObject;
93
94 private ComponentProvider componentProvider;
95
96 public ObservedComponentFactory(String repository, String path, Class<T> type) {
97 this(repository, path, type, Components.getComponentProvider());
98 }
99
100 public ObservedComponentFactory(String repository, String path, Class<T> type, ComponentProvider componentProvider) {
101 this.repository = repository;
102 this.path = path;
103 this.interf = type;
104 this.componentProvider = componentProvider;
105 load();
106 startObservation(path);
107 }
108
109 @Override
110 @SuppressWarnings("unchecked")
111
112 public T newInstance() {
113 if (getObservedObject() == null) {
114
115
116 log.warn("An instance of {} couldn't be loaded from {}:{} yet, returning null.", new Object[]{interf, repository, path});
117 return null;
118 }
119
120 return (T) new CglibProxyFactory().createDelegatorProxy(new ObjectProvider() {
121 @Override
122 public Object getObject() {
123 return getObservedObject();
124 }
125 }, new Class[]{
126
127 getObservedObject().getClass()
128 });
129 }
130
131 protected void startObservation(String handle) {
132 ObservationUtil.registerDeferredChangeListener(repository, handle, this, DEFAULT_DELAY, DEFAULT_MAX_DELAY);
133 }
134
135 @Override
136 public void onEvent(EventIterator events) {
137 reload();
138 }
139
140 protected void reload() {
141 load();
142 }
143
144 protected void load() {
145 MgnlContext.doInSystemContext(new SilentSessionOp<Void>(repository) {
146
147 @Override
148 public Void doExec(Session session) throws RepositoryException {
149 session = MgnlContext.getJCRSession(session.getWorkspace().getName());
150 if (session.nodeExists(path)) {
151 try {
152
153 final Node node = session.getNode(path);
154 onRegister(ContentUtil.asContent(node));
155 } catch (RepositoryException e) {
156 log.error("Can't read configuration for " + interf + " from [" + repository + ":" + path + "], will return null.", e);
157 }
158 } else {
159 log.debug("{} does not exist, will return a default implementation for {}.", path, interf);
160 instantiateDefault();
161 }
162 return null;
163 }
164
165 @Override
166 public String toString() {
167 return " load repository [" + repository + "] path [" + path + "].";
168 }
169 });
170 }
171
172 protected void instantiateDefault() {
173 if (Classes.isConcrete(interf)) {
174 log.info("{} does not exist, will return a new instance of {}.", path, interf);
175 final ClassFactory classFactory = Classes.getClassFactory();
176 this.observedObject = classFactory.newInstance(interf);
177 } else {
178 log.warn("{} does not exist, default implementation for {} is unknown, will return null.", path, interf);
179 }
180 }
181
182
183
184
185 @Deprecated
186 protected boolean isConcrete(Class<?> clazz) {
187 return Classes.isConcrete(clazz);
188 }
189
190
191
192
193 @Deprecated
194 protected void onRegister(Content node) {
195 try {
196 Node n = node.getJCRNode();
197 final T instance = transformNode(n);
198
199 if (this.observedObject != null) {
200 log.info("Re-loaded {} from {}", interf.getName(), node.getHandle());
201 } else {
202 log.debug("Loading {} from {}", interf.getName(), node.getHandle());
203 }
204 this.observedObject = instance;
205
206 } catch (Exception e) {
207 log.error("Can't transform [" + repository + ":" + path + "] to " + interf, e);
208 }
209 }
210
211 protected T transformNode(Node node) throws Node2BeanException, RepositoryException {
212 return (T) Components.getComponent(Node2BeanProcessor.class).toBean(node, true, getNode2BeanTransformer(), componentProvider);
213 }
214
215 protected Node2BeanTransformer getNode2BeanTransformer() {
216 return new Node2BeanTransformerImpl();
217 }
218
219 protected Class<T> getComponentType() {
220 return interf;
221 }
222
223
224
225
226
227
228
229
230 @Deprecated
231 public T getObservedObject() {
232 return this.observedObject;
233 }
234
235 @Override
236 public String toString() {
237 return super.toString() + ":" + interf + "(Observing: " + repository + ":" + path + ")";
238 }
239 }