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