| /*=============================================================================# |
| # Copyright (c) 2017, 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.internal.r.apps.ui.launching; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubMonitor; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.ObjectUtils; |
| import org.eclipse.statet.jcommons.lang.ObjectUtils.ToStringBuilder; |
| |
| import org.eclipse.statet.ecommons.ts.core.SystemRunnable; |
| import org.eclipse.statet.ecommons.ts.core.Tool; |
| |
| import org.eclipse.statet.internal.r.apps.ui.RAppUIPlugin; |
| import org.eclipse.statet.nico.core.runtime.Queue; |
| import org.eclipse.statet.r.apps.ui.VariablesData; |
| import org.eclipse.statet.r.console.core.RProcess; |
| import org.eclipse.statet.r.console.core.RWorkspace; |
| import org.eclipse.statet.r.core.data.CombinedRElement; |
| import org.eclipse.statet.r.core.model.RElementName; |
| import org.eclipse.statet.r.core.tool.TmpUtils; |
| import org.eclipse.statet.r.nico.ICombinedRDataAdapter; |
| import org.eclipse.statet.rj.data.RDataUtils; |
| import org.eclipse.statet.rj.data.RReference; |
| import org.eclipse.statet.rj.data.UnexpectedRDataException; |
| import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable; |
| import org.eclipse.statet.rj.eclient.core.RToolService; |
| import org.eclipse.statet.rj.services.RService; |
| |
| |
| @NonNullByDefault |
| public class DataLoader extends AbstractRToolRunnable implements SystemRunnable { |
| |
| |
| public static final String TASK_ID= "org.eclipse.statet.r.apps/LoadVariables"; //$NON-NLS-1$ |
| |
| |
| private final AppRunner app; |
| |
| private final String expression; |
| |
| private boolean isScheduled; |
| |
| private RWorkspace workspace; |
| |
| private final Set<Long> envs= new HashSet<>(); |
| |
| |
| @SuppressWarnings("null") |
| public DataLoader(final AppRunner app, final String expression) { |
| super(TASK_ID, "Load elements of R app variables"); |
| |
| this.app= app; |
| this.expression= expression; |
| |
| final Queue queue= getTool().getQueue(); |
| queue.addOnIdle(this, 5100); |
| } |
| |
| |
| @SuppressWarnings("null") |
| private RProcess getTool() { |
| return this.app.getTool(); |
| } |
| |
| public void schedule() { |
| synchronized (this) { |
| final Queue queue= getTool().getQueue(); |
| if (!this.isScheduled) { |
| queue.addHot(this); |
| } |
| } |
| } |
| |
| public void stop() { |
| synchronized (this) { |
| final Queue queue= getTool().getQueue(); |
| if (this.isScheduled) { |
| queue.removeHot(this); |
| this.isScheduled= false; |
| } |
| queue.removeOnIdle(this); |
| } |
| } |
| |
| |
| @Override |
| public boolean canRunIn(final Tool tool) { |
| return (tool == this.app.getTool()); |
| } |
| |
| @Override |
| protected void run(final RToolService r, final IProgressMonitor monitor) throws CoreException { |
| if (!this.app.isRunning()) { |
| return; |
| } |
| |
| final SubMonitor m= SubMonitor.convert(monitor); |
| try { |
| final TmpUtils.Item tmpItem= TmpUtils.newItem("appvars", r, m); //$NON-NLS-1$ |
| try { |
| evalExpression(tmpItem, (ICombinedRDataAdapter) r, m); |
| } |
| finally { |
| tmpItem.disposeChecked(m); |
| } |
| } |
| catch (final CoreException | UnexpectedRDataException e) { |
| final ToStringBuilder sb= new ObjectUtils.ToStringBuilder( |
| "An error occurred when evaluating the app variables expression." ); |
| sb.addProp("expression", this.expression); //$NON-NLS-1$ |
| RAppUIPlugin.log(new Status(IStatus.ERROR, RAppUIPlugin.BUNDLE_ID, 0, |
| sb.toString(), e )); |
| this.app.setData(new VariablesData(this.expression, |
| new Status(IStatus.ERROR, RAppUIPlugin.BUNDLE_ID, 0, |
| "Evaluation failed (internal error).", e ))); |
| } |
| finally { |
| this.envs.clear(); |
| |
| synchronized (this) { |
| final Queue queue= getTool().getQueue(); |
| if (this.isScheduled) { |
| queue.removeHot(this); |
| this.isScheduled= false; |
| } |
| } |
| } |
| } |
| |
| private void evalExpression(final TmpUtils.Item tmpItem, final ICombinedRDataAdapter r, |
| final SubMonitor m) throws UnexpectedRDataException, CoreException { |
| final String valueName= tmpItem.createSub("value"); //$NON-NLS-1$ |
| final RElementName valueElementName= RElementName.create(RElementName.MAIN_DEFAULT, |
| valueName ); |
| final RElementName fqElementName= TmpUtils.createFQElementName(valueElementName); |
| |
| CombinedRElement element= null; |
| try { |
| // System.out.println("App Data Update= " + r.getChangeStamp()); |
| // int nframes= RDataUtil.checkSingleIntValue(r.evalData("sys.nframe()", m)); |
| // System.out.println("nframes= " + nframes); |
| // for (int i= 0; i < nframes + 1; i++) { |
| // String s= "evalq(shiny::getDefaultReactiveDomain(), envir=sys.frame(" + i + "L))"; |
| // System.out.println("expr= " + s); |
| // |
| // element= r.evalCombinedStruct(s, |
| // 0, RService.DEPTH_REFERENCE, fqElementName, m ); |
| // |
| // System.out.println(((RReference)element).getRClassName()); |
| // } |
| element= r.evalCombinedStruct(this.expression, |
| 0, RService.DEPTH_REFERENCE, fqElementName, m ); |
| } |
| catch (final CoreException e) { |
| final IStatus status= e.getStatus(); |
| this.app.setData(new VariablesData(this.expression, |
| new Status(status.getSeverity(), RAppUIPlugin.BUNDLE_ID, 0, |
| "Evaluation failed: " + e.getLocalizedMessage(), e ))); |
| return; |
| } |
| final RReference ref= RDataUtils.checkRReference(element); |
| |
| tmpItem.set(valueName, ref, m); |
| |
| element= r.getWorkspaceData().resolve(ref, |
| RWorkspace.RESOLVE_UPTODATE | RWorkspace.RESOLVE_RECURSIVE, 0, m); |
| if (element == null) { |
| element= r.findCombinedStruct(valueElementName, TmpUtils.ENV_FQ_ELEMENT_NAME, false, |
| 0, RService.DEPTH_INFINITE, m ); |
| if (element == null) { |
| throw new UnexpectedRDataException("null"); //$NON-NLS-1$ |
| } |
| } |
| RElementName name= RElementName.parseDefault(this.expression); |
| if (name == null) { |
| name= RElementName.create(RElementName.MAIN_OTHER, "variables"); |
| } |
| element= ICombinedRDataAdapter.createReference(element, name); |
| |
| this.app.setData(new VariablesData(this.expression, |
| ImCollections.newList(element) )); |
| } |
| |
| // private void check(final ICombinedRElement element, |
| // final SubMonitor m) throws CoreException { |
| // if (element instanceof ICombinedRList) { |
| // check((ICombinedRList) element, m); |
| // } |
| // } |
| // |
| // private void resolve(final RReference ref, final @Nullable RElementName fullName, |
| // final int loadOptions, final SubMonitor m) throws CoreException { |
| // if (!this.envs.add(ref.getHandle())) { |
| // return; |
| // } |
| // final ICombinedRElement element= this.workspace.resolve(ref, |
| // RWorkspace.RESOLVE_UPTODATE, loadOptions, m ); |
| // check(element, m); |
| // } |
| // |
| // private void check(final ICombinedRList list, |
| // final SubMonitor m) throws CoreException { |
| // if (list.hasModelChildren(null)) { |
| // final long length= list.getLength(); |
| // if (length <= Integer.MAX_VALUE) { |
| // final int l= (int) length; |
| // ITER_CHILDREN : for (int i= 0; i < l; i++) { |
| // final RObject object= list.get(i); |
| // if (object != null) { |
| // switch (object.getRObjectType()) { |
| // case RObject.TYPE_REFERENCE: |
| // if (((RReference) object).getReferencedRObjectType() == RObject.TYPE_ENV) { |
| // resolve((RReference) object, null, 0, m); |
| // } |
| // else { |
| // } |
| // continue ITER_CHILDREN; |
| // case RObject.TYPE_LIST: |
| // case RObject.TYPE_S4OBJECT: |
| // check((ICombinedRList) object, m); |
| // continue ITER_CHILDREN; |
| // default: |
| // continue ITER_CHILDREN; |
| // } |
| // } |
| // } |
| // } |
| // else { |
| // ITER_CHILDREN : for (long i= 0; i < length; i++) { |
| // final RObject object= list.get(i); |
| // if (object != null) { |
| // switch (object.getRObjectType()) { |
| // case RObject.TYPE_REFERENCE: |
| // if (((RReference) object).getReferencedRObjectType() == RObject.TYPE_ENV) { |
| // resolve((RReference) object, null, 0, m); |
| // } |
| // else { |
| // } |
| // continue ITER_CHILDREN; |
| // case RObject.TYPE_LIST: |
| // case RObject.TYPE_S4OBJECT: |
| // check((ICombinedRList) object, m); |
| // continue ITER_CHILDREN; |
| // default: |
| // continue ITER_CHILDREN; |
| // } |
| // } |
| // } |
| // } |
| // } |
| // } |
| |
| } |