EMMA Coverage Report (generated Tue May 06 07:28:24 PDT 2008)
[all classes][org.springframework.batch.support.transaction]

COVERAGE SUMMARY FOR SOURCE FILE [TransactionAwareProxyFactory.java]

nameclass, %method, %block, %line, %
TransactionAwareProxyFactory.java100% (3/3)100% (11/11)97%  (194/199)99%  (44.8/45)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TransactionAwareProxyFactory$TargetSynchronization100% (1/1)100% (2/2)89%  (39/44)98%  (11.8/12)
afterCompletion (int): void 100% (1/1)84%  (27/32)97%  (6.8/7)
TransactionAwareProxyFactory$TargetSynchronization (TransactionAwareProxyFact... 100% (1/1)100% (12/12)100% (5/5)
     
class TransactionAwareProxyFactory100% (1/1)100% (7/7)100% (112/112)100% (23/23)
TransactionAwareProxyFactory (Object): void 100% (1/1)100% (8/8)100% (3/3)
begin (Object): Object 100% (1/1)100% (40/40)100% (7/7)
commit (Object, Object): void 100% (1/1)100% (22/22)100% (7/7)
createInstance (): Object 100% (1/1)100% (15/15)100% (3/3)
createTransactionalList (): List 100% (1/1)100% (9/9)100% (1/1)
createTransactionalMap (): Map 100% (1/1)100% (9/9)100% (1/1)
createTransactionalSet (): Set 100% (1/1)100% (9/9)100% (1/1)
     
class TransactionAwareProxyFactory$1100% (1/1)100% (2/2)100% (43/43)100% (10/10)
TransactionAwareProxyFactory$1 (TransactionAwareProxyFactory): void 100% (1/1)100% (6/6)100% (1/1)
invoke (MethodInvocation): Object 100% (1/1)100% (37/37)100% (9/9)

1/*
2 * Copyright 2006-2007 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 */
16 
17package org.springframework.batch.support.transaction;
18 
19import java.util.ArrayList;
20import java.util.Collection;
21import java.util.HashMap;
22import java.util.HashSet;
23import java.util.List;
24import java.util.Map;
25import java.util.Set;
26 
27import org.aopalliance.intercept.MethodInterceptor;
28import org.aopalliance.intercept.MethodInvocation;
29import org.springframework.aop.framework.ProxyFactory;
30import org.springframework.transaction.support.TransactionSynchronization;
31import org.springframework.transaction.support.TransactionSynchronizationAdapter;
32import org.springframework.transaction.support.TransactionSynchronizationManager;
33 
34/**
35 * Factory for transaction aware objects (like lists, sets, maps). If a
36 * transaction is active when a method is called on an instance created by the
37 * factory, it makes a copy of the target object and carries out all operations
38 * on the copy. Only when the transaction commits is the target re-initialised
39 * with the copy.<br/>
40 * 
41 * Works well with collections and maps for testing transactional behaviour
42 * without needing a database. The base implementation handles lists, sets and
43 * maps. Subclasses can implement {@link #begin(Object)} and
44 * {@link #commit(Object, Object)} to provide support for other resources.
45 * 
46 * @author Dave Syer
47 * 
48 */
49public class TransactionAwareProxyFactory {
50 
51        private Object target;
52 
53        public TransactionAwareProxyFactory(Object target) {
54                super();
55                this.target = begin(target);
56        }
57 
58        /**
59         * Make a copy of the target that can be used inside a transaction to
60         * isolate changes from the original. Also called from the factory
61         * constructor to isolate the target from the original value passed in.
62         * 
63         * @param target the target object (List, Set or Map)
64         * @return an independent copy
65         */
66        protected final Object begin(Object target) {
67                if (target instanceof List) {
68                        return new ArrayList((List) target);
69                }
70                else if (target instanceof Set) {
71                        return new HashSet((Set) target);
72                }
73                else if (target instanceof Map) {
74                        return new HashMap((Map) target);
75                }
76                else {
77                        throw new UnsupportedOperationException("Cannot copy target for this type: " + target.getClass());
78                }
79        }
80 
81        /**
82         * Take the working copy state and commit it back to the original target.
83         * The target then reflects all the changes applied to the copy during a
84         * transaction.
85         * 
86         * @param copy the working copy.
87         * @param target the original target of the factory.
88         */
89        protected void commit(Object copy, Object target) {
90                if (target instanceof Collection) {
91                        ((Collection) target).clear();
92                        ((Collection) target).addAll((Collection) copy);
93                }
94                else {
95                        ((Map) target).clear();
96                        ((Map) target).putAll((Map) copy);
97                }
98        }
99 
100        public Object createInstance() {
101                ProxyFactory factory = new ProxyFactory(target);
102                factory.addAdvice(new MethodInterceptor() {
103                        public Object invoke(MethodInvocation invocation) throws Throwable {
104 
105                                if (!TransactionSynchronizationManager.isActualTransactionActive()) {
106                                        return invocation.proceed();
107                                }
108 
109                                Object cache;
110 
111                                if (!TransactionSynchronizationManager.hasResource(this)) {
112                                        cache = begin(target);
113                                        TransactionSynchronizationManager.bindResource(this, cache);
114                                        TransactionSynchronizationManager.registerSynchronization(new TargetSynchronization(this, cache));
115                                }
116                                else {
117                                        cache = TransactionSynchronizationManager.getResource(this);
118                                }
119 
120                                return invocation.getMethod().invoke(cache, invocation.getArguments());
121 
122                        }
123                });
124                return factory.getProxy();
125        }
126        
127        public static Map createTransactionalMap() {
128                return (Map) new TransactionAwareProxyFactory(new HashMap()).createInstance();
129        }
130 
131        public static Set createTransactionalSet() {
132                return (Set) new TransactionAwareProxyFactory(new HashSet()).createInstance();
133        }
134 
135        public static List createTransactionalList() {
136                return (List) new TransactionAwareProxyFactory(new ArrayList()).createInstance();
137        }
138 
139        private class TargetSynchronization extends TransactionSynchronizationAdapter {
140 
141                Object cache;
142 
143                Object key;
144 
145                public TargetSynchronization(Object key, Object cache) {
146                        super();
147                        this.cache = cache;
148                        this.key = key;
149                }
150 
151                public void afterCompletion(int status) {
152                        super.afterCompletion(status);
153                        if (status == TransactionSynchronization.STATUS_COMMITTED) {
154                                synchronized (target) {
155                                        commit(cache, target);
156                                }
157                        }
158                        TransactionSynchronizationManager.unbindResource(key);
159                }
160        }
161 
162}

[all classes][org.springframework.batch.support.transaction]
EMMA 2.0.5312 (C) Vladimir Roubtsov