| /******************************************************************************* |
| * Copyright (c) 2009, 2014 Xored Software Inc and others. |
| * 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: |
| * Xored Software Inc - initial API and implementation and/or initial documentation |
| *******************************************************************************/ |
| package org.eclipse.rcptt.tesla.internal.ui.player; |
| |
| import static java.util.Arrays.asList; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.IdentityHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.jobs.IJobChangeEvent; |
| import org.eclipse.core.runtime.jobs.IJobChangeListener; |
| import org.eclipse.core.runtime.jobs.ISchedulingRule; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.rcptt.logging.Q7LoggingManager; |
| import org.eclipse.rcptt.reporting.core.ReportManager; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Node; |
| import org.eclipse.rcptt.sherlock.core.reporting.Procedure1; |
| import org.eclipse.rcptt.tesla.core.Q7WaitUtils; |
| import org.eclipse.rcptt.tesla.core.TeslaFeatures; |
| import org.eclipse.rcptt.tesla.core.TeslaLimits; |
| import org.eclipse.rcptt.tesla.core.context.ContextManagement; |
| import org.eclipse.rcptt.tesla.core.context.ContextManagement.Context; |
| import org.eclipse.rcptt.tesla.core.info.Q7WaitInfoRoot; |
| import org.eclipse.rcptt.tesla.jobs.JobsManager; |
| import org.eclipse.rcptt.tesla.swt.events.TeslaEventManager; |
| import org.eclipse.rcptt.tesla.ui.IJobCollector; |
| import org.eclipse.rcptt.tesla.ui.IJobCollector.JobStatus; |
| import org.eclipse.rcptt.tesla.ui.SWTTeslaActivator; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.progress.UIJob; |
| |
| /** |
| * Manages jobs information and statuses. |
| * */ |
| public class UIJobCollector implements IJobChangeListener { |
| private class JobInfo { |
| private final Job job; |
| private JobStatus status; |
| private boolean sleeping = false; |
| private boolean infoPrinted = false; |
| private long startingTime = System.currentTimeMillis(); |
| private long rescheduleCounter = 0; |
| private boolean jobInStepMode = false; |
| private boolean checkForTimeout = true; |
| private boolean done = false; |
| JobInfo(Job job) { |
| this.job = job; |
| status = calcJobStatus(job, 0); |
| } |
| |
| synchronized void awake() { |
| sleeping = false; |
| done = false; |
| startingTime = System.currentTimeMillis(); |
| } |
| |
| synchronized void sleeping() { |
| sleeping = true; |
| done = false; |
| infoPrinted = false; |
| } |
| |
| synchronized void done(boolean reschedule) { |
| if (!reschedule) { |
| done = true; |
| } else { |
| // Job will be rescheduled |
| rescheduleCounter += 1; |
| } |
| } |
| |
| synchronized void cancel() { |
| done = true; |
| } |
| |
| synchronized void printJobTimeoutLogEntry() { |
| if (!infoPrinted) { |
| infoPrinted = true; |
| SWTTeslaActivator |
| .logToReport("---->>> Waiting timeout exceed then execute: " |
| + getCurrentReportNodeName() |
| + " <<---\n(skipping)" |
| + getJobMessage(this)); |
| } |
| } |
| |
| synchronized boolean isActive() { |
| if (done) |
| return false; |
| if (!JobStatus.REQUIRED.equals(status)) |
| return false; |
| if (sleeping) { |
| long delay = startingTime - System.currentTimeMillis(); |
| return delay < TeslaLimits.getJobWaitForDelayedTimeout(); |
| } |
| |
| return true; |
| } |
| |
| synchronized void scheduled(long delay) { |
| sleeping = false; |
| done = false; |
| checkForTimeout = true; |
| jobInStepMode = false; |
| status = calcJobStatus(job, delay); |
| startingTime = System.currentTimeMillis() + delay; |
| } |
| |
| @Override |
| public String toString() { |
| return job.toString(); |
| } |
| |
| |
| } |
| |
| private final Map<Job, JobInfo> jobs = Collections.synchronizedMap(new IdentityHashMap<Job, JobInfo>()); |
| private boolean state; |
| private boolean needDisable = false; |
| private long stepModeNext = 0; |
| |
| |
| private JobInfo getOrCreateJobInfo(Job job) { |
| synchronized (jobs) { |
| JobInfo rv = jobs.get(job); |
| if (rv == null) { |
| rv = new JobInfo(job); |
| JobsManager.getInstance().removeCanceled(job); |
| if (TeslaFeatures.isActivityLogging()) { |
| String msg = "waiting for job: " |
| + job.getClass().getName(); |
| System.out.println(msg); |
| Q7LoggingManager.get("jobs").log( |
| msg, null); |
| ReportManager.appendLogExtra(msg); |
| } |
| jobs.put(job, rv); |
| } |
| return rv; |
| } |
| } |
| |
| public void aboutToRun(IJobChangeEvent event) { |
| } |
| |
| public void awake(IJobChangeEvent event) { |
| getOrCreateJobInfo(event.getJob()).awake(); |
| } |
| |
| public void done(IJobChangeEvent event) { |
| JobsManager.getInstance().removeCanceled(event.getJob()); |
| synchronized (jobs) { |
| boolean reschedule = TeslaSWTAccess.getJobEventReSchedule(event) && state; |
| getOrCreateJobInfo(event.getJob()).done(reschedule); |
| if (needDisable && isJoinEmpty()) { |
| disable(); |
| } |
| if (!reschedule) |
| jobs.remove(event.getJob()); |
| } |
| } |
| |
| public void running(IJobChangeEvent event) { |
| } |
| |
| public void scheduled(IJobChangeEvent event) { |
| if (!state) { |
| return; |
| } |
| JobInfo jobInfo = getOrCreateJobInfo(event.getJob()); |
| jobInfo.scheduled(event.getDelay()); |
| if (JobStatus.REQUIRED.equals(jobInfo.status)) { |
| if (event.getJob().belongsTo(TeslaSWTAccess.getDecoratorManagerFamily())) { |
| JobsManager.getInstance().nulifyTime(event.getJob()); |
| } |
| if (jobInfo.rescheduleCounter < TeslaLimits |
| .getJobNullifyRescheduleMaxValue()) { |
| JobsManager.getInstance().nulifyTime(event.getJob()); |
| } |
| } |
| } |
| |
| protected JobStatus calcJobStatus(Job job, long delay) { |
| return detectJobStatus(job, delay); |
| } |
| |
| private static final Set<String> IGNORED_BY_DEFAULT = Collections.unmodifiableSet( |
| new HashSet<String> ( |
| asList( |
| "org.eclipse.jdt.internal.core.search.processing.JobManager$1$ProgressJob", |
| "org.eclipse.ui.internal.progress.ProgressViewUpdater$1", |
| "org.eclipse.ui.internal.progress.WorkbenchSiteProgressService$SiteUpdateJob", |
| "org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.RefreshProgressMessageJob", |
| "org.eclipse.ui.dialogs.FilteredItemsSelectionDialog$RefreshProgressMessageJob", |
| "org.eclipse.ui.internal.progress.AnimationManager$1", |
| "org.eclipse.ui.internal.progress.ProgressManager$6", |
| "org.eclipse.ui.internal.progress.TaskBarProgressManager$2", |
| "org.eclipse.ui.internal.views.markers.CachedMarkerBuilder$1" |
| ) |
| ) |
| ); |
| |
| public static JobStatus detectJobStatus(Job job, long delay) { |
| JobStatus status = null; |
| IJobCollector[] collectors = JobCollectorExtensions.getDefault() |
| .getCollectors(); |
| |
| // Take first status |
| for (IJobCollector cl : collectors) { |
| JobStatus jobStatus = cl.testJob(job); |
| if (jobStatus != null |
| && (!jobStatus.equals(JobStatus.UNKNOWN) && status == null)) { |
| status = jobStatus; |
| break; |
| } |
| } |
| // Allow override some default |
| if (status == null) { |
| if ((delay < TeslaLimits.getJobWaitForDelayedTimeout())) { |
| status = JobStatus.REQUIRED; |
| } |
| if (job.belongsTo(getFamilyAutoBuild())) { |
| status = JobStatus.REQUIRED; |
| } |
| // if (TeslaSWTAccess.isDefferedTreeContentProvider(job)) { |
| // status = JobStatus.REQUIRED; |
| // } |
| String jClassName = job.getClass().getName(); |
| if (IGNORED_BY_DEFAULT.contains(jClassName)) |
| status = JobStatus.IGNORED; |
| } |
| return status; |
| } |
| |
| public void sleeping(IJobChangeEvent event) { |
| getOrCreateJobInfo(event.getJob()).sleeping(); |
| } |
| |
| private static boolean isModal(Shell shell) { |
| return PlayerWidgetUtils.isModal(shell); |
| } |
| |
| private long lastSuccessTime = 0; |
| |
| private String getJobMessage(Job job) { |
| return getJobMessage(getOrCreateJobInfo(job)); |
| } |
| |
| private String getJobMessage(JobInfo jobInfo) { |
| Job job = jobInfo.job; |
| StringBuilder msg = new StringBuilder(); |
| msg.append("Job: ").append(job.getName()).append("\n"); |
| |
| msg.append("\tclass: ").append(job.getClass().getName()).append(" ") |
| .append(DetailUtils.extractSupers(job.getClass())).append("\n"); |
| |
| Long startTime = jobInfo.startingTime; |
| |
| long currentTimeMillis = System.currentTimeMillis(); |
| long time = 0; |
| if (startTime != null) { |
| time = currentTimeMillis - startTime.longValue(); |
| } |
| |
| msg.append("\tworking time: ").append(time).append("(ms)\n"); |
| msg.append("\tstate: ").append(job.getState()).append("\n"); |
| |
| ISchedulingRule rule = job.getRule(); |
| if (rule != null) { |
| if (rule instanceof IResource) { |
| IPath location = ((IResource) rule).getLocation(); |
| msg.append("\trule is resource: ") |
| .append(location != null ? location.toOSString() : "/") |
| .append("\n"); |
| } else { |
| msg.append("\trule: ").append(rule.toString()).append("\n"); |
| } |
| } else { |
| msg.append("\trule: Empty\n"); |
| } |
| |
| Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces(); |
| Set<String> names = getSuperClassNames(job); |
| for (Map.Entry<Thread, StackTraceElement[]> thread : traces.entrySet()) { |
| Context ctx = ContextManagement.makeContext(thread.getValue()); |
| for (String name : names) { |
| if (ctx.contains("org.eclipse.core.internal.jobs.Worker", "run") |
| && ctx.contains(name, "run")) { |
| StackTraceElement[] value = thread.getValue(); |
| msg.append("\tstack trace: \n"); |
| // Print 5 lines of stack trace for job |
| int c = 0; |
| for (StackTraceElement stackTraceElement : value) { |
| if (c > 15) { |
| msg.append("\t\t...."); |
| break; |
| } |
| c++; |
| msg.append( |
| "\t\t" |
| + stackTraceElement.getClassName() |
| + "." |
| + stackTraceElement.getMethodName() |
| + ":" |
| + stackTraceElement.getLineNumber() |
| + (stackTraceElement.getFileName() != null ? (" [" |
| + stackTraceElement |
| .getFileName() + "]") |
| : "")).append("\n"); |
| |
| } |
| } |
| } |
| } |
| |
| return msg.toString(); |
| } |
| |
| private boolean logReturnResult(boolean result, List<Job> realJobs, |
| List<Job> jobsInUI, Q7WaitInfoRoot info) { |
| try { |
| long curTime = System.currentTimeMillis(); |
| if (result) { |
| lastSuccessTime = curTime; |
| return result; |
| } |
| for (Job job : jobsInUI) { |
| Q7WaitUtils.updateInfo("job.ui", job.getClass().getName(), info); |
| } |
| for (Job job : realJobs) { |
| Q7WaitUtils.updateInfo("job", job.getClass().getName(), info); |
| } |
| |
| if (lastSuccessTime == 0) { |
| lastSuccessTime = curTime; |
| return result; |
| } |
| if (curTime - lastSuccessTime > TeslaLimits.getJobLoggingTimeout()) { |
| lastSuccessTime = curTime; |
| logJobInformation(realJobs, jobsInUI); |
| } |
| } catch (Exception e) { |
| SWTTeslaActivator.log(e); |
| } |
| |
| return result; |
| } |
| |
| @SuppressWarnings("deprecation") |
| static String getCurrentReportNodeName() { |
| final String[] rv = new String[1]; |
| ReportManager.getCurrentReportNode().update(new Procedure1<Node>() { |
| @Override |
| public void apply(Node node) { |
| rv[0] = node.getName(); |
| } |
| }); |
| return rv[0]; |
| } |
| |
| private void logJobInformation(List<Job> realJobs, List<Job> jobsInUI) { |
| List<Job> otherJobs = new ArrayList<Job>(jobs.keySet()); |
| Set<Job> jobInStepMode = new HashSet<Job>(); |
| for (Job job: otherJobs) { |
| if (getOrCreateJobInfo(job).jobInStepMode) |
| jobInStepMode.add(job); |
| } |
| otherJobs.removeAll(realJobs); |
| otherJobs.removeAll(jobsInUI); |
| otherJobs.removeAll(jobInStepMode); |
| StringBuilder reportMessage = new StringBuilder(); |
| |
| reportMessage.append("----->>> Waiting for Jobs during execution: ") |
| .append(getCurrentReportNodeName()) |
| .append(" -----<<<< \n"); |
| |
| if (realJobs.size() > 0) { |
| reportMessage.append("---> Standalone Jobs:\n"); |
| for (Job job : realJobs) { |
| reportMessage.append(getJobMessage(job)).append("\n"); |
| } |
| } |
| if (jobInStepMode.size() > 0) { |
| reportMessage.append("---> Jobs in Stepping mode:\n"); |
| for (Job job : jobInStepMode) { |
| reportMessage.append(getJobMessage(job)).append("\n"); |
| } |
| } |
| if (jobsInUI.size() > 0) { |
| reportMessage.append("---> Jobs doing UI:\n"); |
| for (Job job : jobsInUI) { |
| reportMessage.append(getJobMessage(job)).append("\n"); |
| } |
| } |
| if (otherJobs.size() > 0) { |
| reportMessage.append("---> Other jobs:\n"); |
| for (Job job : otherJobs) { |
| reportMessage.append(getJobMessage(job)).append("\n"); |
| } |
| } |
| SWTTeslaActivator.logToReport(reportMessage.toString()); |
| } |
| |
| public boolean isEmpty(Context context, Q7WaitInfoRoot info) { |
| // Filter already executed UI jobs with async finish status. |
| List<Job> realJobs = new ArrayList<Job>(); |
| long current = System.currentTimeMillis(); |
| boolean wasInStepMode = false; |
| List<Job> jobsInUI = new ArrayList<Job>(); |
| synchronized (jobs) { |
| // Remove all canceled jobs |
| removeCanceledJobs(); |
| if (jobs.isEmpty()) { |
| return logReturnResult(true, realJobs, jobsInUI, info); |
| } |
| for (JobInfo jobInfo : jobs.values()) { |
| if (!jobInfo.isActive()) |
| continue; |
| Job job = jobInfo.job; |
| IJobCollector[] collectors = JobCollectorExtensions.getDefault() |
| .getCollectors(); |
| boolean allowSkip = true; |
| for (IJobCollector ext : collectors) { |
| if (ext.noSkipMode(job)) { |
| allowSkip = false; |
| break; |
| } |
| } |
| if (allowSkip) { |
| continue; |
| } |
| // SWTTeslaActivator.debugLog("Waiting job:" + job.getName() + ": " |
| // + job.getClass().getName()); |
| long jobStartTime = jobInfo.startingTime; |
| if (jobInfo.checkForTimeout) { |
| if (jobStartTime + TeslaLimits.getStepModeEnableTimeout() < current |
| && job.getState() == Job.RUNNING |
| && stepModeNext < current) { |
| // Job is sleepping to long time already. |
| // Check for job are slepping |
| // String name = job.getClass().getName(); |
| // Locate thread |
| Map<Thread, StackTraceElement[]> traces = Thread |
| .getAllStackTraces(); |
| boolean toContinue = false; |
| Set<String> names = getSuperClassNames(job); |
| for (Map.Entry<Thread, StackTraceElement[]> thread : traces |
| .entrySet()) { |
| Context ctx = ContextManagement.makeContext(thread |
| .getValue()); |
| if (ctx.contains( |
| "org.eclipse.jface.operation.ModalContext$ModalContextThread", |
| "block")) { |
| // Skip model context, since it could |
| continue; |
| } |
| for (String name : names) { |
| if (ctx.contains( |
| "org.eclipse.core.internal.jobs.Worker", |
| "run") |
| && ctx.contains(name, "run")) { |
| |
| if (ctx.contains("java.lang.Thread", |
| "sleep") |
| || ctx.contains("java.lang.Object", |
| "wait")) { |
| /* |
| * Job are in Thread.sleep(), lets allow |
| * one operation. |
| */ |
| if (!jobInfo.jobInStepMode) { |
| // Print step information |
| SWTTeslaActivator |
| .log("---->>> Begin step mode for Job: " |
| + getCurrentReportNodeName() |
| + " <<---\n(skipping)" |
| + getJobMessage(jobInfo)); |
| } |
| jobInfo.jobInStepMode = true; |
| toContinue = true; |
| wasInStepMode = true; |
| break; |
| } |
| } |
| } |
| } |
| if (toContinue) { |
| continue; |
| } |
| } |
| |
| long timeout = TeslaLimits.getJobTimeout(); |
| if (job.belongsTo(getFamilyAutoBuild())) { |
| timeout = TeslaLimits.getAutoBuildJobTimeout(); |
| } |
| if (jobInfo.jobInStepMode) { |
| timeout = TeslaLimits.getStepModeTimeout(); |
| } |
| if (job.getClass() |
| .getName() |
| .contains( |
| "org.eclipse.debug.internal.ui.DebugUIPlugin")) { |
| timeout = TeslaLimits.getDebugJobTimeout(); |
| } |
| if (jobStartTime + timeout < current) { |
| if (context != null |
| && TeslaEventManager.getManager() |
| .isJobInSyncExec(job, context)) { |
| // Remove from stop waited jobs if called sync |
| // exec |
| jobInfo.checkForTimeout = false; |
| } else { |
| printJobTimeoutLogEntry(job); |
| continue; |
| } |
| } |
| } |
| if (context != null) { |
| if (isAsyncSupported()) { |
| // If we are executed from async finished job lets |
| // filter it |
| if (JobsManager.getInstance().isFinishedAsyncJob(job)) { |
| if (context.containsClass(job.getClass().getName())) { |
| jobsInUI.add(job); |
| continue; |
| } |
| } |
| } |
| if (isSyncSupported()) { |
| // Check for any other job running Display.sleep() |
| if (context.contains(Display.class.getName(), "sleep")) { |
| if (TeslaEventManager.getManager().isJobInSyncExec( |
| job, context)) { |
| // If and only if job is already in synchronizer |
| Map<Thread, StackTraceElement[]> traces = Thread |
| .getAllStackTraces(); |
| Set<String> names = getSuperClassNames(job); |
| Thread jobThread = null; |
| Context jobContext = null; |
| for (Map.Entry<Thread, StackTraceElement[]> thread : traces |
| .entrySet()) { |
| Context ctx = ContextManagement |
| .makeContext(thread.getValue()); |
| for (String name : names) { |
| if (ctx.contains( |
| "org.eclipse.core.internal.jobs.Worker", |
| "run") |
| && ctx.contains(name, "run")) { |
| jobThread = thread.getKey(); |
| jobContext = ctx; |
| } |
| } |
| } |
| if (jobThread != null && jobContext != null) { |
| if (jobContext |
| .contains( |
| "org.eclipse.ui.internal.UISynchronizer", |
| "syncExec") |
| && jobContext |
| .contains( |
| "org.eclipse.ui.internal.Semaphore", |
| "acquire")) { |
| if (!SWTUIPlayer |
| .hasRunnables(PlatformUI |
| .getWorkbench() |
| .getDisplay())) { |
| // also check what sync exec are on |
| // current stack trace |
| List<Context> execs = TeslaEventManager |
| .getManager() |
| .getSyncExecs(); |
| boolean toContinue = true; |
| for (Context context2 : execs) { |
| StackTraceElement[] stackTrace = context2 |
| .getStackTrace(); |
| String className = null; |
| for (int i = 0; i < stackTrace.length; i++) { |
| if (stackTrace[i] |
| .getClassName() |
| .equals("org.eclipse.swt.widgets.Display") |
| && stackTrace[i] |
| .getMethodName() |
| .equals("syncExec")) { |
| className = stackTrace[i + 1] |
| .getClassName(); |
| break; |
| } |
| } |
| if (!context |
| .containsClass(className)) { |
| toContinue = false; |
| } |
| } |
| if (toContinue) { |
| jobsInUI.add(job); |
| continue; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| if (jobInfo.isActive()) |
| realJobs.add(job); |
| } |
| } |
| if (!jobsInUI.isEmpty()) { |
| if (realJobs.size() == 1 |
| && realJobs.get(0).belongsTo(getFamilyAutoBuild())) { |
| realJobs.clear(); |
| } |
| } |
| if (realJobs.size() == 1) { |
| Job job = realJobs.iterator().next(); |
| if (job.belongsTo(getFamilyAutoBuild())) { |
| // Check for modal dialogs are visible |
| int flags = TeslaSWTAccess.getJobFlags(job); |
| // Job is alone and blocked |
| if ((flags & 0xFF) == 0x08) { |
| return logReturnResult(true, realJobs, jobsInUI, info); |
| } |
| final Display display = PlatformUI.getWorkbench().getDisplay(); |
| final boolean value[] = { false }; |
| display.syncExec(new Runnable() { |
| |
| public void run() { |
| Shell[] shells = display.getShells(); |
| for (Shell shell : shells) { |
| if (isModal(shell)) { |
| value[0] = true; |
| } |
| } |
| } |
| }); |
| if (value[0]) { |
| return logReturnResult(true, realJobs, jobsInUI, info); |
| } |
| if (job.getState() != Job.NONE) { |
| return logReturnResult(false, realJobs, jobsInUI, info); |
| } |
| return logReturnResult(true, realJobs, jobsInUI, info); |
| } |
| } |
| if (wasInStepMode && realJobs.isEmpty()) { |
| stepModeNext = current + TeslaLimits.getStepModeStepTime(); |
| } |
| return logReturnResult(realJobs.isEmpty(), realJobs, jobsInUI, info); |
| } |
| |
| private void removeCanceledJobs() { |
| synchronized (jobs) { |
| for (JobInfo job : jobs.values()) { |
| if (JobsManager.getInstance().isCanceled(job.job)) { |
| job.cancel(); |
| } |
| } |
| List<Job> find = Arrays.asList(Job.getJobManager().find(null)); |
| for (Job job : jobs.keySet()) { |
| if (!find.contains(job)) { |
| getOrCreateJobInfo(job).cancel(); |
| } |
| } |
| } |
| } |
| |
| private Set<String> getSuperClassNames(Job job) { |
| Class<?> cl = job.getClass(); |
| Set<String> names = new HashSet<String>(); |
| while (true) { |
| if (cl.equals(Job.class)) { |
| break; |
| } |
| names.add(cl.getName()); |
| Class<?> superclass = cl.getSuperclass(); |
| if (superclass == null) { |
| break; |
| } |
| cl = superclass; |
| } |
| return names; |
| } |
| |
| private void printJobTimeoutLogEntry(Job job) { |
| getOrCreateJobInfo(job).printJobTimeoutLogEntry(); |
| } |
| |
| protected boolean isSyncSupported() { |
| return true; |
| } |
| |
| protected boolean isAsyncSupported() { |
| return true; |
| } |
| |
| public void enable() { |
| this.state = true; |
| this.needDisable = false; |
| // Add all current jobs to wait queue |
| Job[] find = Job.getJobManager().find(null); |
| for (Job job : find) { |
| if ((job instanceof UIJob && job.getState() != Job.SLEEPING) |
| || job.belongsTo(getFamilyAutoBuild())) { |
| JobStatus status = calcJobStatus(job, (long) 0); |
| if (JobStatus.REQUIRED.equals(status)) { |
| if (job.belongsTo(TeslaSWTAccess.getDecoratorManagerFamily())) { |
| JobsManager.getInstance().nulifyTime(job); |
| } |
| JobInfo jobInfo = getOrCreateJobInfo(job); |
| if (jobInfo.rescheduleCounter < TeslaLimits |
| .getJobNullifyRescheduleMaxValue()) { |
| JobsManager.getInstance().nulifyTime(job); |
| } |
| } |
| } |
| } |
| } |
| |
| private static Object getFamilyAutoBuild() { |
| try { |
| return ResourcesPlugin.FAMILY_AUTO_BUILD; |
| } catch (Throwable e) { |
| // Skip |
| } |
| return UIJobCollector.class; |
| } |
| |
| public void disable() { |
| this.state = false; |
| this.needDisable = false; |
| } |
| |
| public void setNeedDisable() { |
| this.needDisable = true; |
| } |
| |
| public int getCount() { |
| synchronized (jobs) { |
| return jobs.size(); |
| } |
| } |
| |
| public List<Job> getJobs() { |
| synchronized (jobs) { |
| ArrayList<Job> rv = new ArrayList<Job>(); |
| for (JobInfo info: jobs.values()) |
| if (info.isActive()) |
| rv.add(info.job); |
| return rv; |
| } |
| } |
| |
| /** |
| * Wait untill will not be empty for timeout |
| * |
| * @param timeout |
| * @throws InterruptedException |
| */ |
| public void join(long timeout) throws InterruptedException { |
| SWTTeslaActivator.debugLog("UIJobCollector is going to join"); |
| long startTime = System.currentTimeMillis(); |
| // Context ctx = ContextManagement.currentContext(); |
| while (true) { |
| removeCanceledJobs(); |
| long delta = System.currentTimeMillis() - startTime; |
| if (delta > timeout) { |
| break; |
| } |
| if (isJoinEmpty()) { |
| break; |
| } |
| |
| List<Job> jobs2 = getJobs(); |
| for (Job job : jobs2) { |
| SWTTeslaActivator.debugLog("Waiting for job:" + job.getName() + " " |
| + job.getState()); |
| } |
| SWTTeslaActivator.debugLog("UIJobCollector is going to join"); |
| Thread.sleep(50); |
| } |
| } |
| |
| private boolean isJoinEmpty() { |
| List<Job> realJobs = new ArrayList<Job>(); |
| synchronized (jobs) { |
| if (jobs.isEmpty()) { |
| return true; |
| } |
| for (JobInfo jobInfo: jobs.values()) { |
| if (!jobInfo.isActive()) |
| continue; |
| Job job = jobInfo.job; |
| Set<String> names = getSuperClassNames(job); |
| |
| // Locate thread |
| Map<Thread, StackTraceElement[]> traces = Thread |
| .getAllStackTraces(); |
| boolean toContinue = false; |
| for (Map.Entry<Thread, StackTraceElement[]> thread : traces |
| .entrySet()) { |
| Context ctx = ContextManagement.makeContext(thread |
| .getValue()); |
| for (String name : names) { |
| if (ctx.contains(name, "run") |
| || ctx.contains(name, "runInUIThread")) { |
| // Job already running |
| if (ctx.contains("org.eclipse.swt.widgets.Display", |
| "sleep")) { |
| // Job are showing dialog. Skip waiting for such |
| // job. |
| toContinue = true; |
| break; |
| } |
| } |
| } |
| } |
| if (toContinue) { |
| continue; |
| } |
| realJobs.add(job); |
| } |
| } |
| if (realJobs.size() == 1) { |
| Job job = realJobs.iterator().next(); |
| if (job.belongsTo(getFamilyAutoBuild())) { |
| // Check for modal dialogs are visible |
| int flags = TeslaSWTAccess.getJobFlags(job); |
| // Job is alone and blocked |
| if (flags == 0x08) { |
| return true; |
| } |
| } |
| } |
| return realJobs.isEmpty(); |
| } |
| |
| public void clean() { |
| synchronized (jobs) { |
| jobs.clear(); |
| stepModeNext = 0; |
| } |
| } |
| } |
| |