blob: 91abd3070dd27804d9da4e0248bd89ebdb5ce3fe [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.example.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.IStatus;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.statet.jcommons.lang.Disposable;
import org.eclipse.statet.jcommons.rmi.RMIRegistry;
import org.eclipse.statet.jcommons.rmi.RMIRegistryManager;
import org.eclipse.statet.jcommons.status.ErrorStatus;
import org.eclipse.statet.jcommons.status.InfoStatus;
import org.eclipse.statet.jcommons.status.NullProgressMonitor;
import org.eclipse.statet.jcommons.status.ProgressMonitor;
import org.eclipse.statet.jcommons.status.Status;
import org.eclipse.statet.jcommons.status.StatusException;
import org.eclipse.statet.jcommons.ts.core.Tool;
import org.eclipse.statet.jcommons.ts.core.ToolRunnable;
import org.eclipse.statet.ecommons.runtime.core.util.StatusUtils;
import org.eclipse.statet.internal.rj.example.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.RServiUtils;
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 StatusException {
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 StatusException {
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 StatusException(new ErrorStatus(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 StatusException {
startLocal(rConfig, new NullProgressMonitor()); // TODO real monitor, e.g. in a Job
}
private void startLocal(final RServiNodeConfig rConfig,
final ProgressMonitor m) throws StatusException {
if (rConfig == null) {
throw new NullPointerException("rConfig");
}
if (m == 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(m);
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 StatusException(new ErrorStatus(Activator.BUNDLE_ID,
"Local R instance could not created.", e ));
}
}
public synchronized Tool getRServiSession() throws StatusException {
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 StatusException {
final Tool session= getRServiSession();
final Status status;
if (session != null) {
status= session.getQueue().add(runnable);
}
else {
status= new ErrorStatus(Activator.BUNDLE_ID, "R engine not available.");
}
if (status.getSeverity() != Status.OK) {
throw new StatusException(status);
}
}
public void scheduleDemo(final ToolRunnable runnable) {
try {
schedule(runnable);
}
catch (final StatusException e) {
final IStatus status= new org.eclipse.core.runtime.Status(e.getStatus().getSeverity(), Activator.BUNDLE_ID,
"Cannot schedule '" + runnable.getLabel() + "'", StatusUtils.convert(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 StatusException {
final Config config= this.config;
final String key= this.name + "-" + task;
try {
switch (config.mode) {
case LOCAL_INST:
case LOCAL_RSETUP:
return RServiUtils.getRServi(this.localR, key);
case POOL:
return RServiUtils.getRServi(config.address, key);
default:
throw new StatusException(new ErrorStatus(Activator.BUNDLE_ID,
"R is not configured, please check the configuration." ));
}
}
catch (final StatusException e) {
throw new StatusException(new ErrorStatus(Activator.BUNDLE_ID,
"R not available, please check the configuration.",
e ));
}
catch (final LoginException e) {
throw new StatusException(new ErrorStatus(Activator.BUNDLE_ID,
"R not available, please check the configuration.",
e ));
}
catch (final NoSuchElementException e) {
throw new StatusException(new InfoStatus(Activator.BUNDLE_ID,
"R currently not available, please try again later.",
e ));
}
}
}