/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.ui.core.uiprocess;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.internal.jobs.JobManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.core.runtime.jobs.ProgressProvider;
import org.eclipse.riena.core.singleton.SingletonProvider;
/**
* A job can be presented by several instances of {@link ProgressProvider}. This
* one delegates to those providers.
*/
@SuppressWarnings("restriction")
public class ProgressProviderBridge extends ProgressProvider {
private static final SingletonProvider<ProgressProviderBridge> PPB = new SingletonProvider<ProgressProviderBridge>(
ProgressProviderBridge.class);
private IProgressVisualizerLocator visualizerLocator;
private final Map<Job, IProgressVisualizer> jobToVisualizer = new HashMap<Job, IProgressVisualizer>();
private final Map<Job, UIProcess> jobUiProcess;
public ProgressProviderBridge() {
jobUiProcess = Collections.synchronizedMap(new HashMap<Job, UIProcess>());
registerJobChangeListener();
}
/**
* Registers an internal observer at the {@link JobManager}
*
* @since 3.0
*/
protected void registerJobChangeListener() {
Job.getJobManager().addJobChangeListener(new JobObserver());
}
/**
*
* @return the singleton instance of {@link ProgressProviderBridge}
*/
public static ProgressProviderBridge instance() {
return PPB.getInstance();
}
/**
* Sets the global {@link IProgressVisualizerLocator}
*/
public void setVisualizerFactory(final IProgressVisualizerLocator visualizerLocator) {
this.visualizerLocator = visualizerLocator;
}
@Override
public IProgressMonitor createMonitor(final Job job) {
final ProgressProvider provider = queryProgressProvider(job);
return provider.createMonitor(job);
}
/**
* Locates a {@link ProgressProvider} for the given {@link Job}.The instance
* will be of type {@link UICallbackDispatcher} which dispatches job state
* changes to riena API process listeners.
*/
private ProgressProvider queryProgressProvider(final Job job) {
UIProcess uiprocess = jobUiProcess.get(job);
final Object context = getContext(job);
if (uiprocess == null) {
uiprocess = createDefaultUIProcess(job);
registerMapping(job, uiprocess);
}
final UICallbackDispatcher dispatcher = (UICallbackDispatcher) uiprocess.getAdapter(UICallbackDispatcher.class);
IProgressVisualizer progressVisualizer = jobToVisualizer.get(job);
if (progressVisualizer == null) {
progressVisualizer = visualizerLocator.getProgressVisualizer(context);
jobToVisualizer.put(job, progressVisualizer);
dispatcher.addUIMonitor(progressVisualizer);
}
return dispatcher;
}
private Object getContext(final Job job) {
return job.getProperty(UIProcess.PROPERTY_CONTEXT);
}
/**
* Create a default instance of {@link UIProcess} wrapping the given
* {@link Job}
*/
private UIProcess createDefaultUIProcess(final Job job) {
return new UIProcess(job);
}
/**
* Registers a mapping {@link Job} -> {@link UIProcess}
*/
public synchronized void registerMapping(final Job job, final UIProcess process) {
jobUiProcess.put(job, process);
}
/**
* Unregisters a mapping {@link Job} -> {@link UIProcess}
*/
public synchronized void unregisterMapping(final Job job) {
jobUiProcess.remove(job);
}
/**
*
* @return a list of all registered {@link UIProcess} instances
* @since 3.0
*/
public List<UIProcess> getRegisteredUIProcesses() {
return new ArrayList<UIProcess>(jobUiProcess.values());
}
/**
* Observes the state of jobs. Scheduled jobs will be assigned to an
* instance of {@link UIProcess}. To avoid memory leaks jobs need to be
* unregistered from internal mappings.
*/
private final class JobObserver extends JobChangeAdapter {
@Override
public void scheduled(final IJobChangeEvent event) {
final Job job = event.getJob();
if (jobUiProcess.get(job) == null) {
createDefaultUIProcess(job);
}
}
@Override
public void done(final IJobChangeEvent event) {
final Job job = event.getJob();
jobToVisualizer.remove(job);
unregisterMapping(job);
}
}
}