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 | |
17 | package org.springframework.batch.repeat.context; |
18 | |
19 | import java.util.ArrayList; |
20 | import java.util.HashMap; |
21 | import java.util.HashSet; |
22 | import java.util.Iterator; |
23 | import java.util.List; |
24 | import java.util.Map; |
25 | import java.util.Set; |
26 | |
27 | import org.springframework.batch.repeat.RepeatContext; |
28 | |
29 | public class RepeatContextSupport extends SynchronizedAttributeAccessor implements RepeatContext { |
30 | |
31 | private RepeatContext parent; |
32 | |
33 | private int count; |
34 | |
35 | private volatile boolean completeOnly; |
36 | |
37 | private volatile boolean terminateOnly; |
38 | |
39 | private Map callbacks = new HashMap(); |
40 | |
41 | /** |
42 | * Constructor for {@link RepeatContextSupport}. The parent can be null, |
43 | * but should be set to the enclosing repeat context if there is one, e.g. |
44 | * if this context is an inner loop. |
45 | * @param parent |
46 | */ |
47 | public RepeatContextSupport(RepeatContext parent) { |
48 | super(); |
49 | this.parent = parent; |
50 | } |
51 | |
52 | /* |
53 | * (non-Javadoc) |
54 | * @see org.springframework.batch.repeat.RepeatContext#isCompleteOnly() |
55 | */ |
56 | public boolean isCompleteOnly() { |
57 | return completeOnly; |
58 | } |
59 | |
60 | /* |
61 | * (non-Javadoc) |
62 | * @see org.springframework.batch.repeat.RepeatContext#setCompleteOnly() |
63 | */ |
64 | public void setCompleteOnly() { |
65 | completeOnly = true; |
66 | } |
67 | |
68 | /* |
69 | * (non-Javadoc) |
70 | * @see org.springframework.batch.repeat.RepeatContext#isTerminateOnly() |
71 | */ |
72 | public boolean isTerminateOnly() { |
73 | return terminateOnly; |
74 | } |
75 | |
76 | /* |
77 | * (non-Javadoc) |
78 | * @see org.springframework.batch.repeat.RepeatContext#setTerminateOnly() |
79 | */ |
80 | public void setTerminateOnly() { |
81 | terminateOnly = true; |
82 | setCompleteOnly(); |
83 | } |
84 | |
85 | /* |
86 | * (non-Javadoc) |
87 | * @see org.springframework.batch.repeat.RepeatContext#getParent() |
88 | */ |
89 | public RepeatContext getParent() { |
90 | return parent; |
91 | } |
92 | |
93 | /** |
94 | * Used by clients to increment the started count. |
95 | */ |
96 | public synchronized void increment() { |
97 | count++; |
98 | } |
99 | |
100 | /* |
101 | * (non-Javadoc) |
102 | * @see org.springframework.batch.repeat.RepeatContext#getStartedCount() |
103 | */ |
104 | public synchronized int getStartedCount() { |
105 | return count; |
106 | } |
107 | |
108 | /* |
109 | * (non-Javadoc) |
110 | * @see org.springframework.batch.repeat.RepeatContext#registerDestructionCallback(java.lang.String, |
111 | * java.lang.Runnable) |
112 | */ |
113 | public void registerDestructionCallback(String name, Runnable callback) { |
114 | synchronized (callbacks) { |
115 | Set set = (Set) callbacks.get(name); |
116 | if (set == null) { |
117 | set = new HashSet(); |
118 | callbacks.put(name, set); |
119 | } |
120 | set.add(callback); |
121 | } |
122 | } |
123 | |
124 | /* |
125 | * (non-Javadoc) |
126 | * @see org.springframework.batch.repeat.RepeatContext#close() |
127 | */ |
128 | public void close() { |
129 | |
130 | List errors = new ArrayList(); |
131 | |
132 | Set copy; |
133 | |
134 | synchronized (callbacks) { |
135 | copy = new HashSet(callbacks.entrySet()); |
136 | } |
137 | |
138 | for (Iterator iter = copy.iterator(); iter.hasNext();) { |
139 | Map.Entry entry = (Map.Entry) iter.next(); |
140 | Set set = (Set) entry.getValue(); |
141 | for (Iterator iterator = set.iterator(); iterator.hasNext();) { |
142 | Runnable callback = (Runnable) iterator.next(); |
143 | /* |
144 | * Potentially we could check here if there is an attribute with |
145 | * the given name - if it has been removed, maybe the callback |
146 | * is invalid. On the other hand it is less surprising for the |
147 | * callback register if it is always executed. |
148 | */ |
149 | if (callback != null) { |
150 | /* |
151 | * The documentation of the interface says that these |
152 | * callbacks must not throw exceptions, but we don't trust |
153 | * them necessarily... |
154 | */ |
155 | try { |
156 | callback.run(); |
157 | } |
158 | catch (RuntimeException t) { |
159 | errors.add(t); |
160 | } |
161 | } |
162 | } |
163 | } |
164 | |
165 | if (errors.isEmpty()) { |
166 | return; |
167 | } |
168 | |
169 | throw (RuntimeException) errors.get(0); |
170 | } |
171 | |
172 | } |