blob: 3d0f24b582dab12e82d9b2c3348b8437df1d7328 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.r;
import org.apache.commons.lang.StringUtils;
import org.apache.zeppelin.interpreter.AbstractInterpreter;
import org.apache.zeppelin.interpreter.BaseZeppelinContext;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterException;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* One shiny Interpreter can host more than one Shiny app.
* They are organized by app name which you specify by paragraph local properties.
* e.g. %shiny(app=app_1)
*
* If you don't specify 'app', then default app name 'default' will be used.
*
* One shiny app is composed of at least 3 paragraph (last one is optional)
* <p>
* <ul>
* <li>UI paragraph e.g. %r.shiny(type=ui) </li>
* <li>Server paragraph e.g. %r.shiny(type=server) </li>
* <li>Run paragraph e.g. %r.shiny(type=run) </li>
* <li>Normal R code paragraph(optional) e.g. %r.shiny </li>
* </ul>
* <p>
*/
public class ShinyInterpreter extends AbstractInterpreter {
private static final Logger LOGGER = LoggerFactory.getLogger(ShinyInterpreter.class);
private static final String DEFAULT_APP_NAME = "default";
private Map<String, IRInterpreter> shinyIRInterpreters = new HashMap<>();
private RZeppelinContext z;
public ShinyInterpreter(Properties properties) {
super(properties);
}
@Override
public void open() throws InterpreterException {
this.z = new RZeppelinContext(getInterpreterGroup().getInterpreterHookRegistry(), 1000);
}
@Override
public void close() throws InterpreterException {
for (Map.Entry<String,IRInterpreter> entry : shinyIRInterpreters.entrySet()) {
LOGGER.info("Closing IRInterpreter: " + entry.getKey());
// Stop shiny app first otherwise the R process can not be terminated.
entry.getValue().cancel(InterpreterContext.get());
entry.getValue().close();
}
}
@Override
public void cancel(InterpreterContext context) throws InterpreterException {
String shinyApp = context.getStringLocalProperty("app", DEFAULT_APP_NAME);
IRInterpreter irInterpreter = getIRInterpreter(shinyApp);
irInterpreter.cancel(context);
}
@Override
public FormType getFormType() throws InterpreterException {
return FormType.NATIVE;
}
@Override
public int getProgress(InterpreterContext context) throws InterpreterException {
return 0;
}
@Override
public BaseZeppelinContext getZeppelinContext() {
return this.z;
}
@Override
public InterpreterResult internalInterpret(String st, InterpreterContext context)
throws InterpreterException {
String shinyApp = context.getStringLocalProperty("app", DEFAULT_APP_NAME);
String shinyType = context.getStringLocalProperty("type", "");
IRInterpreter irInterpreter = getIRInterpreter(shinyApp);
if (StringUtils.isBlank(shinyType)) {
return irInterpreter.internalInterpret(st, context);
} else if (shinyType.equals("run")) {
try {
return irInterpreter.runShinyApp(context);
} catch (IOException e) {
throw new InterpreterException(e);
}
} else if (shinyType.equals("ui")) {
return irInterpreter.shinyUI(st, context);
} else if (shinyType.equals("server")) {
return irInterpreter.shinyServer(st, context);
} else {
throw new InterpreterException("Unknown shiny type: " + shinyType);
}
}
/**
* Get the specific IRInterpreter for this shinyApp.
* One ShinyApp is owned by one IRInterpreter(R session).
*
* @param shinyApp
* @return
* @throws InterpreterException
*/
private IRInterpreter getIRInterpreter(String shinyApp) throws InterpreterException {
IRInterpreter irInterpreter = null;
synchronized (shinyIRInterpreters) {
irInterpreter = shinyIRInterpreters.get(shinyApp);
if (irInterpreter == null) {
irInterpreter = createIRInterpreter();
irInterpreter.setInterpreterGroup(getInterpreterGroup());
irInterpreter.open();
shinyIRInterpreters.put(shinyApp, irInterpreter);
}
}
return irInterpreter;
}
/**
* Subclass can overwrite this. e.g. SparkShinyInterpreter.
* @return
*/
protected IRInterpreter createIRInterpreter() {
return new IRInterpreter(properties);
}
}