File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\util\DoubleLaunchChecker.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.util;
25
26 import jenkins.model.Jenkins;
27 import hudson.triggers.SafeTimerTask;
28 import hudson.triggers.Trigger;
29 import org.apache.commons.io.FileUtils;
30 import org.kohsuke.stapler.StaplerRequest;
31 import org.kohsuke.stapler.StaplerResponse;
32
33 import javax.servlet.ServletException;
34 import javax.servlet.ServletContext;
35 import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
36 import java.io.File;
37 import java.io.IOException;
38 import java.util.Random;
39 import java.util.logging.Logger;
40 import java.util.logging.Level;
41 import java.lang.management.ManagementFactory;
42 import java.lang.reflect.Method;
43 import java.util.Timer;
44
45 /**
46 * Makes sure that no other Hudson uses our <tt>JENKINS_HOME</tt> directory,
47 * to forestall the problem of running multiple instances of Hudson that point to the same data directory.
48 *
49 * <p>
50 * This set up error occasionally happens especialy when the user is trying to reassign the context path of the app,
51 * and it results in a hard-to-diagnose error, so we actively check this.
52 *
53 * <p>
54 * The mechanism is simple. This class occasionally updates a known file inside the hudson home directory,
55 * and whenever it does so, it monitors the timestamp of the file to make sure no one else is updating
56 * this file. In this way, while we cannot detect the problem right away, within a reasonable time frame
57 * we can detect the collision.
58 *
59 * <p>
60 * More traditional way of doing this is to use a lock file with PID in it, but unfortunately in Java,
61 * there's no reliabe way to obtain PID.
62 *
63 * @author Kohsuke Kawaguchi
64 * @since 1.178
65 */
66 public class DoubleLaunchChecker {
67 /**
68 * The timestamp of the owner file when we updated it for the last time.
69 * 0 to indicate that there was no update before.
70 */
71 private long lastWriteTime = 0L;
72
73 /**
74 * Once the error is reported, the user can choose to ignore and proceed anyway,
75 * in which case the flag is set to true.
76 */
77 private boolean ignore = false;
78
79 private final Random random = new Random();
80
81 public final File home;
82
83 /**
84 * ID string of the other Hudson that we are colliding with.
85 * Can be null.
86 */
87 private String collidingId;
88
89 public DoubleLaunchChecker() {
90 home = Jenkins.getInstance().getRootDir();
91 }
92
93 protected void execute() {
94 File timestampFile = new File(home,".owner");
95
96 long t = timestampFile.lastModified();
97 if(t!=0 && lastWriteTime!=0 && t!=lastWriteTime && !ignore) {
98 try {
99 collidingId = FileUtils.readFileToString(timestampFile);
100 } catch (IOException e) {
101 LOGGER.log(Level.SEVERE, "Failed to read collision file", e);
102 }
103 // we noticed that someone else have updated this file.
104 // switch GUI to display this error.
105 Jenkins.getInstance().servletContext.setAttribute("app",this);
106 LOGGER.severe("Collision detected. timestamp="+t+", expected="+lastWriteTime);
107 // we need to continue updating this file, so that the other Hudson would notice the problem, too.
108 }
109
110 try {
111 FileUtils.writeStringToFile(timestampFile, getId());
112 lastWriteTime = timestampFile.lastModified();
113 } catch (IOException e) {
114 // if failed to write, err on the safe side and assume things are OK.
115 lastWriteTime=0;
116 }
117
118 schedule();
119 }
120
121 /**
122 * Figures out a string that identifies this instance of Hudson.
123 */
124 public String getId() {
125 Jenkins h = Jenkins.getInstance();
126
127 // in servlet 2.5, we can get the context path
128 String contextPath="";
129 try {
130 Method m = ServletContext.class.getMethod("getContextPath");
131 contextPath=" contextPath=\""+m.invoke(h.servletContext)+"\"";
132 } catch (Exception e) {
133 // maybe running with Servlet 2.4
134 }
135
136 return h.hashCode()+contextPath+" at "+ManagementFactory.getRuntimeMXBean().getName();
137 }
138
139 public String getCollidingId() {
140 return collidingId;
141 }
142
143 /**
144 * Schedules the next execution.
145 */
146 public void schedule() {
147 // randomize the scheduling so that multiple Hudson instances will write at the file at different time
148 long MINUTE = 1000*60;
149 Timer timer = Trigger.timer;
150 if (timer != null) {
151 timer.schedule(new SafeTimerTask() {
152 protected void doRun() {
153 execute();
154 }
155 },(random.nextInt(30)+60)*MINUTE);
156 }
157 }
158
159 /**
160 * Serve all URLs with the index view.
161 */
162 public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
163 rsp.setStatus(SC_INTERNAL_SERVER_ERROR);
164 req.getView(this,"index.jelly").forward(req,rsp);
165 }
166
167 /**
168 * Ignore the problem and go back to using Hudson.
169 */
170 public void doIgnore(StaplerRequest req, StaplerResponse rsp) throws IOException {
171 ignore = true;
172 Jenkins.getInstance().servletContext.setAttribute("app", Jenkins.getInstance());
173 rsp.sendRedirect2(req.getContextPath()+'/');
174 }
175
176 private static final Logger LOGGER = Logger.getLogger(DoubleLaunchChecker.class.getName());
177 }
178