[ZEPPELIN-2106] providing paragraph config in create

note/paragraph call
* Allow to describe graph, colWidth, showTitle or full paragraph config
directly in the Create Paragraph and Create Note endpoint.
* Updated doc.
This commit is contained in:
Remilito 2017-03-03 18:23:56 +01:00
parent fb4c778b9e
commit 76af44ab6c
4 changed files with 194 additions and 30 deletions

View file

@ -111,7 +111,28 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete,
},
{
"title": "paragraph title2",
"text": "paragraph text2"
"text": "paragraph text2",
"showTitle": true,
"colWidth": 9.0,
"graph": {
"mode": "pieChart"
}
}
{
"title": "paragraph title3",
"text": "paragraph text3",
"config": {
"title": true,
"colWidth": 6.0,
"results": [
{
"graph": {
"mode": "scatterChart",
"optionOpen": true
}
}
]
}
}
]
}</pre></td>
@ -598,6 +619,39 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete,
"title": "Paragraph insert revised",
"text": "%spark\nprintln(\"Paragraph insert revised\")",
"index": 0
}</pre></td>
</tr>
<tr>
<td> sample JSON input (providing graph,showTitle and colWidth information) </td>
<td><pre>
{
"title": "paragraph title2",
"text": "paragraph text2",
"showTitle": true,
"colWidth": 9.0,
"graph": {
"mode": "pieChart"
}
}</pre></td>
</tr>
<tr>
<td> sample JSON input (providing paragraph config) </td>
<td><pre>
{
"title": "paragraph title3",
"text": "paragraph text3",
"config": {
"title": true,
"colWidth": 6.0,
"results": [
{
"graph": {
"mode": "scatterChart",
"optionOpen": true
}
}
]
}
}</pre></td>
</tr>
<tr>

View file

@ -18,11 +18,7 @@
package org.apache.zeppelin.rest;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
@ -337,16 +333,16 @@ public class NotebookRestApi {
@Path("/")
@ZeppelinApi
public Response createNote(String message) throws IOException {
String user = SecurityUtils.getPrincipal();
LOG.info("Create new note by JSON {}", message);
NewNoteRequest request = gson.fromJson(message, NewNoteRequest.class);
AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal());
AuthenticationInfo subject = new AuthenticationInfo(user);
Note note = notebook.createNote(subject);
List<NewParagraphRequest> initialParagraphs = request.getParagraphs();
if (initialParagraphs != null) {
for (NewParagraphRequest paragraphRequest : initialParagraphs) {
Paragraph p = note.addParagraph(subject);
p.setTitle(paragraphRequest.getTitle());
p.setText(paragraphRequest.getText());
initParagraph(p, paragraphRequest, user);
}
}
note.addParagraph(subject); // add one paragraph to the last
@ -425,6 +421,7 @@ public class NotebookRestApi {
@ZeppelinApi
public Response insertParagraph(@PathParam("noteId") String noteId, String message)
throws IOException {
String user = SecurityUtils.getPrincipal();
LOG.info("insert paragraph {} {}", noteId, message);
Note note = notebook.getNote(noteId);
@ -432,7 +429,7 @@ public class NotebookRestApi {
checkIfUserCanWrite(noteId, "Insufficient privileges you cannot add paragraph to this note");
NewParagraphRequest request = gson.fromJson(message, NewParagraphRequest.class);
AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal());
AuthenticationInfo subject = new AuthenticationInfo(user);
Paragraph p;
Double indexDouble = request.getIndex();
if (indexDouble == null) {
@ -440,9 +437,7 @@ public class NotebookRestApi {
} else {
p = note.insertParagraph(indexDouble.intValue(), subject);
}
p.setTitle(request.getTitle());
p.setText(request.getText());
initParagraph(p, request, user);
note.persist(subject);
notebookServer.broadcastNote(note);
return new JsonResponse<>(Status.OK, "", p.getId()).build();
@ -486,17 +481,7 @@ public class NotebookRestApi {
checkIfParagraphIsNotNull(p);
Map<String, Object> newConfig = gson.fromJson(message, HashMap.class);
if (newConfig == null || newConfig.isEmpty()) {
LOG.warn("{} is trying to update paragraph {} of note {} with empty config",
user, paragraphId, noteId);
throw new BadRequestException("paragraph config cannot be empty");
}
Map<String, Object> origConfig = p.getConfig();
for (String key : newConfig.keySet()) {
origConfig.put(key, newConfig.get(key));
}
p.setConfig(origConfig);
configureParagraph(p, newConfig, user);
AuthenticationInfo subject = new AuthenticationInfo(user);
note.persist(subject);
@ -963,4 +948,62 @@ public class NotebookRestApi {
}
}
private void initParagraph(Paragraph p, NewParagraphRequest request, String user)
throws IOException {
LOG.info("Init Paragraph for user {}", user);
checkIfParagraphIsNotNull(p);
p.setTitle(request.getTitle());
p.setText(request.getText());
Map< String, Object > config = request.getConfig();
if ( config != null){
Vector< String > ignoredFields = new Vector<>();
if ( request.getGraph() != null)
ignoredFields.add("graph");
if ( request.getColWidth() != null)
ignoredFields.add("colWidth");
if ( request.getShowTitle() != null)
ignoredFields.add("showTitle");
if ( ignoredFields.size() > 0 )
LOG.warn("As config is provided, the following field(s) are ignored {}",
ignoredFields.toString());
}
else {
config = new HashMap<>();
Map graph = request.getGraph();
if (graph != null) {
List<Object> results = new ArrayList<>();
Map<String, Object> result = new HashMap<>();
result.put("graph", graph);
results.add(result);
config.put("results", results);
}
Double colWidth = request.getColWidth();
if (colWidth != null) {
config.put("colWidth", colWidth);
}
Boolean showTitle = request.getShowTitle();
if (showTitle != null) {
config.put("title", showTitle);
}
}
if ( !config.isEmpty()) {
configureParagraph(p, config, user);
}
}
private void configureParagraph(Paragraph p, Map< String, Object> newConfig, String user)
throws IOException {
LOG.info("Configure Paragraph for user {}", user);
if (newConfig == null || newConfig.isEmpty()) {
LOG.warn("{} is trying to update paragraph {} of note {} with empty config",
user, p.getId(), p.getNote().getId());
throw new BadRequestException("paragraph config cannot be empty");
}
Map<String, Object> origConfig = p.getConfig();
for (String key : newConfig.keySet()) {
origConfig.put(key, newConfig.get(key));
}
p.setConfig(origConfig);
}
}

View file

@ -17,15 +17,24 @@
package org.apache.zeppelin.rest.message;
import java.util.HashMap;
/**
* NewParagraphRequest rest api request message
*
* index field will be ignored when it's used to provide initial paragraphs
* visualization (optional) one of:
* table,pieChart,multibarChart,stackedAreaChart,lineChart,scatterChart
* colWidth (optional), e.g. 12.0
*/
public class NewParagraphRequest {
String title;
String text;
Double index;
HashMap< String, Object > graph;
Boolean showTitle;
Double colWidth;
HashMap< String, Object > config;
public NewParagraphRequest() {
@ -42,4 +51,12 @@ public class NewParagraphRequest {
public Double getIndex() {
return index;
}
public HashMap< String, Object > getGraph() { return graph; }
public Boolean getShowTitle() { return showTitle; }
public Double getColWidth() { return colWidth; }
public HashMap< String, Object > getConfig() { return config; }
}

View file

@ -133,8 +133,14 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
String noteName = "test";
String jsonRequest = "{\"name\":\"" + noteName + "\", \"paragraphs\": [" +
"{\"title\": \"title1\", \"text\": \"text1\"}," +
"{\"title\": \"title2\", \"text\": \"text2\"}" +
"]}";
"{\"title\": \"title2\", \"text\": \"text2\"}," +
"{\"title\": \"titleConfig1\", \"text\": \"text3\", " +
"\"graph\": {\"mode\": \"pieChart\"}, " +
"\"colWidth\": 9.0, \"showTitle\": true}, " +
"{\"title\": \"titleConfig2\", \"text\": \"text4\", " +
"\"config\": {\"colWidth\": 9.0, \"title\": true, "+
"\"results\": [{\"graph\": {\"mode\": \"pieChart\"}}] "+
"}}]} ";
PostMethod post = httpPost("/notebook/", jsonRequest);
LOG.info("testNoteCreate \n" + post.getResponseBodyAsString());
assertThat("test note create method:", post, isAllowed());
@ -154,13 +160,20 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
expectedNoteName = "Note " + newNoteId;
}
assertEquals("compare note name", expectedNoteName, newNoteName);
assertEquals("initial paragraph check failed", 3, newNote.getParagraphs().size());
assertEquals("initial paragraph check failed", 5, newNote.getParagraphs().size());
for (Paragraph p : newNote.getParagraphs()) {
if (StringUtils.isEmpty(p.getText())) {
continue;
}
assertTrue("paragraph title check failed", p.getTitle().startsWith("title"));
assertTrue("paragraph text check failed", p.getText().startsWith("text"));
if ( p.getTitle() == "titleConfig"){
assertEquals("paragraph col width check failed", 9.0, p.getConfig().get("colWidth"));
assertTrue("paragraph show title check failed", ((boolean) p.getConfig().get("title")));
Map graph = ((List<Map>)p.getConfig().get("results")).get(0);
String mode = graph.get("mode").toString();
assertEquals("paragraph graph mode check failed", "pieChart", mode);
}
}
// cleanup
ZeppelinServer.notebook.removeNote(newNoteId, anonymous);
@ -213,8 +226,8 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
@Test
public void testexportNote() throws IOException {
LOG.info("testexportNote");
public void testExportNote() throws IOException {
LOG.info("testExportNote");
Note note = ZeppelinServer.notebook.createNote(anonymous);
assertNotNull("can't create new note", note);
note.setName("source note for export");
@ -246,7 +259,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
public void testImportNotebook() throws IOException {
Map<String, Object> resp;
String noteName = "source note for import";
LOG.info("testImortNote");
LOG.info("testImportNote");
// create test note
Note note = ZeppelinServer.notebook.createNote(anonymous);
assertNotNull("can't create new note", note);
@ -620,6 +633,43 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
assertEquals("title2", paragraphAtIdx0.getTitle());
assertEquals("text2", paragraphAtIdx0.getText());
//append paragraph providing config
String jsonRequest3 = "{\"title\": \"title3\", \"text\": \"text3\", " +
"\"graph\": {\"mode\": \"pieChart\"}, " +
"\"colWidth\": 9.0, \"showTitle\": true}";
PostMethod post3 = httpPost("/notebook/" + note.getId() + "/paragraph", jsonRequest3);
LOG.info("testInsertParagraph response3\n" + post3.getResponseBodyAsString());
assertThat("Test insert method:", post3, isAllowed());
post3.releaseConnection();
Paragraph p = note.getLastParagraph();
assertEquals("title3", p.getTitle());
assertEquals("text3", p.getText());
Map result = ((List<Map>)p.getConfig().get("results")).get(0);
String mode = ((Map)result.get("graph")).get("mode").toString();
assertEquals("pieChart", mode);
assertEquals(9.0, p.getConfig().get("colWidth"));
assertTrue(((boolean) p.getConfig().get("title")));
//append paragraph providing graph
String jsonRequest4 = "{\"title\": \"title4\", \"text\": \"text4\", "+
"\"config\": {\"colWidth\": 9.0, \"title\": true, "+
"\"results\": [{\"graph\": {\"mode\": \"pieChart\"}}]}}";
PostMethod post4 = httpPost("/notebook/" + note.getId() + "/paragraph", jsonRequest4);
LOG.info("testInsertParagraph response4\n" + post4.getResponseBodyAsString());
assertThat("Test insert method:", post4, isAllowed());
post4.releaseConnection();
Paragraph p2 = note.getLastParagraph();
assertEquals("title4", p2.getTitle());
assertEquals("text4", p2.getText());
Map result2 = ((List<Map>)p.getConfig().get("results")).get(0);
String mode2 = ((Map)result.get("graph")).get("mode").toString();
assertEquals("pieChart", mode2);
assertEquals(9.0, p2.getConfig().get("colWidth"));
assertTrue(((boolean) p2.getConfig().get("title")));
ZeppelinServer.notebook.removeNote(note.getId(), anonymous);
}