| /*=============================================================================# |
| # 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; |
| } |
| } |
| |
| } |