| /*=============================================================================# |
| # Copyright (c) 2008, 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.r.nico.impl; |
| |
| import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.LOGIN_ADDRESS_DATA_KEY; |
| import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.LOGIN_CALLBACKS_DATA_KEY; |
| import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.LOGIN_MESSAGE_DATA_KEY; |
| import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.LOGIN_OK_EVENT_ID; |
| import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.LOGIN_REQUEST_EVENT_ID; |
| import static org.eclipse.statet.nico.core.runtime.IToolEventHandler.LOGIN_USERNAME_DATA_KEY; |
| |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.rmi.Naming; |
| import java.rmi.NotBoundException; |
| import java.rmi.RemoteException; |
| import java.rmi.registry.Registry; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.locks.Lock; |
| |
| import javax.security.auth.callback.Callback; |
| import javax.security.auth.login.LoginException; |
| |
| import com.ibm.icu.text.DateFormat; |
| |
| import org.eclipse.core.filesystem.IFileStore; |
| 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.SubProgressMonitor; |
| import org.eclipse.debug.core.model.IProcess; |
| import org.eclipse.osgi.util.NLS; |
| |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.lang.SystemUtils; |
| |
| import org.eclipse.statet.ecommons.io.FileUtil; |
| import org.eclipse.statet.ecommons.rmi.core.RMIAddress; |
| import org.eclipse.statet.ecommons.ts.core.ToolCommandHandler; |
| import org.eclipse.statet.ecommons.ts.core.ToolRunnable; |
| import org.eclipse.statet.ecommons.ts.core.ToolService; |
| |
| import org.eclipse.statet.internal.r.console.core.RConsoleCorePlugin; |
| import org.eclipse.statet.internal.r.nico.RNicoMessages; |
| import org.eclipse.statet.internal.r.rdata.BasicCombinedRElement; |
| import org.eclipse.statet.internal.r.rdata.CombinedFactory; |
| import org.eclipse.statet.internal.r.rdata.REnvironmentVar; |
| import org.eclipse.statet.ltk.ast.core.IAstNode; |
| import org.eclipse.statet.ltk.model.core.elements.IModelElement; |
| import org.eclipse.statet.ltk.model.core.elements.ISourceUnit; |
| import org.eclipse.statet.nico.core.runtime.IConsoleRunnable; |
| import org.eclipse.statet.nico.core.runtime.IRemoteEngineController; |
| import org.eclipse.statet.nico.core.runtime.SubmitType; |
| import org.eclipse.statet.nico.core.runtime.ToolProcess; |
| import org.eclipse.statet.nico.core.runtime.ToolStreamProxy; |
| import org.eclipse.statet.nico.core.util.TrackingConfiguration; |
| import org.eclipse.statet.r.console.core.IRBasicAdapter; |
| import org.eclipse.statet.r.console.core.IRDataAdapter; |
| import org.eclipse.statet.r.console.core.RConsoleTool; |
| import org.eclipse.statet.r.console.core.RDbg; |
| 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.IRElement; |
| import org.eclipse.statet.r.core.model.IRLangSourceElement; |
| import org.eclipse.statet.r.core.model.IRModelInfo; |
| import org.eclipse.statet.r.core.model.IRModelManager; |
| import org.eclipse.statet.r.core.model.IRWorkspaceSourceUnit; |
| import org.eclipse.statet.r.core.model.RElementName; |
| import org.eclipse.statet.r.core.model.RModel; |
| import org.eclipse.statet.r.core.rsource.ast.FDef; |
| import org.eclipse.statet.r.core.rsource.ast.RAst; |
| import org.eclipse.statet.r.core.rsource.ast.RAstNode; |
| import org.eclipse.statet.r.core.tool.IRConsoleService; |
| import org.eclipse.statet.r.nico.AbstractRDbgController; |
| import org.eclipse.statet.r.nico.ICombinedRDataAdapter; |
| import org.eclipse.statet.r.nico.IRModelSrcref; |
| import org.eclipse.statet.r.nico.IRSrcref; |
| import org.eclipse.statet.r.nico.RWorkspaceConfig; |
| import org.eclipse.statet.rj.RjException; |
| import org.eclipse.statet.rj.data.RDataJConverter; |
| import org.eclipse.statet.rj.data.REnvironment; |
| import org.eclipse.statet.rj.data.RLanguage; |
| import org.eclipse.statet.rj.data.RList; |
| import org.eclipse.statet.rj.data.RObject; |
| import org.eclipse.statet.rj.data.RObjectFactory; |
| import org.eclipse.statet.rj.data.RReference; |
| import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory; |
| import org.eclipse.statet.rj.data.impl.RLanguageImpl; |
| import org.eclipse.statet.rj.eclient.core.ToolFQRObject; |
| import org.eclipse.statet.rj.eclient.graphics.comclient.ERClientGraphicActions; |
| import org.eclipse.statet.rj.server.ConsoleWriteCmdItem; |
| import org.eclipse.statet.rj.server.DbgCmdItem; |
| import org.eclipse.statet.rj.server.FxCallback; |
| import org.eclipse.statet.rj.server.REngine; |
| import org.eclipse.statet.rj.server.RjsComConfig; |
| import org.eclipse.statet.rj.server.RjsStatus; |
| import org.eclipse.statet.rj.server.Server; |
| import org.eclipse.statet.rj.server.ServerInfo; |
| import org.eclipse.statet.rj.server.ServerLogin; |
| import org.eclipse.statet.rj.server.client.AbstractRJComClient; |
| import org.eclipse.statet.rj.server.client.FunctionCallImpl; |
| import org.eclipse.statet.rj.server.client.RClientGraphicFactory; |
| import org.eclipse.statet.rj.server.client.RGraphicCreatorImpl; |
| import org.eclipse.statet.rj.server.dbg.CallStack; |
| import org.eclipse.statet.rj.server.dbg.CtrlReport; |
| import org.eclipse.statet.rj.server.dbg.DbgEnablement; |
| import org.eclipse.statet.rj.server.dbg.DbgFilterState; |
| import org.eclipse.statet.rj.server.dbg.DbgRequest; |
| import org.eclipse.statet.rj.server.dbg.ElementTracepointInstallationRequest; |
| import org.eclipse.statet.rj.server.dbg.FlagTracepointInstallationRequest; |
| import org.eclipse.statet.rj.server.dbg.FrameContext; |
| import org.eclipse.statet.rj.server.dbg.FrameContextDetailRequest; |
| import org.eclipse.statet.rj.server.dbg.SetDebugReport; |
| import org.eclipse.statet.rj.server.dbg.SetDebugRequest; |
| import org.eclipse.statet.rj.server.dbg.SrcfileData; |
| import org.eclipse.statet.rj.server.dbg.TracepointEvent; |
| import org.eclipse.statet.rj.server.dbg.TracepointInstallationReport; |
| import org.eclipse.statet.rj.server.dbg.TracepointInstallationRequest; |
| import org.eclipse.statet.rj.server.dbg.TracepointStatesUpdate; |
| import org.eclipse.statet.rj.services.FQRObject; |
| 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.RServiceControlExtension; |
| |
| |
| /** |
| * Controller for RJ-Server |
| */ |
| public class RjsController extends AbstractRDbgController |
| implements IRemoteEngineController, IRDataAdapter, ICombinedRDataAdapter, RServiceControlExtension { |
| |
| |
| static { |
| RjsComConfig.registerRObjectFactory(CombinedFactory.FACTORY_ID, CombinedFactory.INSTANCE); |
| } |
| |
| public static class RjsConnection { |
| |
| private final RMIAddress rmiAddress; |
| private final Server server; |
| |
| |
| private RjsConnection(final RMIAddress rmiAddress, final Server server) { |
| this.rmiAddress= rmiAddress; |
| this.server= server; |
| } |
| |
| |
| public RMIAddress getRMIAddress() { |
| return this.rmiAddress; |
| } |
| |
| public Server getServer() { |
| return this.server; |
| } |
| |
| } |
| |
| |
| public static RjsConnection lookup(final Registry registry, final RemoteException registryException, |
| final RMIAddress address) throws CoreException { |
| if (address == null) { |
| throw new NullPointerException(); |
| } |
| |
| final int[] clientVersion= AbstractRJComClient.version(); |
| clientVersion[2]= -1; |
| final Server server; |
| int[] version; |
| try { |
| if (registryException != null) { |
| throw registryException; |
| } |
| server= (Server) registry.lookup(address.getName()); |
| version= server.getVersion(); |
| } |
| catch (final NotBoundException e) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| "The specified R engine is not in the service registry (RMI).", e )); |
| } |
| catch (final RemoteException e) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| NLS.bind("Cannot access the host/service registry (RMI) at ''{0}''.", address.getRegistryAddress()), |
| e )); |
| } |
| catch (final ClassCastException e) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| NLS.bind("The specified R engine ({0}) is incompatibel to this client ({1}).", RjsUtil.getVersionString(null), RjsUtil.getVersionString(clientVersion)), |
| e )); |
| } |
| if (version.length != 3 || version[0] != clientVersion[0] || version[1] != clientVersion[1]) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| NLS.bind("The specified R engine ({0}) is incompatibel to this client ({1}).", RjsUtil.getVersionString(version), RjsUtil.getVersionString(clientVersion)), |
| null )); |
| } |
| return new RjsConnection(address, server); |
| } |
| |
| |
| public static final int RJS_LOCAL= 1 << 0; |
| public static final int RJS_SETUP_CONSOLE= 1 << 8; |
| |
| |
| private static final IModelElement.Filter TAG_ELEMENT_FILTER= new IModelElement.Filter() { |
| @Override |
| public boolean include(final IModelElement element) { |
| return ((element.getElementType() & IRElement.MASK_C1) == IRElement.C1_METHOD); |
| } |
| }; |
| |
| |
| private class NicoComClient extends AbstractRJComClient { |
| |
| |
| public NicoComClient() { |
| } |
| |
| |
| @Override |
| protected void initGraphicFactory() { |
| final ToolCommandHandler handler= getCommandHandler(INIT_RGRAPHIC_FACTORY_HANDLER_ID); |
| final Map<String, Object> data= new HashMap<>(); |
| final IStatus status= executeHandler(INIT_RGRAPHIC_FACTORY_HANDLER_ID, handler, data, null); |
| final RClientGraphicFactory factory= (RClientGraphicFactory) data.get("factory"); //$NON-NLS-1$ |
| if (status != null && status.isOK() && factory != null) { |
| setGraphicFactory(factory, new ERClientGraphicActions(this, getTool())); |
| } |
| } |
| |
| @Override |
| protected void updateBusy(final boolean isBusy) { |
| // try { |
| RjsController.this.isBusy= isBusy; |
| // } |
| // catch (Exception e) { |
| // } |
| } |
| |
| @Override |
| protected void updatePrompt(final String text, final boolean addToHistory) { |
| try { |
| RjsController.this.setCurrentPromptL(text, addToHistory); |
| } |
| catch (final Exception e) { |
| } |
| } |
| |
| @Override |
| protected void writeConsoleOutput(final byte streamId, final String text) { |
| try { |
| final ToolStreamProxy streams= getStreams(); |
| final SubmitType submitType= getCurrentSubmitType(); |
| |
| switch (streamId) { |
| case ConsoleWriteCmdItem.R_OUTPUT: |
| streams.getOutputStreamMonitor().append(text, submitType, 0); |
| return; |
| case ConsoleWriteCmdItem.R_ERROR: |
| streams.getErrorStreamMonitor().append(text, submitType, 0); |
| return; |
| default: |
| streams.getSystemOutputMonitor().append(text, submitType, 0); |
| return; |
| } |
| } |
| catch (final Exception e) { |
| } |
| } |
| |
| @Override |
| protected void showMessage(final String text) { |
| try { |
| final ToolStreamProxy streams= getStreams(); |
| final SubmitType submitType= getCurrentSubmitType(); |
| |
| streams.getInfoStreamMonitor().append(text, submitType, 0); |
| } |
| catch (final Exception e) { |
| } |
| } |
| |
| |
| @Override |
| protected RList handleUICallback(String commandId, final RList args, |
| final IProgressMonitor monitor) throws Exception { |
| // TODO: allow handlers to use RJ data objects |
| // TODO: allow handlers to return values |
| // TODO: provide extension point for event handlers |
| ToolCommandHandler handler= getCommandHandler(commandId); |
| if (handler == null && commandId.startsWith("r/")) { |
| final String s= commandId.substring(2); |
| handler= getCommandHandler(s); |
| if (handler != null) { |
| commandId= s; |
| } |
| } |
| if (handler != null) { |
| final RDataJConverter converter= new RDataJConverter(); |
| converter.setKeepArray1(false); |
| converter.setRObjectFactory(RjsController.this.fRObjectFactory); |
| |
| final Map<String, Object> javaArgs= new HashMap<>(); |
| if (args != null) { |
| for (int i= 0; i < args.getLength(); i++) { |
| javaArgs.put(args.getName(i), converter.toJava(args.get(i))); |
| } |
| } |
| |
| final IStatus status= handler.execute(commandId, RjsController.this, javaArgs, monitor); |
| switch (status.getSeverity()) { |
| case IStatus.OK: |
| break; |
| default: |
| throw new CoreException(status); |
| } |
| |
| Map<String, Object> javaAnswer= null; |
| if (commandId.equals("common/chooseFile")) { //$NON-NLS-1$ |
| javaAnswer= Collections.singletonMap( |
| "filename", javaArgs.get("filename") ); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| if (javaAnswer != null) { |
| final RList answer= (RList) converter.toRJ(javaAnswer); |
| return answer; |
| } |
| else { |
| return null; |
| } |
| } |
| |
| return super.handleUICallback(commandId, args, monitor); |
| } |
| |
| @Override |
| protected void handleDbgEvent(final byte dbgOp, final Object event) { |
| if (dbgOp == DbgCmdItem.OP_NOTIFY_TP_EVENT) { |
| handle((TracepointEvent) event); |
| } |
| super.handleDbgEvent(dbgOp, event); |
| } |
| |
| @Override |
| protected void log(final IStatus status) { |
| RConsoleCorePlugin.log(status); |
| } |
| |
| @Override |
| protected void handleServerStatus(final RjsStatus serverStatus, final IProgressMonitor monitor) throws CoreException { |
| String specialMessage= null; |
| switch (serverStatus.getCode()) { |
| case 0: |
| return; |
| case Server.S_DISCONNECTED: |
| RjsController.this.fConnectionState= Server.S_DISCONNECTED; |
| //$FALL-THROUGH$ |
| case Server.S_LOST: |
| if (RjsController.this.fConnectionState == Server.S_DISCONNECTED) { |
| specialMessage= RNicoMessages.R_Info_Disconnected_message; |
| break; |
| } |
| else if ((RjsController.this.rjsFlags & RJS_LOCAL) == 0) { |
| RjsController.this.fConnectionState= Server.S_LOST; |
| specialMessage= RNicoMessages.R_Info_ConnectionLost_message; |
| break; |
| } |
| //$FALL-THROUGH$ |
| case Server.S_STOPPED: |
| RjsController.this.fConnectionState= Server.S_STOPPED; |
| specialMessage= RNicoMessages.R_Info_Stopped_message; |
| break; |
| default: |
| throw new IllegalStateException(); |
| } |
| |
| if (!isClosed()) { |
| markAsTerminated(); |
| setClosed(true); |
| handleStatus(new Status(IStatus.INFO, RConsoleCorePlugin.BUNDLE_ID, addTimestampToMessage(specialMessage, System.currentTimeMillis())), monitor); |
| } |
| throw new CoreException(new Status(IStatus.CANCEL, RConsoleCorePlugin.BUNDLE_ID, specialMessage)); |
| } |
| |
| @Override |
| protected void handleStatus(final Status status, final IProgressMonitor monitor) { |
| RjsController.this.handleStatus(status, monitor); |
| } |
| |
| @Override |
| protected void processHotMode() { |
| runHotModeLoop(); |
| } |
| |
| @Override |
| protected void processExtraMode(final int position) { |
| runSuspendedLoopL(SUSPENDED_DEEPLEVEL); |
| } |
| |
| @Override |
| protected void scheduleConnectionCheck() { |
| synchronized (getQueue()) { |
| if (getStatusL().isWaiting()) { |
| scheduleControllerRunnable(new ControllerSystemRunnable( |
| "r/check", "Connection Check") { //$NON-NLS-1$ |
| |
| @Override |
| public void run(final ToolService s, |
| final IProgressMonitor monitor) throws CoreException { |
| RjsController.this.fRjs.runMainLoopPing(monitor); |
| } |
| |
| }); |
| } |
| } |
| } |
| |
| } |
| |
| |
| private final RMIAddress address; |
| private final String[] rArgs; |
| |
| private boolean isBusy= true; |
| |
| private final RjsConnection rjsConnection; |
| private final NicoComClient fRjs= new NicoComClient(); |
| private int fRjsId; |
| |
| private final int rjsFlags; |
| private final Map<String, Object> rjsProperties; |
| |
| private int fConnectionState; |
| |
| private final RObjectFactory fRObjectFactory= DefaultRObjectFactory.INSTANCE; |
| |
| |
| /** |
| * |
| * @param process the R process the controller belongs to |
| * @param address the RMI address |
| * @param connectionInfo the initialization data |
| * @param rjsFlags controller mode flags |
| * @param startup flag to start R (otherwise connect only) |
| * @param rArgs R arguments (required only if startup is <code>true</code>) |
| * @param initialWD |
| */ |
| public RjsController(final RProcess process, |
| final RMIAddress address, final RjsConnection connection, final Map<String, Object> connectionInfo, |
| final int rjsFlags, final String[] rArgs, |
| final Map<String, Object> rjsProperties, final IFileStore initialWD, |
| final RWorkspaceConfig workspaceConfig, |
| final List<TrackingConfiguration> trackingConfigurations) { |
| super(process, connectionInfo); |
| if (address == null || connection == null) { |
| throw new IllegalArgumentException(); |
| } |
| this.address= address; |
| this.rjsConnection= connection; |
| this.rjsFlags= rjsFlags; |
| this.rArgs= rArgs; |
| this.rjsProperties= (rjsProperties != null) ? rjsProperties : new HashMap<>(); |
| |
| process.registerFeatureSet(RConsoleTool.R_DATA_FEATURESET_ID); |
| process.registerFeatureSet("org.eclipse.statet.rj.services.RService"); //$NON-NLS-1$ |
| if ((this.rjsFlags & RJS_LOCAL) == 0) { |
| process.registerFeatureSet(IRemoteEngineController.FEATURE_SET_ID); |
| } |
| |
| setTracksConfig(trackingConfigurations); |
| |
| setWorksapceData(new RWorkspace(this, |
| ((this.rjsFlags & RJS_LOCAL) != 0 || address.isLocalHost()) ? null : |
| address.getHostAddress().getHostAddress(), workspaceConfig )); |
| setWorkspaceDirL(initialWD); |
| initRunnableAdapterL(); |
| } |
| |
| |
| @Override |
| public boolean supportsBusy() { |
| return true; |
| } |
| |
| @Override |
| public boolean isBusy() { |
| return this.isBusy; |
| } |
| |
| @Override |
| public boolean isDisconnected() { |
| return (this.fConnectionState == Server.S_DISCONNECTED || this.fConnectionState == Server.S_LOST); |
| } |
| |
| /** |
| * This is an async operation |
| * cancel is not supported by this implementation |
| * |
| * @param monitor a progress monitor |
| */ |
| @Override |
| public void disconnect(final IProgressMonitor monitor) throws CoreException { |
| switch (getStatus()) { |
| case STARTED_IDLING: |
| case STARTED_SUSPENDED: |
| case STARTED_PROCESSING: |
| case STARTED_PAUSED: |
| monitor.beginTask("Disconnecting from R remote engine...", 1); |
| synchronized (getQueue()) { |
| beginInternalTask(); |
| } |
| try { |
| this.fRjs.getConsoleEngine().disconnect(); |
| this.fConnectionState= Server.S_DISCONNECTED; |
| } |
| catch (final RemoteException e) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| "Disconnecting from R remote engine failed.", e)); |
| } |
| finally { |
| synchronized (getQueue()) { |
| scheduleControllerRunnable(new ControllerSystemRunnable( |
| "common/disconnect/finish", "Disconnect") { //$NON-NLS-1$ |
| |
| @Override |
| public void run(final ToolService s, |
| final IProgressMonitor monitor) throws CoreException { |
| if (!isTerminated()) { |
| RjsController.this.fRjs.runMainLoopPing(monitor); |
| RjsController.this.fRjs.handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_DISCONNECTED), monitor); |
| } |
| } |
| |
| }); |
| endInternalTask(); |
| } |
| monitor.done(); |
| } |
| } |
| } |
| |
| |
| @Override |
| protected ToolRunnable createStartRunnable() { |
| return new StartRunnable() { |
| @Override |
| public String getLabel() { |
| return "Connect to and load remote R engine."; |
| } |
| }; |
| } |
| |
| @Override |
| protected void startToolL(final IProgressMonitor monitor) throws CoreException { |
| this.fRjsId= RjsComConfig.registerClientComHandler(this.fRjs); |
| this.fRjs.initClient(getTool(), this, this.rjsProperties, this.fRjsId); |
| try { |
| final Map<String, Object> data= new HashMap<>(); |
| final ToolCommandHandler loginHandler= getCommandHandler(LOGIN_REQUEST_EVENT_ID); |
| String msg= null; |
| boolean connected= false; |
| while (!connected) { |
| final Map<String, Object> connectionInfo= getTool().getConnectionInfo(); |
| final ServerLogin login= this.rjsConnection.getServer().createLogin(Server.C_CONSOLE_CONNECT); |
| try { |
| final Callback[] callbacks= login.getCallbacks(); |
| if (callbacks != null) { |
| final List<Callback> checked= new ArrayList<>(); |
| FxCallback fx= null; |
| for (final Callback callback : callbacks) { |
| if (callback instanceof FxCallback) { |
| fx= (FxCallback) callback; |
| } |
| else { |
| checked.add(callback); |
| } |
| } |
| |
| if (connectionInfo != null) { |
| data.putAll(connectionInfo); |
| } |
| data.put(LOGIN_ADDRESS_DATA_KEY, (fx != null) ? this.address.getHost() : this.address.getAddress()); |
| data.put(LOGIN_MESSAGE_DATA_KEY, msg); |
| data.put(LOGIN_CALLBACKS_DATA_KEY, checked.toArray(new Callback[checked.size()])); |
| |
| if (loginHandler == null) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| "Login requested but not supported by this configuration.", null )); |
| } |
| if (!loginHandler.execute(LOGIN_REQUEST_EVENT_ID, this, data, monitor).isOK()) { |
| throw new CoreException(Status.CANCEL_STATUS); |
| } |
| |
| if (fx != null) { |
| RjsUtil.handleFxCallback(RjsUtil.getSession(data, new SubProgressMonitor(monitor, 1)), fx, new SubProgressMonitor(monitor, 1)); |
| } |
| } |
| |
| msg= null; |
| if (monitor.isCanceled()) { |
| throw new CoreException(Status.CANCEL_STATUS); |
| } |
| |
| final Map<String, Object> args= new HashMap<>(); |
| args.putAll(this.rjsProperties); |
| REngine rjServer; |
| if ((this.rjsFlags & RJS_SETUP_CONSOLE) != 0) { |
| args.put("args", this.rArgs); //$NON-NLS-1$ |
| rjServer= (REngine) this.rjsConnection.getServer().execute(Server.C_CONSOLE_START, args, login.createAnswer()); |
| } |
| else { |
| rjServer= (REngine) this.rjsConnection.getServer().execute(Server.C_CONSOLE_CONNECT, args, login.createAnswer()); |
| } |
| this.fRjs.setServer(rjServer, 0); |
| connected= true; |
| |
| if (callbacks != null) { |
| loginHandler.execute(LOGIN_OK_EVENT_ID, this, data, monitor); |
| if (connectionInfo != null) { |
| connectionInfo.put(LOGIN_USERNAME_DATA_KEY, data.get(LOGIN_USERNAME_DATA_KEY)); |
| } |
| } |
| } |
| catch (final LoginException e) { |
| msg= e.getLocalizedMessage(); |
| } |
| finally { |
| if (login != null) { |
| login.clearData(); |
| } |
| } |
| } |
| |
| final ServerInfo info= this.rjsConnection.getServer().getInfo(); |
| if (getWorkspaceData().isRemote()) { |
| try { |
| final String wd= FileUtil.toString(getWorkspaceData().toFileStore(info.getDirectory())); |
| if (wd != null) { |
| setStartupWD(wd); |
| } |
| } |
| catch (final CoreException e) {} |
| |
| try { |
| String sep= this.fRjs.getProperty(SystemUtils.FILE_SEPARATOR_KEY); |
| if (sep == null) { |
| final String osName= this.fRjs.getProperty(SystemUtils.OS_NAME_KEY); |
| if (osName != null && SystemUtils.isOSWindows(osName)) { |
| sep= "\\"; //$NON-NLS-1$ |
| } |
| } |
| if (sep != null && !sep.isEmpty()) { |
| setFileSeparatorL(sep.charAt(0)); |
| } |
| } |
| catch (final Exception e) {} |
| } |
| else { |
| setStartupWD(info.getDirectory()); |
| } |
| final long timestamp= info.getTimestamp(); |
| if (timestamp != 0) { |
| setStartupTimestamp(timestamp); |
| } |
| |
| final List<IStatus> warnings= new ArrayList<>(); |
| |
| initTracks(info.getDirectory(), monitor, warnings); |
| |
| if ((this.rjsFlags & RJS_SETUP_CONSOLE) != 0 && !this.startupsRunnables.isEmpty()) { |
| getQueue().add(this.startupsRunnables); |
| this.startupsRunnables.clear(); |
| } |
| |
| if ((this.rjsFlags & RJS_SETUP_CONSOLE) == 0) { |
| handleStatus(new Status(IStatus.INFO, RConsoleCorePlugin.BUNDLE_ID, |
| addTimestampToMessage(RNicoMessages.R_Info_Reconnected_message, getTool().getConnectionTimestamp()) ), |
| monitor); |
| } |
| // fRjs.runMainLoop(null, null, monitor); must not wait at server side |
| this.fRjs.activateConsole(); |
| class RStart2Runnable extends ControllerSystemRunnable implements IConsoleRunnable { |
| RStart2Runnable() { |
| super("r/rj/start2", "Finish Initialization / Read Output"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public SubmitType getSubmitType() { |
| return SubmitType.CONSOLE; |
| } |
| |
| @Override |
| public void run(final ToolService s, |
| final IProgressMonitor monitor) throws CoreException { |
| if (!RjsController.this.fRjs.isConsoleReady()) { // R is still working |
| RjsController.this.fRjs.runMainLoop(null, null, monitor); |
| |
| briefChanged(IRConsoleService.AUTO_CHANGE); |
| } |
| for (final IStatus status : warnings) { |
| handleStatus(status, monitor); |
| } |
| } |
| |
| } |
| scheduleControllerRunnable(new RStart2Runnable()); |
| } |
| catch (final RemoteException e) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| "The R engine could not be started.", e )); |
| } |
| catch (final RjException e) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, |
| "An error occured when creating login data.", e )); |
| } |
| } |
| |
| // public void controlNotification(final RjsComObject com) throws RemoteException { |
| // if (com instanceof RjsStatus) { |
| // final RjsStatusImpl2 serverStatus= (RjsStatusImpl2) com; |
| // if (serverStatus.getCode() == Server.S_DISCONNECTED || serverStatus.getCode() == Server.S_STOPPED) { |
| // scheduleControllerRunnable(new IToolRunnable() { |
| // public String getTypeId() { |
| // return null; |
| // } |
| // public String getLabel() { |
| // return "Update State"; |
| // } |
| // public SubmitType getSubmitType() { |
| // return SubmitType.OTHER; |
| // } |
| // public void changed(final int event, final ToolProcess process) { |
| // } |
| // public void run(final IToolRunnableControllerAdapter tools, final IProgressMonitor monitor) |
| // throws InterruptedException, CoreException { |
| // if (!isTerminated()) { |
| // rjsHandleStatus(serverStatus, monitor); |
| // } |
| // } |
| // |
| // }); |
| // } |
| // } |
| // } |
| |
| |
| protected String addTimestampToMessage(final String message, final long timestamp) { |
| final String datetime= DateFormat.getDateTimeInstance().format(System.currentTimeMillis()); |
| return datetime + " - " + message; //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected void requestHotMode(final boolean async) { |
| this.fRjs.requestHotMode(async); |
| } |
| |
| @Override |
| protected boolean initilizeHotMode() { |
| return this.fRjs.startHotMode(); |
| } |
| |
| @Override |
| protected void onHotModeExit(final IProgressMonitor monitor) { |
| super.onHotModeExit(monitor); |
| try { |
| this.fRjs.finishTask(monitor); |
| } |
| catch (final Throwable e) {} |
| } |
| |
| @Override |
| protected void onTaskFinished(final RunnableData runnableData, final int event, |
| final IProgressMonitor monitor) { |
| try { |
| this.fRjs.finishTask(monitor); |
| } |
| catch (final Throwable e) {} |
| |
| super.onTaskFinished(runnableData, event, monitor); |
| } |
| |
| |
| @Override |
| protected int setSuspended(final int level, final int enterDetail, final Object enterData) { |
| final int diff= super.setSuspended(level, enterDetail, enterData); |
| if (level > 0 && diff > 0) { |
| this.fRjs.requestExtraMode( |
| (AbstractRJComClient.EXTRA_BEFORE | AbstractRJComClient.EXTRA_NESTED) ); |
| } |
| return diff; |
| } |
| |
| @Override |
| protected CallStack doEvalCallStack(final IProgressMonitor monitor) throws CoreException { |
| return (CallStack) this.fRjs.execSyncDbgOp(DbgCmdItem.OP_LOAD_FRAME_LIST, |
| null, monitor ); |
| } |
| |
| @Override |
| protected FrameContext doEvalFrameContext(final int position, |
| final IProgressMonitor monitor) throws Exception { |
| return (FrameContext) this.fRjs.execSyncDbgOp(DbgCmdItem.OP_LOAD_FRAME_CONTEXT, |
| new FrameContextDetailRequest(position), monitor ); |
| } |
| |
| |
| @Override |
| protected void interruptTool() throws UnsupportedOperationException { |
| this.fRjs.runAsyncInterrupt(); |
| } |
| |
| @Override |
| protected void postCancelTask(final int options, final IProgressMonitor monitor) throws CoreException { |
| super.postCancelTask(options, monitor); |
| if (this.fRjs.isConsoleReady()) { |
| this.fCurrentInput= ""; //$NON-NLS-1$ |
| doSubmitL(monitor); |
| this.fCurrentInput= ""; //$NON-NLS-1$ |
| doSubmitL(monitor); |
| } |
| else { |
| // reschedule? |
| } |
| } |
| |
| @Override |
| protected boolean isToolAlive() { |
| if (this.fConnectionState != 0 || !this.fRjs.runAsyncPing()) { |
| return false; |
| } |
| if (Thread.currentThread() == getControllerThread() && !isInHotModeL() |
| && !this.fRjs.isConsoleReady()) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| protected void killTool(final IProgressMonitor monitor) { |
| this.fRjs.setClosed(true); |
| final ToolProcess consoleProcess= getTool(); |
| // TODO: kill remote command? |
| final IProcess[] processes= consoleProcess.getLaunch().getProcesses(); |
| for (int i= 0; i < processes.length; i++) { |
| if (processes[i] != consoleProcess && !processes[i].isTerminated()) { |
| try { |
| processes[i].terminate(); |
| } |
| catch (final Exception e) { |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void clear() { |
| this.fRjs.setClosed(true); |
| |
| super.clear(); |
| |
| if ((this.rjsFlags & RJS_LOCAL) != 0 && !isDisconnected()) { |
| try { |
| Naming.unbind(this.address.getAddress()); |
| } |
| catch (final Throwable e) { |
| } |
| } |
| this.fRjs.disposeAllGraphics(); |
| if (this.fRjsId > 0) { |
| RjsComConfig.unregisterClientComHandler(this.fRjsId); |
| this.fRjsId= 0; |
| } |
| } |
| |
| @Override |
| protected int finishToolL() { |
| int exitCode= 0; |
| if (isDisconnected()) { |
| exitCode= ToolProcess.EXITCODE_DISCONNECTED; |
| } |
| return exitCode; |
| } |
| |
| @Override |
| protected boolean canSuspend(final IProgressMonitor monitor) { |
| return (this.fRjs.getDataLevel() == 0); |
| } |
| |
| @Override |
| protected void doRequestSuspend(final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.execSyncDbgOp(DbgCmdItem.OP_REQUEST_SUSPEND, |
| null, monitor ); |
| } |
| |
| @Override |
| protected SetDebugReport doExec(final SetDebugRequest request, |
| final IProgressMonitor monitor) throws CoreException { |
| return (SetDebugReport) this.fRjs.execSyncDbgOp(DbgCmdItem.OP_SET_DEBUG, request, monitor); |
| } |
| |
| @Override |
| protected CtrlReport doExec(final DbgRequest request, |
| final IProgressMonitor monitor) throws CoreException { |
| return (CtrlReport) this.fRjs.execSyncDbgOp(request.getOp(), request, monitor); |
| } |
| |
| @Override |
| protected void doPrepareSrcfile(final String srcfile, final String statetPath, |
| final IProgressMonitor monitor) throws CoreException { |
| final FunctionCall prepare= createFunctionCall("rj:::.statet.prepareSrcfile"); |
| prepare.addChar("filename", srcfile); |
| prepare.addChar("path", statetPath); |
| prepare.evalVoid(monitor); |
| } |
| |
| @Override |
| public TracepointInstallationReport exec(final TracepointInstallationRequest request, |
| final IProgressMonitor monitor) throws CoreException { |
| if (request instanceof FlagTracepointInstallationRequest) { |
| return (TracepointInstallationReport) this.fRjs.execSyncDbgOp( |
| DbgCmdItem.OP_INSTALL_TP_FLAGS, request, monitor ); |
| } |
| else if (request instanceof ElementTracepointInstallationRequest) { |
| return (TracepointInstallationReport) this.fRjs.execSyncDbgOp( |
| DbgCmdItem.OP_INSTALL_TP_POSITIONS, request, monitor ); |
| } |
| else { |
| throw new IllegalArgumentException("request type not supported"); |
| } |
| } |
| |
| @Override |
| public void exec(final DbgEnablement request) throws CoreException { |
| this.fRjs.execAsyncDbgOp(DbgCmdItem.OP_SET_ENABLEMENT, request); |
| } |
| |
| @Override |
| public void exec(final DbgFilterState request) throws CoreException { |
| this.fRjs.execAsyncDbgOp(DbgCmdItem.OP_RESET_FILTER_STATE, request); |
| } |
| |
| @Override |
| public void exec(final TracepointStatesUpdate request) throws CoreException { |
| this.fRjs.execAsyncDbgOp(DbgCmdItem.OP_UPDATE_TP_STATES, request); |
| } |
| |
| @Override |
| public void exec(final TracepointStatesUpdate request, |
| final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.execSyncDbgOp(DbgCmdItem.OP_UPDATE_TP_STATES, request, monitor); |
| } |
| |
| |
| @Override |
| protected void doSubmitCommandL(final String[] lines, final SrcfileData srcfile, |
| final IRSrcref srcref, |
| final IProgressMonitor monitor) throws CoreException { |
| if ((this.fCurrentPrompt.meta & (IRBasicAdapter.META_PROMPT_DEFAULT | IRBasicAdapter.META_PROMPT_SUSPENDED)) == 0) { |
| super.doSubmitCommandL(lines, srcfile, srcref, monitor); |
| return; |
| } |
| |
| final FunctionCall prepare= createFunctionCall("rj:::.statet.prepareCommand"); |
| prepare.add("lines", this.fRObjectFactory.createVector(this.fRObjectFactory.createCharData(lines))); |
| |
| if (srcfile != null && srcref != null) { |
| final List<String> attributeNames= new ArrayList<>(); |
| final List<RObject> attributeValues= new ArrayList<>(); |
| |
| if (srcfile.getName() != null) { |
| prepare.addChar("filename", srcfile.getName()); |
| } |
| // if (srcfile.workspacePath != null) { |
| // attributeNames.add("statet.Path"); |
| // attributeValues.add(fRObjectFactory.createVector(fRObjectFactory.createCharData( |
| // new String[] { srcfile.workspacePath } ))); |
| // } |
| if (srcfile.getTimestamp() != 0) { |
| attributeNames.add("timestamp"); |
| attributeValues.add(this.fRObjectFactory.createVector(this.fRObjectFactory.createNumData( |
| new double[] { srcfile.getTimestamp() } ))); |
| } |
| final int[] rjSrcref= RDbg.createRJSrcref(srcref); |
| if (rjSrcref != null) { |
| attributeNames.add("linesSrcref"); |
| attributeValues.add(this.fRObjectFactory.createVector(this.fRObjectFactory.createIntData( |
| rjSrcref ))); |
| } |
| |
| if (attributeNames.size() > 0) { |
| prepare.add("srcfileAttributes", this.fRObjectFactory.createList( |
| attributeValues.toArray(new RObject[attributeValues.size()]), |
| attributeNames.toArray(new String[attributeNames.size()]) )); |
| } |
| |
| if (srcref instanceof IRModelSrcref) { |
| // Move to abstract controller or breakpoint adapter? |
| final IRModelSrcref modelSrcref= (IRModelSrcref) srcref; |
| final List<IRLangSourceElement> elements= modelSrcref.getElements(); |
| if (elements.size() > 0) { |
| final List<String> elementIds= new ArrayList<>(elements.size()); |
| final List<RObject> elementIndexes= new ArrayList<>(elements.size()); |
| for (final IRLangSourceElement element : elements) { |
| if (TAG_ELEMENT_FILTER.include(element)) { |
| final FDef fdef= element.getAdapter(FDef.class); |
| if (fdef != null) { |
| final String elementId= RDbg.getElementId(element); |
| final RAstNode cont= fdef.getContChild(); |
| final int[] path= RAst.computeRExpressionIndex(cont, |
| RAst.getRRootNode(cont, modelSrcref) ); |
| if (elementId != null && path != null) { |
| final int[] fullPath= new int[path.length+1]; |
| fullPath[0]= 1; |
| System.arraycopy(path, 0, fullPath, 1, path.length); |
| elementIds.add(elementId); |
| elementIndexes.add(this.fRObjectFactory.createVector( |
| this.fRObjectFactory.createIntData(fullPath))); |
| } |
| } |
| } |
| } |
| if (elementIds.size() > 0) { |
| prepare.add("elementIds", this.fRObjectFactory.createList( |
| elementIndexes.toArray(new RObject[elementIndexes.size()]), |
| elementIds.toArray(new String[elementIds.size()]) )); |
| } |
| } |
| } |
| } |
| |
| prepare.evalVoid(monitor); |
| |
| final boolean addToHistory= (this.fCurrentPrompt.meta & IRBasicAdapter.META_HISTORY_DONTADD) == 0; |
| this.fCurrentInput= lines[0]; |
| doBeforeSubmitL(); |
| for (int i= 1; i < lines.length; i++) { |
| setCurrentPromptL(this.continuePromptText, addToHistory); |
| this.fCurrentInput= lines[i]; |
| doBeforeSubmitL(); |
| } |
| this.fCurrentInput= "rj:::.statet.evalCommand()"; |
| doSubmitL(monitor); |
| } |
| |
| @Override |
| public void doSubmitFileCommandToConsole(final String[] lines, |
| final SrcfileData srcfile, final ISourceUnit su, |
| final IProgressMonitor monitor) throws CoreException { |
| if (srcfile != null && su instanceof IRWorkspaceSourceUnit |
| && su.getModelTypeId() == RModel.R_TYPE_ID) { |
| try { |
| final IRModelInfo modelInfo= (IRModelInfo) su.getModelInfo(RModel.R_TYPE_ID, |
| IRModelManager.MODEL_FILE, monitor ); |
| if (modelInfo != null) { |
| final IRLangSourceElement fileElement= modelInfo.getSourceElement(); |
| final RAstNode rootNode= (RAstNode) fileElement.getAdapter(IAstNode.class); |
| final List<? extends IRLangSourceElement> elements= modelInfo.getSourceElement() |
| .getSourceChildren(TAG_ELEMENT_FILTER); |
| |
| final List<String> elementIds= new ArrayList<>(elements.size()); |
| final List<RObject> elementIndexes= new ArrayList<>(elements.size()); |
| |
| for (final IRLangSourceElement element : elements) { |
| final FDef fdef= element.getAdapter(FDef.class); |
| if (fdef != null) { |
| final String elementId= RDbg.getElementId(element); |
| final RAstNode cont= fdef.getContChild(); |
| final int[] path= RAst.computeRExpressionIndex(cont, rootNode); |
| if (elementId != null && path != null) { |
| elementIds.add(elementId); |
| elementIndexes.add(this.fRObjectFactory.createVector( |
| this.fRObjectFactory.createIntData(path))); |
| } |
| } |
| } |
| |
| final FunctionCall prepare= createFunctionCall("rj:::.statet.prepareSource"); //$NON-NLS-1$ |
| prepare.add(this.fRObjectFactory.createList(new RObject[] { |
| this.fRObjectFactory.createVector(this.fRObjectFactory.createCharData( |
| new String[] { srcfile.getPath() })), |
| this.fRObjectFactory.createVector(this.fRObjectFactory.createNumData( |
| new double[] { srcfile.getTimestamp() })), |
| this.fRObjectFactory.createVector(this.fRObjectFactory.createIntData( |
| new int[] { rootNode.getChildCount() })), |
| this.fRObjectFactory.createList( |
| elementIndexes.toArray(new RObject[elementIndexes.size()]), |
| elementIds.toArray(new String[elementIds.size()]) ), |
| }, new String[] { "path", "timestamp", "exprsLength", "elementIds" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| prepare.evalVoid(monitor); |
| } |
| } |
| catch (final CoreException e) { |
| RConsoleCorePlugin.log(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, -1, |
| NLS.bind("An error occurred when preparing element tagging for file ''{0}''.", |
| srcfile.getPath() ), e )); |
| } |
| } |
| super.doSubmitFileCommandToConsole(lines, srcfile, su, monitor); |
| } |
| |
| @Override |
| protected void doSubmitL(final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.answerConsole(this.fCurrentInput + this.fLineSeparator, monitor); |
| } |
| |
| |
| @Override |
| public String getProperty(final String key) { |
| return this.fRjs.getProperty(key); |
| } |
| |
| @Override |
| public RPlatform getPlatform() { |
| return this.fRjs.getRPlatform(); |
| } |
| |
| @Override |
| public void evalVoid(final String command, |
| final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.evalVoid(command, null, |
| monitor ); |
| } |
| |
| @Override |
| public void evalVoid(final String command, final @Nullable RObject envir, |
| final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.evalVoid(command, envir, |
| monitor ); |
| } |
| |
| @Override |
| public RObject evalData(final String command, |
| final IProgressMonitor monitor) throws CoreException { |
| return this.fRjs.evalData(command, null, |
| null, 0, -1, monitor ); |
| } |
| |
| @Override |
| public RObject evalData(final String command, final @Nullable String factoryId, |
| final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| return this.fRjs.evalData(command, null, |
| factoryId, options, depth, monitor ); |
| } |
| |
| @Override |
| public RObject evalData(final String command, final @Nullable RObject envir, |
| final @Nullable String factoryId, final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| return this.fRjs.evalData(command, envir, |
| factoryId, options, depth, monitor ); |
| } |
| |
| @Override |
| public RObject evalData(final RReference reference, |
| final IProgressMonitor monitor) throws CoreException { |
| return this.fRjs.evalData(reference, null, 0, -1, |
| monitor ); |
| } |
| |
| @Override |
| public RObject evalData(final RReference reference, |
| final @Nullable String factoryId, final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| return this.fRjs.evalData(reference, |
| factoryId, options, depth, monitor ); |
| } |
| |
| @Override |
| public FQRObject findData(final String symbol, final @Nullable RObject env, final boolean inherits, |
| final @Nullable String factoryId, final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| final RObject[] data= this.fRjs.findData(symbol, env, inherits, |
| factoryId, options, depth, monitor ); |
| if (data != null) { |
| return new ToolFQRObject(getTool(), (REnvironment) data[1], symbol, data[0]); |
| } |
| return null; |
| } |
| |
| |
| private BasicCombinedRElement checkCombinedRElement(final @Nullable RObject data, |
| final int options, final @Nullable RElementName name) { |
| if (data instanceof BasicCombinedRElement) { |
| final BasicCombinedRElement e= (BasicCombinedRElement) data; |
| if (e.getRObjectType() == RObject.TYPE_ENVIRONMENT) { |
| ((REnvironmentVar) e).setSource(getTool(), getChangeStamp(), options); |
| } |
| if (name != null) { |
| e.setElementName(name); |
| } |
| return e; |
| } |
| return null; |
| } |
| |
| @Override |
| public CombinedRElement evalCombinedStruct(final String command, |
| final int options, final int depth, final @Nullable RElementName name, |
| final IProgressMonitor monitor) throws CoreException { |
| final RObject data= this.fRjs.evalData(command, null, |
| CombinedFactory.FACTORY_ID, (options | RObjectFactory.F_ONLY_STRUCT), depth, |
| monitor ); |
| return checkCombinedRElement(data, options, name); |
| } |
| |
| @Override |
| public CombinedRElement evalCombinedStruct(final String command, final @Nullable RObject envir, |
| final int options, final int depth, final @Nullable RElementName name, |
| final IProgressMonitor monitor) throws CoreException { |
| final RObject data= this.fRjs.evalData(command, envir, |
| CombinedFactory.FACTORY_ID, (options | RObjectFactory.F_ONLY_STRUCT), depth, |
| monitor ); |
| return checkCombinedRElement(data, options, name); |
| } |
| |
| private CombinedRElement evalCombinedStructSpecialEnv(final RElementName name, |
| final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| final byte envType; |
| switch (name.getType()) { |
| case RElementName.SCOPE_NS: |
| envType= REnvironment.ENVTYPE_NAMESPACE_EXPORTS; |
| break; |
| case RElementName.SCOPE_NS_INT: |
| envType= REnvironment.ENVTYPE_NAMESPACE; |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| final RObject data= this.fRjs.evalData(envType, name.getSegmentName(), |
| CombinedFactory.FACTORY_ID, (options | RObjectFactory.F_ONLY_STRUCT), depth, |
| monitor ); |
| return checkCombinedRElement(data, options, name); |
| } |
| |
| @Override |
| public CombinedRElement evalCombinedStruct(final RElementName name, |
| final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| switch (name.getType()) { |
| case RElementName.SCOPE_NS: |
| case RElementName.SCOPE_NS_INT: |
| if (name.getNextSegment() == null) { |
| return evalCombinedStructSpecialEnv(name, options, depth, monitor); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| final String command= name.getDisplayName(RElementName.DISPLAY_FQN | RElementName.DISPLAY_EXACT); |
| if (command == null) { |
| throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0, "Illegal R element name.", null)); |
| } |
| return evalCombinedStruct(command, options, depth, name, monitor); |
| } |
| |
| @Override |
| public CombinedRElement evalCombinedStruct(final RReference reference, |
| final int options, final int depth, final @Nullable RElementName name, |
| final IProgressMonitor monitor) throws CoreException { |
| final RObject data= evalData(reference, |
| CombinedFactory.FACTORY_ID, (options | RObjectFactory.F_ONLY_STRUCT), depth, |
| monitor ); |
| return checkCombinedRElement(data, options, name); |
| } |
| |
| private boolean isValidSymbol(final RElementName name) { |
| return (name.getType() == RElementName.MAIN_DEFAULT && name.getSegmentName() != null |
| && name.getNextSegment() == null ); |
| } |
| |
| private RLanguage createLangObject(final RElementName name, final String arg) { |
| final String expr= name.getDisplayName(RElementName.DISPLAY_FQN | RElementName.DISPLAY_EXACT); |
| if (expr == null) { |
| throw new IllegalArgumentException(arg); |
| } |
| return new RLanguageImpl(RLanguage.CALL, expr, null); |
| } |
| |
| @Override |
| public @Nullable CombinedRElement findCombinedStruct(final RElementName symbol, |
| final @Nullable RObject env, final boolean inherits, |
| final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| if (!isValidSymbol(symbol)) { |
| throw new IllegalArgumentException("symbol"); //$NON-NLS-1$ |
| } |
| final RObject[] data= this.fRjs.findData(symbol.getSegmentName(), env, inherits, |
| CombinedFactory.FACTORY_ID, (options | RObjectFactory.F_ONLY_STRUCT), depth, |
| monitor ); |
| if (data != null) { |
| final BasicCombinedRElement element= checkCombinedRElement(data[0], options, symbol); |
| if (element != null) { |
| element.setParent(checkCombinedRElement(data[1], options, |
| (env instanceof CombinedRElement) ? ((CombinedRElement) env).getElementName() : null )); |
| return element; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable CombinedRElement findCombinedStruct(final RElementName symbol, |
| final @Nullable RElementName envName, final boolean inherits, |
| final int options, final int depth, |
| final IProgressMonitor monitor) throws CoreException { |
| if (!isValidSymbol(symbol)) { |
| throw new IllegalArgumentException("symbol"); //$NON-NLS-1$ |
| } |
| final RLanguage env= (envName != null) ? createLangObject(envName, "envName") : null; |
| final RObject[] data= this.fRjs.findData(symbol.getSegmentName(), env, inherits, |
| CombinedFactory.FACTORY_ID, (options | RObjectFactory.F_ONLY_STRUCT), depth, |
| monitor ); |
| if (data != null) { |
| final BasicCombinedRElement element= checkCombinedRElement(data[0], options, symbol); |
| if (element != null) { |
| element.setParent(checkCombinedRElement(data[1], options, envName)); |
| return element; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public void assignData(final String expression, final RObject data, |
| final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.assignData(expression, data, null, monitor); |
| } |
| |
| @Override |
| public void downloadFile(final OutputStream out, final String fileName, final int options, |
| final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.downloadFile(out, fileName, options, monitor); |
| } |
| |
| @Override |
| public byte[] downloadFile(final String fileName, final int options, |
| final IProgressMonitor monitor) throws CoreException { |
| return this.fRjs.downloadFile(fileName, options, monitor); |
| } |
| |
| @Override |
| public void uploadFile(final InputStream in, final long length, final String fileName, final int options, |
| final IProgressMonitor monitor) throws CoreException { |
| this.fRjs.uploadFile(in, length, fileName, options, monitor); |
| } |
| |
| @Override |
| public FunctionCall createFunctionCall(final String name) throws CoreException { |
| return new FunctionCallImpl(this.fRjs, name, this.fRObjectFactory); |
| } |
| |
| @Override |
| public RGraphicCreator createRGraphicCreator(final int options) throws CoreException { |
| return new RGraphicCreatorImpl(this, this.fRjs, options); |
| } |
| |
| |
| @Override |
| public void addCancelHandler(final Callable<Boolean> handler) { |
| this.fRjs.addCancelHandler(handler); |
| } |
| |
| @Override |
| public void removeCancelHandler(final Callable<Boolean> handler) { |
| this.fRjs.removeCancelHandler(handler); |
| } |
| |
| @Override |
| public Lock getWaitLock() { |
| return this.fRjs.getWaitLock(); |
| } |
| |
| @Override |
| public void waitingForUser(final IProgressMonitor monitor) { |
| this.fRjs.waitingForUser(); |
| } |
| |
| @Override |
| public void resume() { |
| this.fRjs.resume(); |
| } |
| |
| } |