File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\BulkChange.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson;
25
26 import hudson.model.Saveable;
27
28 import java.io.IOException;
29
30 /**
31 * Transaction-like object that can be used to make a bunch of changes to an object, and defer the
32 * {@link Saveable#save()} until the end.
33 *
34 * <p>
35 * The usage of {@link BulkChange} needs to follow a specific closure-like pattern, namely:
36 *
37 * <pre>
38 * BulkChange bc = new BulkChange(someObject);
39 * try {
40 * ... make changes to 'someObject'
41 * } finally {
42 * bc.commit();
43 * }
44 * </pre>
45 *
46 * <p>
47 * ... or if you'd like to avoid saving when something bad happens:
48 *
49 * <pre>
50 * BulkChange bc = new BulkChange(someObject);
51 * try {
52 * ... make changes to 'someObject'
53 * bc.commit();
54 * } finally {
55 * bc.abort();
56 * }
57 * </pre>
58 *
59 * <p>
60 * Use of this method is optional. If {@link BulkChange} is not used, individual mutator
61 * will perform the save operation, and things will just run somewhat slower.
62 *
63 *
64 * <h2>Cooperation from {@link Saveable}</h2>
65 * <p>
66 * For this class to work as intended, {@link Saveable} implementations need to co-operate.
67 * Namely,
68 *
69 * <ol>
70 * <li>
71 * Mutater methods should invoke {@code this.save()} so that if the method is called outside
72 * a {@link BulkChange}, the result will be saved immediately.
73 *
74 * <li>
75 * In the {@code save()} method implementation, use {@link #contains(Saveable)} and
76 * only perform the actual I/O operation when this method returns false.
77 * </ol>
78 *
79 * <p>
80 * See {@link jenkins.model.Jenkins#save()} as an example if you are not sure how to implement {@link Saveable}.
81 *
82 * @author Kohsuke Kawaguchi
83 * @since 1.249
84 */
85 public class BulkChange {
86 private final Saveable saveable;
87 public final Exception allocator;
88 private final BulkChange parent;
89
90 private boolean completed;
91
92 public BulkChange(Saveable saveable) {
93 this.parent = current();
94 this.saveable = saveable;
95 // rememeber who allocated this object in case
96 // someone forgot to call save() at the end.
97 allocator = new Exception();
98
99 // in effect at construction
100 INSCOPE.set(this);
101 }
102
103 /**
104 * Saves the accumulated changes.
105 */
106 public void commit() throws IOException {
107 if(completed) return;
108 completed = true;
109
110 // move this object out of the scope first before save, or otherwise the save() method will do nothing.
111 pop();
112 saveable.save();
113 }
114
115 /**
116 * Exits the scope of {@link BulkChange} without saving the changes.
117 *
118 * <p>
119 * This can be used when a bulk change fails in the middle.
120 * Note that unlike a real transaction, this will not roll back the state of the object.
121 *
122 * <p>
123 * The abort method can be called after the commit method, in which case this method does nothing.
124 * This is so that {@link BulkChange} can be used naturally in the try/finally block.
125 */
126 public void abort() {
127 if(completed) return;
128 completed = true;
129 pop();
130 }
131
132 private void pop() {
133 if(current()!=this)
134 throw new AssertionError("Trying to save BulkChange that's not in scope");
135 INSCOPE.set(parent);
136 }
137
138 /**
139 * {@link BulkChange}s that are effective currently.
140 */
141 private static final ThreadLocal<BulkChange> INSCOPE = new ThreadLocal<BulkChange>();
142
143 /**
144 * Gets the {@link BulkChange} instance currently in scope for the current thread.
145 */
146 public static BulkChange current() {
147 return INSCOPE.get();
148 }
149
150 /**
151 * Checks if the given {@link Saveable} is currently in the bulk change.
152 *
153 * <p>
154 * The expected usage is from the {@link Saveable#save()} implementation to check
155 * if the actual persistence should happen now or not.
156 */
157 public static boolean contains(Saveable s) {
158 for(BulkChange b=current(); b!=null; b=b.parent)
159 if(b.saveable==s || b.saveable==ALL)
160 return true;
161 return false;
162 }
163
164 /**
165 * Magic {@link Saveable} instance that can make {@link BulkChange} veto
166 * all the save operations by making the {@link #contains(Saveable)} method return
167 * true for everything.
168 */
169 public static final Saveable ALL = new Saveable() {
170 public void save() {
171 }
172 };
173 }
174