blob: bec349e0bc897c09cb25bafef538ad9443eacc26 [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.client;
import kong.unirest.GetRequest;
import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import kong.unirest.apache.ApacheClient;
import kong.unirest.json.JSONArray;
import kong.unirest.json.JSONObject;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.zeppelin.common.SessionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import unirest.shaded.org.apache.http.client.HttpClient;
import unirest.shaded.org.apache.http.impl.client.HttpClients;
import javax.net.ssl.SSLContext;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Low level api for interacting with Zeppelin. Underneath, it use the zeppelin rest api.
* You can use this class to operate Zeppelin note/paragraph,
* e.g. get/add/delete/update/execute/cancel
*/
public class ZeppelinClient {
private static final Logger LOGGER = LoggerFactory.getLogger(ZeppelinClient.class);
private ClientConfig clientConfig;
public ZeppelinClient(ClientConfig clientConfig) throws Exception {
this.clientConfig = clientConfig;
Unirest.config().defaultBaseUrl(clientConfig.getZeppelinRestUrl() + "/api");
if (clientConfig.isUseKnox()) {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) {
return true;
}
}).build();
HttpClient customHttpClient = HttpClients.custom().setSSLContext(sslContext)
.setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
Unirest.config().httpClient(ApacheClient.builder(customHttpClient));
} catch (Exception e) {
throw new Exception("Fail to setup httpclient of Unirest", e);
}
}
}
public ClientConfig getClientConfig() {
return clientConfig;
}
/**
* Throw exception if the status code is not 200.
*
* @param response
* @throws Exception
*/
private void checkResponse(HttpResponse<JsonNode> response) throws Exception {
if (response.getStatus() == 302) {
throw new Exception("Please login first");
}
if (response.getStatus() != 200) {
String message = response.getStatusText();
if (response.getBody() != null &&
response.getBody().getObject() != null &&
response.getBody().getObject().has("message")) {
message = response.getBody().getObject().getString("message");
}
throw new Exception(String.format("Unable to call rest api, status: %s, statusText: %s, message: %s",
response.getStatus(),
response.getStatusText(),
message));
}
}
/**
* Throw exception if the status in the json object is not `OK`.
*
* @param jsonNode
* @throws Exception
*/
private void checkJsonNodeStatus(JsonNode jsonNode) throws Exception {
if (! "OK".equalsIgnoreCase(jsonNode.getObject().getString("status"))) {
throw new Exception(StringEscapeUtils.unescapeJava(jsonNode.getObject().getString("message")));
}
}
/**
* Get Zeppelin version.
*
* @return
* @throws Exception
*/
public String getVersion() throws Exception {
HttpResponse<JsonNode> response = Unirest
.get("/version")
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return jsonNode.getObject().getJSONObject("body").getString("version");
}
/**
* Request a new session id. It doesn't create session (interpreter process) in zeppelin server side, but just
* create an unique session id.
*
* @param interpreter
* @return
* @throws Exception
*/
public SessionInfo newSession(String interpreter) throws Exception {
HttpResponse<JsonNode> response = Unirest
.post("/session")
.queryString("interpreter", interpreter)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return createSessionInfoFromJson(jsonNode.getObject().getJSONObject("body"));
}
/**
* Stop the session(interpreter process) in Zeppelin server.
*
* @param sessionId
* @throws Exception
*/
public void stopSession(String sessionId) throws Exception {
HttpResponse<JsonNode> response = Unirest
.delete("/session/{sessionId}")
.routeParam("sessionId", sessionId)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
}
/**
* Get session info for the provided sessionId.
* Return null if provided sessionId doesn't exist.
*
* @param sessionId
* @throws Exception
*/
public SessionInfo getSession(String sessionId) throws Exception {
HttpResponse<JsonNode> response = Unirest
.get("/session/{sessionId}")
.routeParam("sessionId", sessionId)
.asJson();
if (response.getStatus() == 404) {
String statusText = response.getStatusText();
if (response.getBody().getObject().has("message")) {
statusText = response.getBody().getObject().getString("message");
}
if (statusText.contains("No such session")) {
return null;
}
}
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
JSONObject bodyObject = jsonNode.getObject().getJSONObject("body");
return createSessionInfoFromJson(bodyObject);
}
/**
* List all the sessions.
*
* @return
* @throws Exception
*/
public List<SessionInfo> listSessions() throws Exception {
return listSessions(null);
}
/**
* List all the sessions for the provided interpreter.
*
* @param interpreter
* @return
* @throws Exception
*/
public List<SessionInfo> listSessions(String interpreter) throws Exception {
GetRequest getRequest = Unirest.get("/session");
if (interpreter != null) {
getRequest.queryString("interpreter", interpreter);
}
HttpResponse<JsonNode> response = getRequest.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
JSONArray sessionJsonArray = jsonNode.getObject().getJSONArray("body");
List<SessionInfo> sessionInfos = new ArrayList<>();
for (int i = 0; i< sessionJsonArray.length();++i) {
sessionInfos.add(createSessionInfoFromJson(sessionJsonArray.getJSONObject(i)));
}
return sessionInfos;
}
private SessionInfo createSessionInfoFromJson(JSONObject sessionJson) {
SessionInfo sessionInfo = new SessionInfo();
if (sessionJson.has("sessionId")) {
sessionInfo.setSessionId(sessionJson.getString("sessionId"));
}
if (sessionJson.has("noteId")) {
sessionInfo.setNoteId(sessionJson.getString("noteId"));
}
if (sessionJson.has("interpreter")) {
sessionInfo.setInterpreter(sessionJson.getString("interpreter"));
}
if (sessionJson.has("state")) {
sessionInfo.setState(sessionJson.getString("state"));
}
if (sessionJson.has("weburl")) {
sessionInfo.setWeburl(sessionJson.getString("weburl"));
}
if (sessionJson.has("startTime")) {
sessionInfo.setStartTime(sessionJson.getString("startTime"));
}
return sessionInfo;
}
/**
* Login zeppelin with userName and password, throw exception if login fails.
*
* @param userName
* @param password
* @throws Exception
*/
public void login(String userName, String password) throws Exception {
if (clientConfig.isUseKnox()) {
HttpResponse<String> response = Unirest.get(clientConfig.getKnoxSSOUrl() +
"?originalUrl=" + clientConfig.getZeppelinRestUrl())
.basicAuth(userName, password)
.asString();
if (response.getStatus() != 200) {
throw new Exception(String.format("Knox SSO login failed, status: %s, statusText: %s",
response.getStatus(),
response.getStatusText()));
}
response = Unirest.get("/security/ticket")
.asString();
if (response.getStatus() != 200) {
throw new Exception(String.format("Fail to get ticket after Knox SSO, status: %s, statusText: %s",
response.getStatus(),
response.getStatusText()));
}
} else {
HttpResponse<JsonNode> response = Unirest
.post("/login")
.field("userName", userName)
.field("password", password)
.asJson();
if (response.getStatus() != 200) {
throw new Exception(String.format("Login failed, status: %s, statusText: %s",
response.getStatus(),
response.getStatusText()));
}
}
}
public String createNote(String notePath) throws Exception {
return createNote(notePath, "");
}
/**
* Create a new empty note with provided notePath and defaultInterpreterGroup
*
* @param notePath
* @param defaultInterpreterGroup
* @return
* @throws Exception
*/
public String createNote(String notePath, String defaultInterpreterGroup) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("name", notePath);
bodyObject.put("defaultInterpreterGroup", defaultInterpreterGroup);
HttpResponse<JsonNode> response = Unirest
.post("/notebook")
.body(bodyObject.toString())
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return jsonNode.getObject().getString("body");
}
/**
* Delete note with provided noteId.
*
* @param noteId
* @throws Exception
*/
public void deleteNote(String noteId) throws Exception {
HttpResponse<JsonNode> response = Unirest
.delete("/notebook/{noteId}")
.routeParam("noteId", noteId)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
}
/**
* Clone a note to a specified notePath.
*
* @param noteId
* @param destPath
* @return
* @throws Exception
*/
public String cloneNote(String noteId, String destPath) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("name", destPath);
HttpResponse<JsonNode> response = Unirest
.post("/notebook/{noteId}")
.routeParam("noteId", noteId)
.body(bodyObject.toString())
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return jsonNode.getObject().getString("body");
}
public void renameNote(String noteId, String newNotePath) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("name", newNotePath);
HttpResponse<JsonNode> response = Unirest
.put("/notebook/{noteId}/rename")
.routeParam("noteId", noteId)
.body(bodyObject.toString())
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
}
/**
* Query {@link NoteResult} with provided noteId.
*
* @param noteId
* @return
* @throws Exception
*/
public NoteResult queryNoteResult(String noteId) throws Exception {
HttpResponse<JsonNode> response = Unirest
.get("/notebook/{noteId}")
.routeParam("noteId", noteId)
.asJson();
return extractNoteResultFromResponse(response);
}
/**
* Query {@link NoteResult} with provided notePath.
*
* @param notePath
* @return
* @throws Exception
*/
public NoteResult queryNoteResultByPath(String notePath) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("notePath", notePath);
HttpResponse<JsonNode> response = Unirest
.post("/notebook/getByPath")
.body(bodyObject)
.asJson();
return extractNoteResultFromResponse(response);
}
private NoteResult extractNoteResultFromResponse(HttpResponse<JsonNode> response) throws Exception {
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
JSONObject noteJsonObject = jsonNode.getObject().getJSONObject("body");
boolean isRunning = false;
if (noteJsonObject.has("info")) {
JSONObject infoJsonObject = noteJsonObject.getJSONObject("info");
if (infoJsonObject.has("isRunning")) {
isRunning = Boolean.parseBoolean(infoJsonObject.getString("isRunning"));
}
}
String noteId = null;
if (noteJsonObject.has("id")) {
noteId = noteJsonObject.getString("id");
}
String notePath = null;
if (noteJsonObject.has("path")) {
notePath = noteJsonObject.getString("path");
}
List<ParagraphResult> paragraphResultList = new ArrayList<>();
if (noteJsonObject.has("paragraphs")) {
JSONArray paragraphJsonArray = noteJsonObject.getJSONArray("paragraphs");
for (int i = 0; i< paragraphJsonArray.length(); ++i) {
paragraphResultList.add(new ParagraphResult(paragraphJsonArray.getJSONObject(i)));
}
}
return new NoteResult(noteId, notePath, isRunning, paragraphResultList);
}
/**
* Execute note with provided noteId, return until note execution is completed.
* Interpreter process will be stopped after note execution.
*
* @param noteId
* @return
* @throws Exception
*/
public NoteResult executeNote(String noteId) throws Exception {
return executeNote(noteId, new HashMap<>());
}
/**
* Execute note with provided noteId and parameters, return until note execution is completed.
* Interpreter process will be stopped after note execution.
*
* @param noteId
* @param parameters
* @return
* @throws Exception
*/
public NoteResult executeNote(String noteId, Map<String, String> parameters) throws Exception {
submitNote(noteId, parameters);
return waitUntilNoteFinished(noteId);
}
/**
* Submit note to execute with provided noteId, return at once the submission is completed.
* You need to query {@link NoteResult} by yourself afterwards until note execution is completed.
* Interpreter process will be stopped after note execution.
*
* @param noteId
* @return
* @throws Exception
*/
public NoteResult submitNote(String noteId) throws Exception {
return submitNote(noteId, new HashMap<>());
}
/**
* Submit note to execute with provided noteId and parameters, return at once the submission is completed.
* You need to query {@link NoteResult} by yourself afterwards until note execution is completed.
* Interpreter process will be stopped after note execution.
*
* @param noteId
* @param parameters
* @return
* @throws Exception
*/
public NoteResult submitNote(String noteId, Map<String, String> parameters) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("params", parameters);
// run note in non-blocking and isolated way.
HttpResponse<JsonNode> response = Unirest
.post("/notebook/job/{noteId}")
.routeParam("noteId", noteId)
.queryString("blocking", "false")
.queryString("isolated", "true")
.body(bodyObject)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return queryNoteResult(noteId);
}
/**
* Cancel a running note.
*
* @param noteId
* @throws Exception
*/
public void cancelNote(String noteId) throws Exception {
HttpResponse<JsonNode> response = Unirest
.delete("/notebook/job/{noteId}")
.routeParam("noteId", noteId)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
}
/**
* Import note with given note json content to the specified notePath.
*
* @param notePath
* @param noteContent
* @return
* @throws Exception
*/
public String importNote(String notePath, String noteContent) throws Exception {
JSONObject bodyObject = new JSONObject(noteContent);
HttpResponse<JsonNode> response = Unirest
.post("/notebook/import")
.queryString("notePath", notePath)
.body(bodyObject)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return jsonNode.getObject().getString("body");
}
/**
* Block there until note execution is completed.
*
* @param noteId
* @return
* @throws Exception
*/
public NoteResult waitUntilNoteFinished(String noteId) throws Exception {
while (true) {
NoteResult noteResult = queryNoteResult(noteId);
if (!noteResult.isRunning()) {
return noteResult;
}
Thread.sleep(clientConfig.getQueryInterval());
}
}
/**
* Block there until note execution is completed, and throw exception if note execution is not completed
* in <code>timeoutInMills</code>.
*
* @param noteId
* @param timeoutInMills
* @return
* @throws Exception
*/
public NoteResult waitUntilNoteFinished(String noteId, long timeoutInMills) throws Exception {
long start = System.currentTimeMillis();
while (true && (System.currentTimeMillis() - start) < timeoutInMills) {
NoteResult noteResult = queryNoteResult(noteId);
if (!noteResult.isRunning()) {
return noteResult;
}
Thread.sleep(clientConfig.getQueryInterval());
}
throw new Exception("Note is not finished in " + timeoutInMills / 1000 + " seconds");
}
/**
* Add paragraph to note with provided title and text.
*
* @param noteId
* @param title
* @param text
* @return
* @throws Exception
*/
public String addParagraph(String noteId, String title, String text) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("title", title);
bodyObject.put("text", text);
HttpResponse<JsonNode> response = Unirest.post("/notebook/{noteId}/paragraph")
.routeParam("noteId", noteId)
.body(bodyObject.toString())
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return jsonNode.getObject().getString("body");
}
/**
* Update paragraph with specified title and text.
*
* @param noteId
* @param paragraphId
* @param title
* @param text
* @throws Exception
*/
public void updateParagraph(String noteId, String paragraphId, String title, String text) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("title", title);
bodyObject.put("text", text);
HttpResponse<JsonNode> response = Unirest.put("/notebook/{noteId}/paragraph/{paragraphId}")
.routeParam("noteId", noteId)
.routeParam("paragraphId", paragraphId)
.body(bodyObject.toString())
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
}
/**
* Execute paragraph with parameters in specified session. If sessionId is null or empty string, then it depends on
* the interpreter binding mode of Note(e.g. isolated per note), otherwise it will run in the specified session.
*
* @param noteId
* @param paragraphId
* @param sessionId
* @param parameters
* @return
* @throws Exception
*/
public ParagraphResult executeParagraph(String noteId,
String paragraphId,
String sessionId,
Map<String, String> parameters) throws Exception {
submitParagraph(noteId, paragraphId, sessionId, parameters);
return waitUtilParagraphFinish(noteId, paragraphId);
}
/**
* Execute paragraph with parameters.
*
* @param noteId
* @param paragraphId
* @param parameters
* @return
* @throws Exception
*/
public ParagraphResult executeParagraph(String noteId,
String paragraphId,
Map<String, String> parameters) throws Exception {
return executeParagraph(noteId, paragraphId, "", parameters);
}
/**
* Execute paragraph in specified session. If sessionId is null or empty string, then it depends on
* the interpreter binding mode of Note (e.g. isolated per note), otherwise it will run in the specified session.
*
* @param noteId
* @param paragraphId
* @param sessionId
* @return
* @throws Exception
*/
public ParagraphResult executeParagraph(String noteId,
String paragraphId,
String sessionId) throws Exception {
return executeParagraph(noteId, paragraphId, sessionId, new HashMap<>());
}
/**
* Execute paragraph.
*
* @param noteId
* @param paragraphId
* @return
* @throws Exception
*/
public ParagraphResult executeParagraph(String noteId, String paragraphId) throws Exception {
return executeParagraph(noteId, paragraphId, "", new HashMap<>());
}
/**
* Submit paragraph to execute with provided parameters and sessionId. Return at once the submission is completed.
* You need to query {@link ParagraphResult} by yourself afterwards until paragraph execution is completed.
*
* @param noteId
* @param paragraphId
* @param sessionId
* @param parameters
* @return
* @throws Exception
*/
public ParagraphResult submitParagraph(String noteId,
String paragraphId,
String sessionId,
Map<String, String> parameters) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("params", parameters);
HttpResponse<JsonNode> response = Unirest
.post("/notebook/job/{noteId}/{paragraphId}")
.routeParam("noteId", noteId)
.routeParam("paragraphId", paragraphId)
.queryString("sessionId", sessionId)
.body(bodyObject.toString())
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return queryParagraphResult(noteId, paragraphId);
}
/**
* Submit paragraph to execute with provided sessionId. Return at once the submission is completed.
* You need to query {@link ParagraphResult} by yourself afterwards until paragraph execution is completed.
*
* @param noteId
* @param paragraphId
* @param sessionId
* @return
* @throws Exception
*/
public ParagraphResult submitParagraph(String noteId,
String paragraphId,
String sessionId) throws Exception {
return submitParagraph(noteId, paragraphId, sessionId, new HashMap<>());
}
/**
* Submit paragraph to execute with provided parameters. Return at once the submission is completed.
* You need to query {@link ParagraphResult} by yourself afterwards until paragraph execution is completed.
*
* @param noteId
* @param paragraphId
* @param parameters
* @return
* @throws Exception
*/
public ParagraphResult submitParagraph(String noteId,
String paragraphId,
Map<String, String> parameters) throws Exception {
return submitParagraph(noteId, paragraphId, "", parameters);
}
/**
* Submit paragraph to execute. Return at once the submission is completed.
* You need to query {@link ParagraphResult} by yourself afterwards until paragraph execution is completed.
*
* @param noteId
* @param paragraphId
* @return
* @throws Exception
*/
public ParagraphResult submitParagraph(String noteId, String paragraphId) throws Exception {
return submitParagraph(noteId, paragraphId, "", new HashMap<>());
}
/**
* This used by {@link ZSession} for creating or reusing a paragraph for executing another piece of code.
*
* @param noteId
* @param maxParagraph
* @return
* @throws Exception
*/
public String nextSessionParagraph(String noteId, int maxParagraph) throws Exception {
HttpResponse<JsonNode> response = Unirest
.post("/notebook/{noteId}/paragraph/next")
.routeParam("noteId", noteId)
.queryString("maxParagraph", maxParagraph)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
return jsonNode.getObject().getString("message");
}
/**
* Cancel a running paragraph.
*
* @param noteId
* @param paragraphId
* @throws Exception
*/
public void cancelParagraph(String noteId, String paragraphId) throws Exception {
HttpResponse<JsonNode> response = Unirest
.delete("/notebook/job/{noteId}/{paragraphId}")
.routeParam("noteId", noteId)
.routeParam("paragraphId", paragraphId)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
}
/**
* Query {@link ParagraphResult}
*
* @param noteId
* @param paragraphId
* @return
* @throws Exception
*/
public ParagraphResult queryParagraphResult(String noteId, String paragraphId) throws Exception {
HttpResponse<JsonNode> response = Unirest
.get("/notebook/{noteId}/paragraph/{paragraphId}")
.routeParam("noteId", noteId)
.routeParam("paragraphId", paragraphId)
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
JSONObject paragraphJson = jsonNode.getObject().getJSONObject("body");
return new ParagraphResult(paragraphJson);
}
/**
* Query {@link ParagraphResult} until it is finished.
*
* @param noteId
* @param paragraphId
* @return
* @throws Exception
*/
public ParagraphResult waitUtilParagraphFinish(String noteId, String paragraphId) throws Exception {
while (true) {
ParagraphResult paragraphResult = queryParagraphResult(noteId, paragraphId);
LOGGER.debug(paragraphResult.toString());
if (paragraphResult.getStatus().isCompleted()) {
return paragraphResult;
}
Thread.sleep(clientConfig.getQueryInterval());
}
}
/**
* Query {@link ParagraphResult} until it is finished or timeout.
*
* @param noteId
* @param paragraphId
* @param timeoutInMills
* @return
* @throws Exception
*/
public ParagraphResult waitUtilParagraphFinish(String noteId, String paragraphId, long timeoutInMills) throws Exception {
long start = System.currentTimeMillis();
while (true && (System.currentTimeMillis() - start) < timeoutInMills) {
ParagraphResult paragraphResult = queryParagraphResult(noteId, paragraphId);
if (paragraphResult.getStatus().isCompleted()) {
return paragraphResult;
}
Thread.sleep(clientConfig.getQueryInterval());
}
throw new Exception("Paragraph is not finished in " + timeoutInMills / 1000 + " seconds");
}
/**
* Query {@link ParagraphResult} until it is running.
*
* @param noteId
* @param paragraphId
* @return
* @throws Exception
*/
public ParagraphResult waitUtilParagraphRunning(String noteId, String paragraphId) throws Exception {
while (true) {
ParagraphResult paragraphResult = queryParagraphResult(noteId, paragraphId);
if (paragraphResult.getStatus().isRunning()) {
return paragraphResult;
}
Thread.sleep(clientConfig.getQueryInterval());
}
}
/**
* This is equal to the restart operation in note page.
*
* @param noteId
* @param interpreter
*/
public void stopInterpreter(String noteId, String interpreter) throws Exception {
JSONObject bodyObject = new JSONObject();
bodyObject.put("noteId", noteId);
HttpResponse<JsonNode> response = Unirest
.put("/interpreter/setting/restart/{interpreter}")
.routeParam("interpreter", interpreter)
.body(bodyObject.toString())
.asJson();
checkResponse(response);
JsonNode jsonNode = response.getBody();
checkJsonNodeStatus(jsonNode);
}
}