View Javadoc

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