blob: 306063e5ec7763a99d2b34b9fe1c525b7e619773 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2015, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.r.console.core.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.status.Status;
import org.eclipse.statet.r.console.core.RProcess;
import org.eclipse.statet.r.core.data.CombinedRElement;
import org.eclipse.statet.r.core.model.RElementName;
import org.eclipse.statet.rj.data.RReference;
public class LoadReferencesUtil {
public static final int MAX_EXPLICITE_WAIT= 250;
public static final int MAX_AUTO_WAIT= 100;
private class LoadRunnable extends LoadReferenceRunnable implements Runnable {
public LoadRunnable(final RReference reference, final RProcess tool,
final int stamp, final String cause) {
super(reference, tool, stamp, cause);
setFinishRunnable(this);
}
public LoadRunnable(final RElementName name, final RProcess tool,
final int stamp, final String cause) {
super(name, tool, stamp, cause);
setFinishRunnable(this);
}
@Override
public void run() {
taskFinished(this);
}
}
private final RProcess tool;
private final Map<Object, LoadRunnable> resolveTasks= new HashMap<>();
private final AtomicInteger resolveTasksScheduled= new AtomicInteger();
private long waitMillis;
private List<CombinedRElement> resolvedElements;
public LoadReferencesUtil(final RProcess tool, final long waitTimeout) {
if (tool == null) {
throw new NullPointerException("tool"); //$NON-NLS-1$
}
this.tool= tool;
this.waitMillis= waitTimeout;
}
public long getWaitTimeout() {
return this.waitMillis;
}
public void setWaitTimeout(final long millis) {
this.waitMillis= millis;
}
public CombinedRElement resolve(final RReference reference, final int loadOptions) {
if (reference instanceof CombinedRElement) {
final RProcess elementProcess= LoadReferenceRunnable.findRProcess(
(CombinedRElement) reference );
if (elementProcess != this.tool) {
return null;
}
}
else {
return null;
}
final Long key= Long.valueOf(reference.getHandle());
LoadRunnable task= this.resolveTasks.get(key);
if (task != null) {
final int currentOptions= task.getLoadOptions();
if ((currentOptions & loadOptions) == loadOptions) {
return null;
}
synchronized (task) {
if (!task.isStarted()) {
task.setLoadOptions(currentOptions | loadOptions);
return null;
}
}
}
task= new LoadRunnable(reference, this.tool, 0, "Content Assist");
this.resolveTasks.put(key, task);
return schedule(task);
}
public CombinedRElement resolve(final RElementName name, final int loadOptions) {
final RElementName key= name;
LoadRunnable task= this.resolveTasks.get(key);
if (task != null) {
final int currentOptions= task.getLoadOptions();
if ((currentOptions & loadOptions) == loadOptions) {
return task.getResolvedElement();
}
synchronized (task) {
if (!task.isStarted()) {
task.setLoadOptions(currentOptions | loadOptions);
return null;
}
}
}
if (!LoadReferenceRunnable.isAccessAllowed(name, this.tool.getWorkspaceData())) {
return null;
}
task= new LoadRunnable(name, this.tool, 0, "Content Assist");
this.resolveTasks.put(key, task);
return schedule(task);
}
private CombinedRElement schedule(final LoadRunnable task) {
synchronized (task) {
final long startTime= System.nanoTime();
if (task.getTool().getQueue().addHot(task).getSeverity() == Status.OK) {
try {
final long wait= this.waitMillis;
if (wait > 0) {
task.wait(wait);
}
if (task.isFinished()) {
return task.getResolvedElement();
}
else {
this.resolveTasksScheduled.incrementAndGet();
return null;
}
}
catch (final InterruptedException e) {
task.cancel();
}
finally {
this.waitMillis-= TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
}
}
return null;
}
}
protected void taskFinished(final LoadRunnable runnable) {
final CombinedRElement element= runnable.getResolvedElement();
if (element != null) {
if (this.resolvedElements == null) {
this.resolvedElements= new ArrayList<>();
}
this.resolvedElements.add(element);
}
if (this.resolveTasksScheduled.decrementAndGet() == 0) {
allFinished((this.resolvedElements != null) ?
ImCollections.toList(this.resolvedElements) :
ImCollections.<CombinedRElement>emptyList() );
}
}
protected void allFinished(final ImList<CombinedRElement> resolvedElements) {
}
}