blob: f0477fb9f5819d8305d2f088503125a602a7d005 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2011, 2018 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.rj.servi.rcpdemo;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.Status;
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.ui.statushandlers.StatusManager;
import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
import org.eclipse.statet.ecommons.ts.core.Tool;
import org.eclipse.statet.ecommons.ts.core.ToolQueue;
import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
import org.eclipse.statet.ecommons.ts.core.ToolService;
import org.eclipse.statet.internal.rj.servi.RServiImpl;
import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
import org.eclipse.statet.rj.data.RObject;
import org.eclipse.statet.rj.data.RReference;
import org.eclipse.statet.rj.eclient.core.RToolService;
import org.eclipse.statet.rj.servi.RServi;
import org.eclipse.statet.rj.services.FunctionCall;
import org.eclipse.statet.rj.services.RGraphicCreator;
import org.eclipse.statet.rj.services.RPlatform;
import org.eclipse.statet.rj.services.RService;
/**
* Implementations of ECommons Tool Service and Scheduling interfaces (org.eclipse.statet.ecommons.ts.core) for
* RServi using Eclipse jobs.
*/
public class RServiSession extends PlatformObject implements Tool {
private class Queue implements ToolQueue {
@Override
public IStatus add(final ToolRunnable runnable) {
synchronized (RServiSession.this.jobs) {
if (isTerminated()) {
return new Status(IStatus.ERROR, Activator.BUNDLE_ID,
"The R session is terminated.");
}
if (!runnable.changed(ToolRunnable.ADDING_TO, RServiSession.this)) {
return Status.CANCEL_STATUS;
}
final RunnableJob job= new RunnableJob(runnable);
RServiSession.this.jobs.add(job);
job.addJobChangeListener(RServiSession.this.jobListener);
job.schedule();
return Status.OK_STATUS;
}
}
@Override
public void remove(final ToolRunnable runnable) {
RunnableJob removed= null;
synchronized (RServiSession.this.jobs) {
for (int i= 0; i < RServiSession.this.jobs.size(); i++) {
final RunnableJob job= RServiSession.this.jobs.get(i);
if (job.runnable == runnable) {
if (job.runnable.changed(ToolRunnable.REMOVING_FROM, RServiSession.this)) {
removed= job;
RServiSession.this.jobs.remove(i);
break;
}
return;
}
}
}
if (removed != null) {
removed.cancel();
}
}
@Override
public boolean isHotSupported() {
return false;
}
@Override
public IStatus addHot(final ToolRunnable runnable) {
return add(runnable);
}
@Override
public void removeHot(final ToolRunnable runnable) {
remove(runnable);
}
}
private class RServiService implements RToolService, RService, ToolService {
@Override
public Tool getTool() {
return RServiSession.this;
}
@Override
public RPlatform getPlatform() {
return RServiSession.this.servi.getPlatform();
}
@Override
public void evalVoid(final String expression,
final IProgressMonitor monitor) throws CoreException {
RServiSession.this.servi.evalVoid(expression, monitor);
}
@Override
public void evalVoid(final String expression, final RObject envir,
final IProgressMonitor monitor) throws CoreException {
RServiSession.this.servi.evalVoid(expression, envir, monitor);
}
@Override
public RObject evalData(final String expression,
final IProgressMonitor monitor) throws CoreException {
return RServiSession.this.servi.evalData(expression, monitor);
}
@Override
public RObject evalData(final String expression,
final String factoryId, final int options, final int depth,
final IProgressMonitor monitor) throws CoreException {
return RServiSession.this.servi.evalData(expression, factoryId, options, depth, monitor);
}
@Override
public RObject evalData(final String expression, final RObject envir,
final String factoryId, final int options, final int depth,
final IProgressMonitor monitor) throws CoreException {
return RServiSession.this.servi.evalData(expression, envir, factoryId, options, depth, monitor);
}
@Override
public RObject evalData(final RReference reference,
final IProgressMonitor monitor) throws CoreException {
return RServiSession.this.servi.evalData(reference, monitor);
}
@Override
public RObject evalData(final RReference reference,
final String factoryId, final int options, final int depth,
final IProgressMonitor monitor) throws CoreException {
return RServiSession.this.servi.evalData(reference, factoryId, options, depth, monitor);
}
@Override
public void assignData(final String expression, final RObject data,
final IProgressMonitor monitor) throws CoreException {
RServiSession.this.servi.assignData(expression, data, monitor);
}
@Override
public void uploadFile(final InputStream in, final long length, final String fileName,
final int options, final IProgressMonitor monitor) throws CoreException {
RServiSession.this.servi.uploadFile(in, length, fileName, options, monitor);
}
@Override
public void downloadFile(final OutputStream out, final String fileName, final int options,
final IProgressMonitor monitor) throws CoreException {
RServiSession.this.servi.downloadFile(fileName, options, monitor);
}
@Override
public byte[] downloadFile(final String fileName, final int options,
final IProgressMonitor monitor) throws CoreException {
return RServiSession.this.servi.downloadFile(fileName, options, monitor);
}
@Override
public FunctionCall createFunctionCall(final String name) throws CoreException {
return RServiSession.this.servi.createFunctionCall(name);
}
@Override
public RGraphicCreator createRGraphicCreator(final int options) throws CoreException {
return RServiSession.this.servi.createRGraphicCreator(options);
}
}
private class RunnableJob extends Job {
private final ToolRunnable runnable;
public RunnableJob(final ToolRunnable runnable) {
super(runnable.getLabel());
this.runnable= runnable;
setRule(RServiSession.this.schedulingRule);
if (runnable instanceof SystemRunnable) {
setSystem(true);
}
}
@Override
public boolean belongsTo(final Object family) {
return (family == RServiSession.this);
}
@Override
public boolean shouldRun() {
synchronized (RServiSession.this.jobs) {
return RServiSession.this.jobs.remove(this);
}
}
@Override
protected IStatus run(final IProgressMonitor monitor) {
try {
this.runnable.run(RServiSession.this.service, monitor);
this.runnable.changed(ToolRunnable.FINISHING_OK, RServiSession.this);
return Status.OK_STATUS;
}
catch (final CoreException e) {
if (e.getStatus() != null && e.getStatus().getSeverity() == IStatus.CANCEL) {
this.runnable.changed(ToolRunnable.FINISHING_CANCEL, RServiSession.this);
return e.getStatus();
}
final Status status= new Status(IStatus.ERROR, Activator.BUNDLE_ID,
"An error occurred when running " + getName() + ".", e);
StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
this.runnable.changed(ToolRunnable.FINISHING_ERROR, RServiSession.this);
return status;
}
}
}
private class JobListener implements IJobChangeListener {
@Override
public void aboutToRun(final IJobChangeEvent event) {
}
@Override
public void awake(final IJobChangeEvent event) {
}
@Override
public void done(final IJobChangeEvent event) {
if (event.getResult() == Status.CANCEL_STATUS) {
synchronized (RServiSession.this.jobs) {
if (RServiSession.this.jobs.remove(event.getJob())) {
((RunnableJob) event.getJob()).runnable.changed(ToolRunnable.BEING_ABANDONED, RServiSession.this);
}
}
}
}
@Override
public void running(final IJobChangeEvent event) {
}
@Override
public void scheduled(final IJobChangeEvent event) {
}
@Override
public void sleeping(final IJobChangeEvent event) {
}
}
private final Queue queue= new Queue();
private final RServiService service= new RServiService();
private final String label;
private final ISchedulingRule schedulingRule;
private int state;
private RServi servi;
private final List<RunnableJob> jobs= new ArrayList<>();
private final IJobChangeListener jobListener= new JobListener();
public RServiSession(final RServi servi) {
this("R engine", servi, new ISchedulingRule() {
@Override
public boolean contains(final ISchedulingRule rule) {
return (rule == this);
}
@Override
public boolean isConflicting(final ISchedulingRule rule) {
return (rule == this);
}
});
}
public RServiSession(final String label,
final RServi servi, final ISchedulingRule schedulingRule) {
this.label= label;
this.servi= servi;
this.schedulingRule= schedulingRule;
doStart();
}
@Override
public String getMainType() {
return "R";
}
@Override
public boolean isProvidingFeatureSet(final String featureSetId) {
return "org.eclipse.statet.rj.services.RService".equals(featureSetId); //$NON-NLS-1$
}
@Override
public ToolQueue getQueue() {
return this.queue;
}
@Override
public boolean isTerminated() {
return (this.state < 0);
}
private void doStart() {
if (this.servi != null) {
((RServiImpl) this.servi).setRHandle(this);
this.state= 1;
}
else {
doTerminate();
}
}
private void doTerminate() {
if (this.servi != null) {
try {
this.servi.close();
}
catch (final CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.servi= null;
}
if (this.state != -2) {
this.state= -2;
terminated();
}
}
protected void terminated() {
}
@Override
public String getLabel(final int config) {
return this.label;
}
public void close(final boolean immediately) {
synchronized (this.jobs) {
if (this.state < 0) {
return;
}
if (immediately) {
Job.getJobManager().cancel(this);
for (int i= 0; i < this.jobs.size(); i++) {
this.jobs.get(i).runnable.changed(ToolRunnable.BEING_ABANDONED, RServiSession.this);
}
this.jobs.clear();
}
this.queue.add(new SystemRunnable() {
@Override
public String getTypeId() {
return "r/session/close";
}
@Override
public String getLabel() {
return "Close R Session";
}
@Override
public boolean canRunIn(final Tool tool) {
return (tool == RServiSession.this);
}
@Override
public boolean changed(final int event, final Tool tool) {
return true;
}
@Override
public void run(final ToolService service,
final IProgressMonitor monitor) throws CoreException {
doTerminate();
}
});
this.state= -1;
}
}
}