EMMA Coverage Report (generated Thu Jan 24 13:37:04 CST 2013)
[all classes][org.springframework.batch.core.listener]

COVERAGE SUMMARY FOR SOURCE FILE [AbstractListenerFactoryBean.java]

nameclass, %method, %block, %line, %
AbstractListenerFactoryBean.java100% (1/1)100% (8/8)99%  (302/304)99%  (68/69)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AbstractListenerFactoryBean100% (1/1)100% (8/8)99%  (302/304)99%  (68/69)
isListener (Object, Class, ListenerMetaData []): boolean 100% (1/1)96%  (52/54)92%  (11/12)
AbstractListenerFactoryBean (): void 100% (1/1)100% (3/3)100% (1/1)
afterPropertiesSet (): void 100% (1/1)100% (5/5)100% (2/2)
getMethodInvokerByName (String, Object, Class []): MethodInvoker 100% (1/1)100% (10/10)100% (3/3)
getObject (): Object 100% (1/1)100% (222/222)100% (46/46)
isSingleton (): boolean 100% (1/1)100% (2/2)100% (1/1)
setDelegate (Object): void 100% (1/1)100% (4/4)100% (2/2)
setMetaDataMap (Map): void 100% (1/1)100% (4/4)100% (2/2)

1/*
2 * Copyright 2002-2008 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.springframework.batch.core.listener;
17 
18import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerByAnnotation;
19import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerForInterface;
20 
21import java.util.HashMap;
22import java.util.HashSet;
23import java.util.Map;
24import java.util.Map.Entry;
25import java.util.Set;
26 
27import org.springframework.aop.TargetSource;
28import org.springframework.aop.framework.Advised;
29import org.springframework.aop.framework.ProxyFactory;
30import org.springframework.aop.support.DefaultPointcutAdvisor;
31import org.springframework.batch.support.MethodInvoker;
32import org.springframework.batch.support.MethodInvokerUtils;
33import org.springframework.beans.factory.FactoryBean;
34import org.springframework.beans.factory.InitializingBean;
35import org.springframework.core.Ordered;
36import org.springframework.util.Assert;
37 
38/**
39 * {@link FactoryBean} implementation that builds a listener based on the
40 * various lifecycle methods or annotations that are provided. There are three
41 * possible ways of having a method called as part of a listener lifecycle:
42 * 
43 * <ul>
44 * <li>Interface implementation: By implementing any of the subclasses of a
45 * listener interface, methods on said interface will be called
46 * <li>Annotations: Annotating a method will result in registration.
47 * <li>String name of the method to be called, which is tied to a
48 * {@link ListenerMetaData} value in the metaDataMap.
49 * </ul>
50 * 
51 * It should be noted that methods obtained by name or annotation that don't
52 * match the listener method signatures to which they belong will cause errors.
53 * However, it is acceptable to have no parameters at all. If the same method is
54 * marked in more than one way. (i.e. the method name is given and it is
55 * annotated) the method will only be called once. However, if the same class
56 * has multiple methods tied to a particular listener, each method will be
57 * called. Also note that the same annotations cannot be applied to two separate
58 * methods in a single class.
59 * 
60 * @author Lucas Ward
61 * @author Dan Garrette
62 * @since 2.0
63 * @see ListenerMetaData
64 */
65public abstract class AbstractListenerFactoryBean implements FactoryBean, InitializingBean {
66 
67        private Object delegate;
68 
69        private Map<String, String> metaDataMap;
70 
71        public Object getObject() {
72 
73                if (metaDataMap == null) {
74                        metaDataMap = new HashMap<String, String>();
75                }
76                // Because all annotations and interfaces should be checked for, make
77                // sure that each meta data
78                // entry is represented.
79                for (ListenerMetaData metaData : this.getMetaDataValues()) {
80                        if (!metaDataMap.containsKey(metaData.getPropertyName())) {
81                                // put null so that the annotation and interface is checked
82                                metaDataMap.put(metaData.getPropertyName(), null);
83                        }
84                }
85 
86                Set<Class<?>> listenerInterfaces = new HashSet<Class<?>>();
87 
88                // For every entry in the map, try and find a method by interface, name,
89                // or annotation. If the same
90                Map<String, Set<MethodInvoker>> invokerMap = new HashMap<String, Set<MethodInvoker>>();
91                boolean synthetic = false;
92                for (Entry<String, String> entry : metaDataMap.entrySet()) {
93 
94                        final ListenerMetaData metaData = this.getMetaDataFromPropertyName(entry.getKey());
95                        Set<MethodInvoker> invokers = new HashSet<MethodInvoker>();
96 
97                        MethodInvoker invoker;
98 
99                        invoker = getMethodInvokerForInterface(metaData.getListenerInterface(), metaData.getMethodName(), delegate,
100                                        metaData.getParamTypes());
101                        if (invoker != null) {
102                                invokers.add(invoker);
103                        }
104                        
105                        invoker = getMethodInvokerByName(entry.getValue(), delegate, metaData.getParamTypes());
106                        if (invoker != null) {
107                                invokers.add(invoker);
108                                synthetic = true;
109                        }
110 
111                        invoker = getMethodInvokerByAnnotation(metaData.getAnnotation(), delegate, metaData.getParamTypes());
112                        if (invoker != null) {
113                                invokers.add(invoker);
114                                synthetic = true;
115                        }
116 
117                        if (!invokers.isEmpty()) {
118                                invokerMap.put(metaData.getMethodName(), invokers);
119                                listenerInterfaces.add(metaData.getListenerInterface());
120                        }
121 
122                }
123 
124                if (listenerInterfaces.isEmpty()) {
125                        listenerInterfaces.add(this.getDefaultListenerClass());
126                }
127 
128                if (!synthetic) {
129                        int count = 0;
130                        for (Class<?> listenerInterface : listenerInterfaces) {
131                                if (listenerInterface.isInstance(delegate)) {
132                                        count++;
133                                }
134                        }
135                        // All listeners can be supplied by the delegate itself
136                        if (count == listenerInterfaces.size()) {
137                                return delegate;
138                        }
139                }
140 
141                boolean ordered = false;
142                if (delegate instanceof Ordered) {
143                        ordered = true;
144                        listenerInterfaces.add(Ordered.class);
145                }
146 
147                // create a proxy listener for only the interfaces that have methods to
148                // be called
149                ProxyFactory proxyFactory = new ProxyFactory();
150                if (delegate instanceof Advised) {
151                        proxyFactory.setTargetSource(((Advised) delegate).getTargetSource());
152                }
153                else {
154                        proxyFactory.setTarget(delegate);
155                }
156                proxyFactory.setInterfaces(listenerInterfaces.toArray(new Class[0]));
157                proxyFactory.addAdvisor(new DefaultPointcutAdvisor(new MethodInvokerMethodInterceptor(invokerMap, ordered)));
158                return proxyFactory.getProxy();
159 
160        }
161 
162        protected abstract ListenerMetaData getMetaDataFromPropertyName(String propertyName);
163 
164        protected abstract ListenerMetaData[] getMetaDataValues();
165 
166        protected abstract Class<?> getDefaultListenerClass();
167 
168        protected MethodInvoker getMethodInvokerByName(String methodName, Object candidate, Class<?>... params) {
169                if (methodName != null) {
170                        return MethodInvokerUtils.getMethodInvokerByName(candidate, methodName, false, params);
171                }
172                else {
173                        return null;
174                }
175        }
176 
177        public boolean isSingleton() {
178                return true;
179        }
180 
181        public void setDelegate(Object delegate) {
182                this.delegate = delegate;
183        }
184 
185        public void setMetaDataMap(Map<String, String> metaDataMap) {
186                this.metaDataMap = metaDataMap;
187        }
188 
189        public void afterPropertiesSet() throws Exception {
190                Assert.notNull(delegate, "Delegate must not be null");
191        }
192 
193        /**
194         * Convenience method to check whether the given object is or can be made
195         * into a listener.
196         * 
197         * @param target the object to check
198         * @return true if the delegate is an instance of any of the listener
199         * interface, or contains the marker annotations
200         */
201        public static boolean isListener(Object target, Class<?> listenerType, ListenerMetaData[] metaDataValues) {
202                if (target == null) {
203                        return false;
204                }
205                if (listenerType.isInstance(target)) {
206                        return true;
207                }
208                if (target instanceof Advised) {
209                        TargetSource targetSource = ((Advised) target).getTargetSource();
210                        if (targetSource != null && targetSource.getTargetClass() != null
211                                        && listenerType.isAssignableFrom(targetSource.getTargetClass())) {
212                                return true;
213                        }
214                }
215                for (ListenerMetaData metaData : metaDataValues) {
216                        if (MethodInvokerUtils.getMethodInvokerByAnnotation(metaData.getAnnotation(), target) != null) {
217                                return true;
218                        }
219                }
220                return false;
221        }
222}

[all classes][org.springframework.batch.core.listener]
EMMA 2.0.5312 (C) Vladimir Roubtsov