blob: 4050ed15d178e65c81fe8973deb73d3ee3fb8750 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2019 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.rhelp.server.update;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import static org.eclipse.statet.rhelp.server.Application.BUNDLE_ID;
import java.util.NoSuchElementException;
import javax.security.auth.login.LoginException;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.rmi.RMIRegistry;
import org.eclipse.statet.jcommons.rmi.RMIRegistryManager;
import org.eclipse.statet.jcommons.runtime.ClassLoaderUtils;
import org.eclipse.statet.jcommons.status.ErrorStatus;
import org.eclipse.statet.jcommons.status.ProgressMonitor;
import org.eclipse.statet.jcommons.status.StatusException;
import org.eclipse.statet.rhelp.server.Application;
import org.eclipse.statet.rj.RjException;
import org.eclipse.statet.rj.renv.core.REnv;
import org.eclipse.statet.rj.renv.core.REnvConfiguration;
import org.eclipse.statet.rj.server.util.RJContext;
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;
@NonNullByDefault
public class REnvServiController {
private static final int LOCAL_RENV= 1;
private static final int POOL= 3;
private static class Config {
private final int mode;
private @Nullable String address;
private @Nullable RServiNodeManager localR;
public Config(final int mode) {
this.mode= mode;
}
}
private static final Config NO_CONFIG= new Config(0);
private final REnv rEnv;
private @Nullable RServiNodeConfig localConfig;
private Config current= NO_CONFIG;
public REnvServiController(final REnv rEnv) {
this.rEnv= rEnv;
}
public void configure() throws StatusException {
final REnvConfiguration rEnvConfig= this.rEnv.get(REnvConfiguration.class);
final RServiNodeConfig rServiConfig= new RServiNodeConfig();
rServiConfig.load(rEnvConfig);
try {
final Class<?> handlerClass= Class.forName("org.springframework.boot.loader.jar.Handler");
final String url= ClassLoaderUtils.getClassLocationUrlString(handlerClass);
rServiConfig.addToClasspath(ClassLoaderUtils.toJClassPathEntryString(url));
rServiConfig.setJavaArgs("-Djava.protocol.handler.pkgs=org.springframework.boot.loader"); //$NON-NLS-1$
}
catch (final ClassNotFoundException e) {
final String url= ClassLoaderUtils.getClassLocationUrlString(REnvServiController.class);
if (!url.startsWith("file:")) {
throw new StatusException(new ErrorStatus(Application.BUNDLE_ID,
"An error occurred when configuring protocol handler for fat jar.",
e ));
}
}
this.localConfig= rServiConfig;
}
public void startR(final ProgressMonitor m) throws StatusException {
startLocal(new Config(LOCAL_RENV), m);
}
public void stopR() {
set(NO_CONFIG);
}
public void setPool(final String poolAddress) {
final Config config= new Config(POOL);
config.address= poolAddress;
set(config);
}
private void startLocal(final Config config,
final ProgressMonitor m) throws StatusException {
nonNullAssert(config);
final RServiNodeConfig rServiConfig= this.localConfig;
if (rServiConfig == null) {
throw new IllegalStateException("R is not yet configured.");
}
try {
RJContext.class.getProtectionDomain().getCodeSource().getLocation();
final RJContext context= new RJContext(RJContext.detectRJLibPaths());
// 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.rEnv.getId(), context );
nodeFactory.setRegistry(registry);
nodeFactory.setConfig(rServiConfig);
final RServiNodeManager localR= RServiImpl.createNodeManager(
this.rEnv.getId(), registry, nodeFactory );
localR.start();
config.localR= localR;
set(config);
}
catch (final RjException e) {
throw new StatusException(new ErrorStatus(BUNDLE_ID,
"Local R instance could not created.", e ));
}
}
private void set(final Config config) {
Config previous;
synchronized (this) {
previous= this.current;
this.current= config;
}
if (previous != null && previous.localR != null) {
previous.localR.stop();
}
}
@SuppressWarnings("null")
public RServi getRServi(final String task) throws StatusException {
final Config config= this.current;
final String key= this.rEnv.getId() + "->" + task;
try {
switch (config.mode) {
case LOCAL_RENV:
return RServiUtils.getRServi(config.localR, key);
case POOL:
return RServiUtils.getRServi(config.address, key);
}
}
catch (final StatusException e) {
throw new StatusException(new ErrorStatus(BUNDLE_ID,
"R not available, please check the configuration.", e ));
}
catch (final LoginException e) {
throw new StatusException(new ErrorStatus(BUNDLE_ID,
"R not available, please check the configuration.", e ));
}
catch (final NoSuchElementException e) {
throw new StatusException(new ErrorStatus(BUNDLE_ID,
"R currently not available, please try again later.", e ));
}
throw new StatusException(new ErrorStatus(BUNDLE_ID,
"R is not configured, please check the configuration." ));
}
}