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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2010, Sun Microsystems, Inc., Alan Harder
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.diagnosis;
25
26 import hudson.XmlFile;
27 import hudson.model.AdministrativeMonitor;
28 import hudson.model.ManagementLink;
29 import jenkins.model.Jenkins;
30 import hudson.Extension;
31 import hudson.model.Item;
32 import hudson.model.Job;
33 import hudson.model.Run;
34 import hudson.model.Saveable;
35 import hudson.model.listeners.ItemListener;
36 import hudson.model.listeners.RunListener;
37 import hudson.model.listeners.SaveableListener;
38 import hudson.util.RobustReflectionConverter;
39 import hudson.util.VersionNumber;
40 import org.kohsuke.stapler.StaplerRequest;
41 import org.kohsuke.stapler.StaplerResponse;
42 import com.thoughtworks.xstream.converters.UnmarshallingContext;
43
44 import java.io.IOException;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.HashMap;
48 import java.util.Iterator;
49 import java.util.Map;
50 import java.util.TreeSet;
51 import java.util.logging.Level;
52 import java.util.logging.Logger;
53 import org.kohsuke.stapler.HttpRedirect;
54 import org.kohsuke.stapler.HttpResponse;
55 import org.kohsuke.stapler.HttpResponses;
56
57 /**
58 * Tracks whether any data structure changes were corrected when loading XML,
59 * that could be resaved to migrate that data to the new format.
60 *
61 * @author Alan.Harder@Sun.Com
62 */
63 @Extension
64 public class OldDataMonitor extends AdministrativeMonitor {
65 private static Logger LOGGER = Logger.getLogger(OldDataMonitor.class.getName());
66
67 private HashMap<Saveable,VersionRange> data = new HashMap<Saveable,VersionRange>();
68 private boolean updating = false;
69
70 public OldDataMonitor() {
71 super("OldData");
72 }
73
74 @Override
75 public String getDisplayName() {
76 return Messages.OldDataMonitor_DisplayName();
77 }
78
79 public boolean isActivated() {
80 return !data.isEmpty();
81 }
82
83 public synchronized Map<Saveable,VersionRange> getData() {
84 return Collections.unmodifiableMap(data);
85 }
86
87 private static void remove(Saveable obj, boolean isDelete) {
88 OldDataMonitor odm = (OldDataMonitor) Jenkins.getInstance().getAdministrativeMonitor("OldData");
89 synchronized (odm) {
90 if (odm.updating) return; // Skip during doUpgrade or doDiscard
91 odm.data.remove(obj);
92 if (isDelete && obj instanceof Job<?,?>)
93 for (Run r : ((Job<?,?>)obj).getBuilds())
94 odm.data.remove(r);
95 }
96 }
97
98 // Listeners to remove data here if resaved or deleted in regular Hudson usage
99
100 @Extension
101 public static final SaveableListener changeListener = new SaveableListener() {
102 @Override
103 public void onChange(Saveable obj, XmlFile file) {
104 remove(obj, false);
105 }
106 };
107
108 @Extension
109 public static final ItemListener itemDeleteListener = new ItemListener() {
110 @Override
111 public void onDeleted(Item item) {
112 remove(item, true);
113 }
114 };
115
116 @Extension
117 public static final RunListener<Run> runDeleteListener = new RunListener<Run>() {
118 @Override
119 public void onDeleted(Run run) {
120 remove(run, true);
121 }
122 };
123
124 /**
125 * Inform monitor that some data in a deprecated format has been loaded,
126 * and converted in-memory to a new structure.
127 * @param obj Saveable object; calling save() on this object will persist
128 * the data in its new format to disk.
129 * @param version Hudson release when the data structure changed.
130 */
131 public static void report(Saveable obj, String version) {
132 OldDataMonitor odm = (OldDataMonitor) Jenkins.getInstance().getAdministrativeMonitor("OldData");
133 synchronized (odm) {
134 try {
135 VersionRange vr = odm.data.get(obj);
136 if (vr != null) vr.add(version);
137 else odm.data.put(obj, new VersionRange(version, null));
138 } catch (IllegalArgumentException ex) {
139 LOGGER.log(Level.WARNING, "Bad parameter given to OldDataMonitor", ex);
140 }
141 }
142 }
143
144 /**
145 * Inform monitor that some data in a deprecated format has been loaded, during
146 * XStream unmarshalling when the Saveable containing this object is not available.
147 * @param context XStream unmarshalling context
148 * @param version Hudson release when the data structure changed.
149 */
150 public static void report(UnmarshallingContext context, String version) {
151 RobustReflectionConverter.addErrorInContext(context, new ReportException(version));
152 }
153
154 private static class ReportException extends Exception {
155 private String version;
156 private ReportException(String version) {
157 this.version = version;
158 }
159 }
160
161 /**
162 * Inform monitor that some unreadable data was found while loading.
163 * @param obj Saveable object; calling save() on this object will discard the unreadable data.
164 * @param errors Exception(s) thrown while loading, regarding the unreadable classes/fields.
165 */
166 public static void report(Saveable obj, Collection<Throwable> errors) {
167 StringBuilder buf = new StringBuilder();
168 int i = 0;
169 for (Throwable e : errors) {
170 if (e instanceof ReportException) {
171 report(obj, ((ReportException)e).version);
172 } else {
173 if (++i > 1) buf.append(", ");
174 buf.append(e.getClass().getSimpleName()).append(": ").append(e.getMessage());
175 }
176 }
177 if (buf.length() == 0) return;
178 OldDataMonitor odm = (OldDataMonitor) Jenkins.getInstance().getAdministrativeMonitor("OldData");
179 synchronized (odm) {
180 VersionRange vr = odm.data.get(obj);
181 if (vr != null) vr.extra = buf.toString();
182 else odm.data.put(obj, new VersionRange(null, buf.toString()));
183 }
184 }
185
186 public static class VersionRange {
187 private static VersionNumber currentVersion = Jenkins.getVersion();
188
189 VersionNumber min, max;
190 boolean single = true;
191 public String extra;
192
193 public VersionRange(String version, String extra) {
194 min = max = version != null ? new VersionNumber(version) : null;
195 this.extra = extra;
196 }
197
198 public void add(String version) {
199 VersionNumber ver = new VersionNumber(version);
200 if (min==null) { min = max = ver; }
201 else {
202 if (ver.isOlderThan(min)) { min = ver; single = false; }
203 if (ver.isNewerThan(max)) { max = ver; single = false; }
204 }
205 }
206
207 @Override
208 public String toString() {
209 return min==null ? "" : min.toString() + (single ? "" : " - " + max.toString());
210 }
211
212 /**
213 * Does this version range contain a version more than the given number of releases ago?
214 * @param threshold Number of releases
215 * @return True if the major version# differs or the minor# differs by >= threshold
216 */
217 public boolean isOld(int threshold) {
218 return currentVersion != null && min != null && (currentVersion.digit(0) > min.digit(0)
219 || (currentVersion.digit(0) == min.digit(0)
220 && currentVersion.digit(1) - min.digit(1) >= threshold));
221 }
222 }
223
224 /**
225 * Sorted list of unique max-versions in the data set. For select list in jelly.
226 */
227 public synchronized Iterator<VersionNumber> getVersionList() {
228 TreeSet<VersionNumber> set = new TreeSet<VersionNumber>();
229 for (VersionRange vr : data.values())
230 if (vr.max!=null) set.add(vr.max);
231 return set.iterator();
232 }
233
234 /**
235 * Depending on whether the user said "yes" or "no", send him to the right place.
236 */
237 public HttpResponse doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
238 if (req.hasParameter("no")) {
239 disable(true);
240 return HttpResponses.redirectViaContextPath("/manage");
241 } else {
242 return new HttpRedirect("manage");
243 }
244 }
245
246 /**
247 * Save all or some of the files to persist data in the new forms.
248 * Remove those items from the data map.
249 */
250 public synchronized HttpResponse doUpgrade(StaplerRequest req, StaplerResponse rsp) throws IOException {
251 String thruVerParam = req.getParameter("thruVer");
252 VersionNumber thruVer = thruVerParam.equals("all") ? null : new VersionNumber(thruVerParam);
253 updating = true;
254 for (Iterator<Map.Entry<Saveable,VersionRange>> it = data.entrySet().iterator(); it.hasNext();) {
255 Map.Entry<Saveable,VersionRange> entry = it.next();
256 VersionNumber version = entry.getValue().max;
257 if (version != null && (thruVer == null || !version.isNewerThan(thruVer))) {
258 entry.getKey().save();
259 it.remove();
260 }
261 }
262 updating = false;
263 return HttpResponses.forwardToPreviousPage();
264 }
265
266 /**
267 * Save all files containing only unreadable data (no data upgrades), which discards this data.
268 * Remove those items from the data map.
269 */
270 public synchronized HttpResponse doDiscard(StaplerRequest req, StaplerResponse rsp) throws IOException {
271 updating = true;
272 for (Iterator<Map.Entry<Saveable,VersionRange>> it = data.entrySet().iterator(); it.hasNext();) {
273 Map.Entry<Saveable,VersionRange> entry = it.next();
274 if (entry.getValue().max == null) {
275 entry.getKey().save();
276 it.remove();
277 }
278 }
279 updating = false;
280 return HttpResponses.forwardToPreviousPage();
281 }
282
283 public HttpResponse doIndex(StaplerResponse rsp) throws IOException {
284 return new HttpRedirect("manage");
285 }
286
287 @Extension
288 public static class ManagementLinkImpl extends ManagementLink {
289 @Override
290 public String getIconFileName() {
291 return "document.png";
292 }
293
294 @Override
295 public String getUrlName() {
296 return "administrativeMonitor/OldData/";
297 }
298
299 @Override
300 public String getDescription() {
301 return Messages.OldDataMonitor_Description();
302 }
303
304 public String getDisplayName() {
305 return Messages.OldDataMonitor_DisplayName();
306 }
307 }
308 }
309