1. Project Clover database Fri Apr 29 2016 13:24:33 CEST
  2. Package info.magnolia.module.blossom.context

File ObservedBeanFactoryBean.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

4
28
13
1
248
162
16
0.57
2.15
13
1.23
41.6% of code in this file is excluded from these metrics.

Classes

Class Line # Actions
ObservedBeanFactoryBean 79 28 41.6% 16 2
0.9555555695.6%
 

Contributing tests

This file is covered by 3 tests. .

Source view

1    /**
2    * This file Copyright (c) 2010-2016 Magnolia International
3    * Ltd. (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10    * This file is distributed in the hope that it will be
11    * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12    * implied warranty of MERCHANTABILITY or FITNESS FOR A
13    * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14    * Redistribution, except as permitted by whichever of the GPL
15    * or MNA you select, is prohibited.
16    *
17    * 1. For the GPL license (GPL), you can redistribute and/or
18    * modify this file under the terms of the GNU General
19    * Public License, Version 3, as published by the Free Software
20    * Foundation. You should have received a copy of the GNU
21    * General Public License, Version 3 along with this program;
22    * if not, write to the Free Software Foundation, Inc., 51
23    * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24    *
25    * 2. For the Magnolia Network Agreement (MNA), this file
26    * and the accompanying materials are made available under the
27    * terms of the MNA which accompanies this distribution, and
28    * is available at http://www.magnolia-cms.com/mna.html
29    *
30    * Any modifications to this file must keep this entire header
31    * intact.
32    *
33    */
34    package info.magnolia.module.blossom.context;
35   
36    import javax.jcr.Node;
37    import javax.jcr.RepositoryException;
38    import javax.jcr.observation.EventIterator;
39    import javax.jcr.observation.EventListener;
40   
41    import org.slf4j.Logger;
42    import org.slf4j.LoggerFactory;
43    import org.springframework.aop.TargetSource;
44    import org.springframework.aop.framework.ProxyFactoryBean;
45    import org.springframework.beans.factory.BeanFactory;
46    import org.springframework.beans.factory.BeanFactoryAware;
47    import org.springframework.beans.factory.BeanNameAware;
48    import org.springframework.beans.factory.DisposableBean;
49    import org.springframework.beans.factory.InitializingBean;
50    import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
51    import org.springframework.context.ApplicationContext;
52    import org.springframework.context.ApplicationContextAware;
53    import org.springframework.context.ApplicationEventPublisher;
54    import org.springframework.context.ApplicationEventPublisherAware;
55   
56    import info.magnolia.cms.util.ObservationUtil;
57    import info.magnolia.context.SystemContext;
58    import info.magnolia.jcr.node2bean.Node2BeanException;
59    import info.magnolia.jcr.node2bean.Node2BeanProcessor;
60    import info.magnolia.module.blossom.node2bean.SpringNode2BeanTransformer;
61    import info.magnolia.module.blossom.support.BeanFactoryUtils;
62    import info.magnolia.objectfactory.Components;
63    import info.magnolia.repository.RepositoryConstants;
64   
65    /**
66    * FactoryBean that creates a bean and populates its properties with values from the repository and reloads the bean
67    * automatically when the repository is updated.
68    *
69    * The returned instance is a proxy that delegates calls to the instance created from the repository. The instance
70    * delegated to is transparently swapped. The proxy is by default a JDK dynamic proxy proxying all the objects
71    * interfaces. This can be changed to a cglib proxy by setting the property proxyTargetClass to true.
72    *
73    * There is a delay mechanism in place that aggregates events in order to postpone reloading while the repository is
74    * being updated. By default any change postpones reloading by 15 seconds but no longer than 60 seconds. These values
75    * can be configured.
76    *
77    * @since 1.2
78    */
 
79    public class ObservedBeanFactoryBean extends ProxyFactoryBean implements InitializingBean, BeanNameAware, ApplicationContextAware, BeanFactoryAware, EventListener, DisposableBean, ApplicationEventPublisherAware {
80   
81    private static final Logger logger = LoggerFactory.getLogger(ObservedBeanFactoryBean.class);
82   
83    private static final String DEFAULT_WORKSPACE = RepositoryConstants.CONFIG;
84    private static final int DEFAULT_MAX_DELAY = 60000;
85    private static final int DEFAULT_DELAY = 15000;
86   
87    private ApplicationContext applicationContext;
88    private ApplicationEventPublisher applicationEventPublisher;
89    private AbstractAutowireCapableBeanFactory beanFactory;
90    private String beanName;
91    private String workspace = DEFAULT_WORKSPACE;
92    private String path;
93    private int maxObservationDelay = DEFAULT_MAX_DELAY;
94    private int observationDelay = DEFAULT_DELAY;
95    private Class<?> defaultClass;
96   
97    private volatile Object target;
98   
 
99  3 toggle public ObservedBeanFactoryBean() {
100  3 super.setSingleton(true);
101   
102  3 super.setTargetSource(new TargetSource() {
103   
 
104  18 toggle @Override
105    public Class<?> getTargetClass() {
106  18 Object local = target;
107  18 return local != null ? local.getClass() : null;
108    }
109   
 
110    toggle @Override
111    public boolean isStatic() {
112    return false;
113    }
114   
 
115    toggle @Override
116    public Object getTarget() throws Exception {
117    return target;
118    }
119   
 
120  17 toggle @Override
121    public void releaseTarget(Object target) throws Exception {
122    }
123    });
124    }
125   
 
126    toggle public Class<?> getDefaultClass() {
127    return defaultClass;
128    }
129   
 
130    toggle public void setDefaultClass(Class<?> defaultClass) {
131    this.defaultClass = defaultClass;
132    }
133   
 
134    toggle @Deprecated
135    public String getRepository() {
136    return workspace;
137    }
138   
 
139    toggle @Deprecated
140    public void setRepository(String repository) {
141    this.workspace = repository;
142    }
143   
 
144    toggle public String getWorkspace() {
145    return workspace;
146    }
147   
 
148    toggle public void setWorkspace(String workspace) {
149    this.workspace = workspace;
150    }
151   
 
152    toggle public String getPath() {
153    return path;
154    }
155   
 
156    toggle public void setPath(String path) {
157    this.path = path;
158    }
159   
 
160    toggle public void setMaxObservationDelay(int maxObservationDelay) {
161    this.maxObservationDelay = maxObservationDelay;
162    }
163   
 
164    toggle public void setObservationDelay(int observationDelay) {
165    this.observationDelay = observationDelay;
166    }
167   
 
168  3 toggle @Override
169    public void afterPropertiesSet() throws Exception {
170  3 this.target = createInstance();
171  3 startObservation();
172    }
173   
 
174  1 toggle @Override
175    public void destroy() throws Exception {
176  1 stopObservation();
177  1 Object instance = target;
178  1 target = null;
179  1 destroyInstance(instance);
180    }
181   
 
182  1 toggle @Override
183    public void onEvent(EventIterator events) {
184  1 try {
185  1 reloadInstance();
186    } catch (Exception e) {
187  0 logger.error("Failed to reload observed bean [" + beanName + "] configured at path [" + path + "] in workspace [" + workspace + "] on change event", e);
188    }
189    }
190   
 
191    toggle @Override
192    public void setApplicationContext(ApplicationContext applicationContext) {
193    this.applicationContext = applicationContext;
194    }
195   
 
196    toggle @Override
197    public void setBeanFactory(BeanFactory beanFactory) {
198    this.beanFactory = (AbstractAutowireCapableBeanFactory) beanFactory;
199    }
200   
 
201    toggle @Override
202    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
203    this.applicationEventPublisher = applicationEventPublisher;
204    }
205   
 
206    toggle @Override
207    public void setBeanName(String beanName) {
208    this.beanName = beanName;
209    }
210   
 
211  4 toggle protected Object createInstance() throws Node2BeanException, RepositoryException {
212  4 Node node = getConfigurationNode();
213  4 return transformNode(node);
214    }
215   
 
216  2 toggle protected void destroyInstance(Object instance) {
217  2 if (instance != null) {
218  2 BeanFactoryUtils.destroyBean(instance, beanName, beanFactory);
219    }
220    }
221   
 
222  1 toggle protected synchronized void reloadInstance() throws Node2BeanException, RepositoryException {
223  1 Object previousInstance = this.target;
224  1 this.target = createInstance();
225  1 destroyInstance(previousInstance);
226   
227  1 applicationEventPublisher.publishEvent(new ObservedBeanReloadedEvent(applicationContext, target, beanName, workspace, path));
228    }
229   
 
230  4 toggle protected Object transformNode(Node node) throws Node2BeanException, RepositoryException {
231  4 SpringNode2BeanTransformer transformer = new SpringNode2BeanTransformer(beanFactory);
232  4 transformer.setTopLevelBeanName(beanName);
233  4 transformer.setDefaultClass(defaultClass);
234  4 return Components.getComponent(Node2BeanProcessor.class).toBean(node, true, transformer, Components.getComponentProvider());
235    }
236   
 
237  4 toggle protected Node getConfigurationNode() throws RepositoryException {
238  4 return Components.getComponent(SystemContext.class).getJCRSession(workspace).getNode(path);
239    }
240   
 
241  3 toggle protected void startObservation() {
242  3 ObservationUtil.registerDeferredChangeListener(workspace, path, this, observationDelay, maxObservationDelay);
243    }
244   
 
245  1 toggle protected void stopObservation() {
246  1 ObservationUtil.unregisterChangeListener(workspace, this);
247    }
248    }