Skip to content
Closed
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 33 additions & 2 deletions docs/manual/interpreters.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,39 @@ Zeppelin interpreter setting is the configuration of a given interpreter on Zepp

<img src="../assets/themes/zeppelin/img/screenshots/interpreter_setting.png" width="500px">

Properties are exported as environment variable when property name is consisted of upper characters, numbers and underscore ([A-Z_0-9]). Otherwise set properties as JVM property.

Properties are exported as environment variables when property name is consisted of upper characters, numbers and underscore ([A-Z_0-9]). Otherwise set properties as JVM property.

You may use parameters from the context of interpreter by add #{contextParameterName} in value, parameter can be of the following types: string, number, boolean.

###### Context parameters
<table class="table-configuration">
<tr>
<th>Name</th>
<th>Type</th>
</tr>
<tr>
<td>user</td>
<td>string</td>
</tr>
<tr>
<td>noteId</td>
<td>string</td>
</tr>
<tr>
<td>replName</td>
<td>string</td>
</tr>
<tr>
<td>className</td>
<td>string</td>
</tr>
</table>

If context parameter is null then replaced by empty string.

<img src="../assets/themes/zeppelin/img/screenshots/interpreter_setting_with_context_parameters.png" width="800px">

<br>
Each notebook can be bound to multiple Interpreter Settings using setting icon on upper right corner of the notebook.

<img src="../assets/themes/zeppelin/img/screenshots/interpreter_binding.png" width="800px">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@
package org.apache.zeppelin.interpreter;


import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.zeppelin.annotation.ZeppelinApi;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.reflect.FieldUtils;
import org.apache.zeppelin.annotation.Experimental;
import org.apache.zeppelin.annotation.ZeppelinApi;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.scheduler.Scheduler;
import org.apache.zeppelin.scheduler.SchedulerFactory;
Expand Down Expand Up @@ -157,6 +161,8 @@ public Properties getProperty() {
}
}

replaceContextParameters(p);

return p;
}

Expand Down Expand Up @@ -296,6 +302,41 @@ public Interpreter getInterpreterInTheSameSessionByClassName(String className) {
return null;
}

/**
* Replace markers #{contextFieldName} by values from {@link InterpreterContext} fields
* with same name and marker #{user}. If value == null then replace by empty string.
*/
private void replaceContextParameters(Properties properties) {
InterpreterContext interpreterContext = InterpreterContext.get();
if (interpreterContext != null) {
String markerTemplate = "#\\{%s\\}";
List<String> skipFields = Arrays.asList("paragraphTitle", "paragraphId", "paragraphText");
List typesToProcess = Arrays.asList(String.class, Double.class, Float.class, Short.class,
Byte.class, Character.class, Boolean.class, Integer.class, Long.class);
for (String key : properties.stringPropertyNames()) {
String p = properties.getProperty(key);
if (StringUtils.isNotEmpty(p)) {
for (Field field : InterpreterContext.class.getDeclaredFields()) {
Class clazz = field.getType();
if (!skipFields.contains(field.getName()) && (typesToProcess.contains(clazz)
|| clazz.isPrimitive())) {
Object value = null;
try {
value = FieldUtils.readField(field, interpreterContext, true);
} catch (Exception e) {
logger.error("Cannot read value of field {0}", field.getName());
}
p = p.replaceAll(String.format(markerTemplate, field.getName()),
value != null ? value.toString() : StringUtils.EMPTY);
}
}
p = p.replaceAll(String.format(markerTemplate, "user"),
StringUtils.defaultString(userName, StringUtils.EMPTY));
properties.setProperty(key, p);
}
}
}
}

/**
* Type of interpreter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@

package org.apache.zeppelin.interpreter;

import static org.junit.Assert.assertEquals;

import java.util.Properties;

import org.apache.zeppelin.interpreter.remote.mock.MockInterpreterA;
import org.apache.zeppelin.user.AuthenticationInfo;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class InterpreterTest {

@Test
Expand Down Expand Up @@ -51,4 +52,38 @@ public void testOverriddenProperty() {
assertEquals("v2", intp.getProperty("p1"));
}

@Test
public void testPropertyWithReplacedContextFields() {
String noteId = "testNoteId";
String paragraphTitle = "testParagraphTitle";
String paragraphText = "testParagraphText";
String paragraphId = "testParagraphId";
String user = "username";
InterpreterContext.set(new InterpreterContext(noteId,
paragraphId,
null,
paragraphTitle,
paragraphText,
new AuthenticationInfo("testUser", "testTicket"),
null,
null,
null,
null,
null,
null));
Properties p = new Properties();
p.put("p1", "replName #{noteId}, #{paragraphTitle}, #{paragraphId}, #{paragraphText}, #{replName}, #{noteId}, #{user}," +
" #{authenticationInfo}");
MockInterpreterA intp = new MockInterpreterA(p);
intp.setUserName(user);
String actual = intp.getProperty("p1");
InterpreterContext.remove();

assertEquals(
String.format("replName %s, #{paragraphTitle}, #{paragraphId}, #{paragraphText}, , %s, %s, #{authenticationInfo}", noteId,
noteId, user),
actual
);
}

}