blob: 8ef59e533ad99c51597a95150fb0744bbdaea1ef [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 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.File;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import javax.security.auth.login.LoginException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.statet.jcommons.lang.Disposable;
import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
import org.eclipse.statet.ecommons.rmi.core.RMIRegistryManager;
import org.eclipse.statet.ecommons.ts.core.Tool;
import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
import org.eclipse.statet.rj.RjException;
import org.eclipse.statet.rj.eclient.graphics.comclient.ERClientGraphicActionsFactory;
import org.eclipse.statet.rj.rsetups.RSetup;
import org.eclipse.statet.rj.rsetups.RSetupUtil;
import org.eclipse.statet.rj.server.RjsComConfig;
import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
import org.eclipse.statet.rj.server.osgi.ERJContext;
import org.eclipse.statet.rj.servi.RServi;
import org.eclipse.statet.rj.servi.RServiUtil;
import org.eclipse.statet.rj.servi.node.RServiImpl;
import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
import org.eclipse.statet.rj.servi.node.RServiNodeManager;
public class RServiManager implements Disposable {
private static final int LOCAL_INST= 1;
private static final int LOCAL_RSETUP= 2;
private static final int POOL= 3;
private static class Config {
private int mode;
private String address;
}
private final String name;
private Config config= new Config();
private RServiNodeManager localR;
private RServiSession currentSession;
private final List<RServiSession> runningSessions= new ArrayList<>();
public RServiManager(final String appId, final RClientGraphicFactory graphicFactory) {
this.name= appId;
RjsComConfig.setProperty("rj.servi.graphicFactory", graphicFactory);
RjsComConfig.setProperty("rj.servi.comClientGraphicActionsFactory",
new ERClientGraphicActionsFactory() );
}
public void setLocalInst(final String rHome) throws CoreException {
closeRServiSession();
final Config config= new Config();
config.mode= LOCAL_INST;
config.address= rHome;
this.config= config;
final RServiNodeConfig rConfig= new RServiNodeConfig();
rConfig.setRHome(rHome);
rConfig.setEnableVerbose(true);
startLocal(rConfig);
}
public void setRSetup(final String setupId) throws CoreException {
closeRServiSession();
final Config config= new Config();
config.mode= LOCAL_RSETUP;
config.address= setupId;
this.config= config;
final RSetup setup= RSetupUtil.loadSetup(setupId, null);
if (setup == null) {
throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "No R setup with specified id found."));
}
final RServiNodeConfig rConfig= new RServiNodeConfig();
rConfig.setRHome(setup.getRHome());
setLibs(setup.getRLibsSite(), rConfig, "R_LIBS_SITE");
setLibs(setup.getRLibs(), rConfig, "R_LIBS");
setLibs(setup.getRLibsUser(), rConfig, "R_LIBS_USER");
rConfig.setEnableVerbose(true);
startLocal(rConfig);
}
public void setPool(final String poolAddress) {
closeRServiSession();
final Config config= new Config();
config.mode= POOL;
config.address= poolAddress;
this.config= config;
}
private void setLibs(final List<String> locations, final RServiNodeConfig rConfig, final String varName) {
if (locations != null && locations.size() > 0) {
final StringBuilder sb= new StringBuilder(locations.get(0));
for (int i= 0; i < locations.size(); i++) {
sb.append(File.pathSeparatorChar);
sb.append(locations.get(i));
}
rConfig.getEnvironmentVariables().put(varName, sb.toString());
}
}
private void startLocal(final RServiNodeConfig rConfig) throws CoreException {
startLocal(rConfig, new NullProgressMonitor()); // TODO real monitor, e.g. in a Job
}
private void startLocal(final RServiNodeConfig rConfig,
final IProgressMonitor monitor) throws CoreException {
if (rConfig == null) {
throw new NullPointerException("rConfig");
}
if (monitor == null) {
throw new NullPointerException("monitor");
}
try {
final ERJContext context= new ERJContext();
if (System.getSecurityManager() == null) {
if (System.getProperty("java.security.policy") == null) {
final String policyFile= context.getServerPolicyFilePath();
System.setProperty("java.security.policy", policyFile);
}
System.setSecurityManager(new SecurityManager());
}
final RMIRegistry registry= RMIRegistryManager.INSTANCE.getEmbeddedPrivateRegistry(monitor);
final RServiNodeFactory nodeFactory= RServiImpl.createLocalNodeFactory(this.name, context);
nodeFactory.setRegistry(registry);
nodeFactory.setConfig(rConfig);
final RServiNodeManager newLocalR= RServiImpl.createNodeManager(this.name, registry, nodeFactory);
newLocalR.start();
if (this.localR != null) {
this.localR.stop();
this.localR= null;
}
this.localR= newLocalR;
}
catch (final RjException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Local R instance could not created.", e));
}
}
public synchronized Tool getRServiSession() throws CoreException {
if (this.currentSession == null) {
final RServi servi= getRServi("session");
this.currentSession= new RServiSession(servi) {
@Override
protected void terminated() {
synchronized (RServiManager.this.runningSessions) {
RServiManager.this.runningSessions.remove(this);
}
}
};
synchronized (this.runningSessions) {
this.runningSessions.add(this.currentSession);
}
}
return this.currentSession;
}
private void closeRServiSession() {
if (this.currentSession != null) {
this.currentSession.close(false);
this.currentSession= null;
}
}
public void schedule(final ToolRunnable runnable) throws CoreException {
final Tool session= getRServiSession();
final IStatus status;
if (session != null) {
status= session.getQueue().add(runnable);
}
else {
status= new Status(IStatus.ERROR, Activator.BUNDLE_ID,
"R engine not available.");
}
if (!status.isOK()) {
throw new CoreException(status);
}
}
public void scheduleDemo(final ToolRunnable runnable) {
try {
schedule(runnable);
}
catch (final CoreException e) {
final Status status= new Status(e.getStatus().getSeverity(), Activator.BUNDLE_ID,
"Cannot schedule '" + runnable.getLabel() + "'", e);
StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
}
}
@Override
public void dispose() {
this.config= new Config();
final RServiSession[] sessions;
synchronized (this.runningSessions) {
sessions= this.runningSessions.toArray(new RServiSession[this.runningSessions.size()]);
}
for (final RServiSession session : sessions) {
session.close(true);
}
}
private RServi getRServi(final String task) throws CoreException {
final Config config= this.config;
final String key= this.name + "-" + task;
try {
switch (config.mode) {
case LOCAL_INST:
case LOCAL_RSETUP:
return RServiUtil.getRServi(this.localR, key);
case POOL:
return RServiUtil.getRServi(config.address, key);
}
}
catch (final CoreException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
}
catch (final LoginException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
}
catch (final NoSuchElementException e) {
throw new CoreException(new Status(IStatus.INFO, Activator.BUNDLE_ID, "R currently not available, please try again later.", e));
}
throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R is not configured, please check the configuration."));
}
}