Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 74a0e67bdfce8706c53de6a8902f8fe566634d8f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*******************************************************************************
 * Copyright (c) 2008-2010 Sonatype, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *      Sonatype, Inc. - initial API and implementation
 *******************************************************************************/

package org.eclipse.m2e.tests.common;

import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;

import org.eclipse.m2e.core.internal.jobs.IBackgroundProcessingQueue;

public class JobHelpers {

  private static final int POLLING_DELAY = 10;

  public static void waitForJobsToComplete() {
    try {
      waitForJobsToComplete(new NullProgressMonitor());
    } catch(Exception ex) {
      throw new IllegalStateException(ex);
    }
  }

  public static void waitForJobsToComplete(IProgressMonitor monitor) throws InterruptedException, CoreException {
    waitForBuildJobs();

    /*
     * First, make sure refresh job gets all resource change events
     * 
     * Resource change events are delivered after WorkspaceJob#runInWorkspace returns
     * and during IWorkspace#run. Each change notification is delivered by
     * only one thread/job, so we make sure no other workspaceJob is running then
     * call IWorkspace#run from this thread. 
     * 
     * Unfortunately, this does not catch other jobs and threads that call IWorkspace#run
     * so we have to hard-code workarounds
     *  
     * See http://www.eclipse.org/articles/Article-Resource-deltas/resource-deltas.html
     */
    IWorkspace workspace = ResourcesPlugin.getWorkspace();
    IJobManager jobManager = Job.getJobManager();
    jobManager.suspend();
    try {
      Job[] jobs = jobManager.find(null);
      for (int i = 0; i < jobs.length; i++) {
        if(jobs[i] instanceof WorkspaceJob || jobs[i].getClass().getName().endsWith("JREUpdateJob")) {
          jobs[i].join();
        }
      }
      workspace.run(new IWorkspaceRunnable() {
        public void run(IProgressMonitor monitor) {
        }
      }, workspace.getRoot(), 0, monitor);

      // Now we flush all background processing queues
      boolean processed = flushProcessingQueues(jobManager, monitor);
      for(int i = 0; i < 10 && processed; i++ ) {
        processed = flushProcessingQueues(jobManager, monitor);
        Thread.sleep(10);
      }

      Assert.assertFalse("Could not flush background processing queues: " + getProcessingQueues(jobManager), processed);
    } finally {
      jobManager.resume();
    }

    waitForBuildJobs();
  }

  private static boolean flushProcessingQueues(IJobManager jobManager, IProgressMonitor monitor) throws InterruptedException, CoreException {
    boolean processed = false;
    for (IBackgroundProcessingQueue queue : getProcessingQueues(jobManager)) {
      queue.join();
      if (!queue.isEmpty()) {
        IStatus status = queue.run(monitor);
        if (!status.isOK()) {
          throw new CoreException(status);
        }
        processed = true;
      }
      if (queue.isEmpty()) {
        queue.cancel();
      }
    }
    return processed;
  }

  private static List<IBackgroundProcessingQueue> getProcessingQueues(IJobManager jobManager) {
    ArrayList<IBackgroundProcessingQueue> queues = new ArrayList<IBackgroundProcessingQueue>();
    for (Job job : jobManager.find(null)) {
      if (job instanceof IBackgroundProcessingQueue) {
        queues.add((IBackgroundProcessingQueue) job);
      }
    }
    return queues;
  }

  private static void waitForBuildJobs() {
    waitForJobs(BuildJobMatcher.INSTANCE, 60 * 1000);
  }

  public static void waitForJobs(IJobMatcher matcher, int maxWaitMillis) {
    final long limit = System.currentTimeMillis() + maxWaitMillis;
    while(true) {
      Job job = getJob(matcher);
      if(job == null) {
        return;
      }
      boolean timeout = System.currentTimeMillis() > limit;
      Assert.assertFalse("Timeout while waiting for completion of job: " + job, timeout);
      job.wakeUp();
      try {
        Thread.sleep(POLLING_DELAY);
      } catch(InterruptedException e) {
        // ignore and keep waiting
      }
    }
  }

  private static Job getJob(IJobMatcher matcher) {
    Job[] jobs = Job.getJobManager().find(null);
    for(Job job : jobs) {
      if(matcher.matches(job)) {
        return job;
      }
    }
    return null;
  }

  public static void waitForLaunchesToComplete(int maxWaitMillis) {
    // wait for any jobs that actually start the launch
    waitForJobs(LaunchJobMatcher.INSTANCE, maxWaitMillis);

    // wait for the launches themselves
    final long limit = System.currentTimeMillis() + maxWaitMillis;
    while(true) {
      ILaunch launch = getActiveLaunch();
      if(launch == null) {
        return;
      }
      boolean timeout = System.currentTimeMillis() > limit;
      Assert.assertFalse("Timeout while waiting for completion of launch: " + launch.getLaunchConfiguration(), timeout);
      try {
        Thread.sleep(POLLING_DELAY);
      } catch(InterruptedException e) {
        // ignore and keep waiting
      }
    }
  }

  private static ILaunch getActiveLaunch() {
    ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches();
    if(launches != null) {
      for(ILaunch launch : launches) {
        if(!launch.isTerminated()) {
          return launch;
        }
      }
    }
    return null;
  }

  public static interface IJobMatcher {

    boolean matches(Job job);

  }

  static class LaunchJobMatcher implements IJobMatcher {

    public static final IJobMatcher INSTANCE = new LaunchJobMatcher();

    public boolean matches(Job job) {
      return job.getClass().getName().matches("(.*\\.DebugUIPlugin.*)");
    }

  }

  static class BuildJobMatcher implements IJobMatcher {

    public static final IJobMatcher INSTANCE = new BuildJobMatcher();

    public boolean matches(Job job) {
      return (job instanceof WorkspaceJob) || job.getClass().getName().matches("(.*\\.AutoBuild.*)")
          || job.getClass().getName().endsWith("JREUpdateJob");
    }

  }

}

Back to the top