summaryrefslogtreecommitdiff
path: root/qpid/java/broker-plugins/management-http
diff options
context:
space:
mode:
authorKeith Wall <kwall@apache.org>2014-12-19 19:13:50 +0000
committerKeith Wall <kwall@apache.org>2014-12-19 19:13:50 +0000
commitaa516ab4d908927a95b20275fc7daaa7bb9420a9 (patch)
tree13d7e8e04c45960ee680c69926d3bbf485b9f2bd /qpid/java/broker-plugins/management-http
parent40e74eaa3f8a345e7bc888e36de79717b7c761d0 (diff)
downloadqpid-python-aa516ab4d908927a95b20275fc7daaa7bb9420a9.tar.gz
QPID-6276: [Java Broker] Enhance the virtualhost UI to support upload/download of virtualhost config expressed as JSON.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1646829 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/broker-plugins/management-http')
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java44
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html28
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css16
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/index.html1
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js14
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js156
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html1
7 files changed, 213 insertions, 47 deletions
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
index 0bc0a4514f..52c9b10e59 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
@@ -62,13 +62,20 @@ public class RestServlet extends AbstractServlet
public static final String INHERITED_ACTUALS_PARAM = "inheritedActuals";
public static final String EXTRACT_INITIAL_CONFIG_PARAM = "extractInitialConfig";
+ /**
+ * Signifies that the agent wishes the servlet to set the Content-Disposition on the
+ * response with the value attachment. This filename will be derived from the parameter value.
+ */
+ public static final String CONTENT_DISPOSITION_ATTACHMENT_FILENAME_PARAM = "contentDispositionAttachmentFilename";
+
public static final Set<String> RESERVED_PARAMS =
new HashSet<>(Arrays.asList(DEPTH_PARAM,
SORT_PARAM,
ACTUALS_PARAM,
INCLUDE_SYS_CONTEXT_PARAM,
EXTRACT_INITIAL_CONFIG_PARAM,
- INHERITED_ACTUALS_PARAM));
+ INHERITED_ACTUALS_PARAM,
+ CONTENT_DISPOSITION_ATTACHMENT_FILENAME_PARAM));
private Class<? extends ConfiguredObject>[] _hierarchy;
@@ -316,19 +323,23 @@ public class RestServlet extends AbstractServlet
@Override
protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
+ // TODO - sort special params, everything else should act as a filter
+ String attachmentFilename = request.getParameter(CONTENT_DISPOSITION_ATTACHMENT_FILENAME_PARAM);
+ boolean extractInitialConfig = getBooleanParameterFromRequest(request, EXTRACT_INITIAL_CONFIG_PARAM);
+
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
setCachingHeadersOnResponse(response);
+ setContentDispositionHeaderIfNecessary(response, attachmentFilename);
Collection<ConfiguredObject<?>> allObjects = getObjects(request);
- // TODO - sort special params, everything else should act as a filter
- boolean extractInitialConfig = getBooleanParameterFromRequest(request, EXTRACT_INITIAL_CONFIG_PARAM);
int depth;
boolean actuals;
boolean includeSystemContext;
boolean inheritedActuals;
+
if(extractInitialConfig)
{
depth = Integer.MAX_VALUE;
@@ -344,20 +355,35 @@ public class RestServlet extends AbstractServlet
inheritedActuals = getBooleanParameterFromRequest(request, INHERITED_ACTUALS_PARAM);
}
- List<Map<String, Object>> output = new ArrayList<Map<String, Object>>();
+ List<Map<String, Object>> output = new ArrayList<>();
for(ConfiguredObject configuredObject : allObjects)
{
output.add(_objectConverter.convertObjectToMap(configuredObject, getConfiguredClass(),
depth, actuals, inheritedActuals, includeSystemContext, extractInitialConfig));
}
+
Writer writer = getOutputWriter(request, response);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
mapper.writeValue(writer, extractInitialConfig && output.size() == 1 ? output.get(0) : output);
+ }
- response.setContentType("application/json");
- response.setStatus(HttpServletResponse.SC_OK);
+ private void setContentDispositionHeaderIfNecessary(final HttpServletResponse response,
+ final String attachmentFilename)
+ {
+ if (attachmentFilename != null)
+ {
+ String filenameRfc2183 = ensureFilenameIsRfc2183(attachmentFilename);
+ if (filenameRfc2183.length() > 0)
+ {
+ response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", filenameRfc2183));
+ }
+ else
+ {
+ response.setHeader("Content-disposition", String.format("attachment")); // Agent will allow user to choose a name
+ }
+ }
}
private Class<? extends ConfiguredObject> getConfiguredClass()
@@ -671,4 +697,10 @@ public class RestServlet extends AbstractServlet
return Boolean.parseBoolean(request.getParameter(paramName));
}
+ private String ensureFilenameIsRfc2183(final String requestedFilename)
+ {
+ String fileNameRfc2183 = requestedFilename.replaceAll("[\\P{InBasic_Latin}\\\\:/]", "");
+ return fileNameRfc2183;
+ }
+
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html
index 3e3e931829..383c782d60 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html
@@ -59,6 +59,34 @@
<div id="addVirtualHostNode.typeFields"></div>
+ <div id="addVirtualHostNode.uploadFields" class="clear">
+ <div class="formLabel-labelCell">
+ <label for="addVirtualHostNode.upload">Upload virtualhost configuration from file:</label>
+ </div>
+ <div class="formLabel-controlCell">
+ <input id="addVirtualHostNode.upload" type="checkbox"
+ data-dojo-type="dijit.form.CheckBox"
+ data-dojo-props="
+ name: 'upload'" />
+ </div>
+ <div id="addVirtualHostNode.fileFields" class="clear">
+ <div class="formLabel-labelCell">
+ <label for="addVirtualHostNode.file">Select JSON file*:</label>
+ </div>
+ <div class="tableContainer-valueCell formLabel-controlCell">
+ <input type="file" id="addVirtualHostNode.file"
+ multiple="false"
+ data-dojo-type="dojox.form.Uploader"
+ data-dojo-props="
+ label: 'Select'"/>
+ <span id="addVirtualHostNode.selectedFile" class="infoMessage"></span>
+ <span id="addVirtualHostNode.selectedFileStatus"></span>
+ </div>
+ </div>
+ </div>
+
+ <div class="clear"></div>
+
<div data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Context variables', open: false">
<div id="addVirtualHostNode.context"></div>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css b/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css
index d04117b266..e6a0ce467f 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css
@@ -215,6 +215,22 @@ div .messages {
height: 16px;
}
+.loadingIcon
+{
+ background: url("../dojo/dojox/image/resources/images/loading.gif") no-repeat;
+ width: 25px;
+ height: 25px;
+ display: inline-block;
+}
+
+.loadedIcon
+{
+ background: url("../dojo/dojox/mobile/themes/common/domButtons/compat/mblDomButtonDarkBlueCheck.png") no-repeat;
+ width: 25px;
+ height: 25px;
+ display: inline-block;
+}
+
.infoMessage
{
padding: 5px;
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
index eb742bbfa0..379a25bbcd 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
@@ -25,6 +25,7 @@
<link rel="stylesheet" href="dojo/dojox/grid/enhanced/resources/claro/EnhancedGrid.css">
<link rel="stylesheet" href="dojo/dojox/grid/enhanced/resources/EnhancedGrid_rtl.css">
<link rel="stylesheet" href="dojo/dojox/form/resources/CheckedMultiSelect.css">
+ <link rel="stylesheet" href="dojo/dojox/form/resources/FileInput.css" />
<link rel="stylesheet" href="css/common.css" media="screen">
<script>
function getContextPath()
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
index cdc7890209..434e119736 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
@@ -93,6 +93,19 @@ define(["dojo/_base/xhr",
that.stopButton = registry.byNode(query(".stopButton", containerNode)[0]);
that.startButton = registry.byNode(query(".startButton", containerNode)[0]);
that.editButton = registry.byNode(query(".editButton", containerNode)[0]);
+ that.downloadButton = registry.byNode(query(".downloadButton", containerNode)[0]);
+ that.downloadButton.on("click",
+ function(e)
+ {
+ var iframe = document.createElement('iframe');
+ iframe.id = "downloader_" + that.name;
+ document.body.appendChild(iframe);
+ var suggestedAttachmentName = encodeURIComponent(that.name + ".json");
+ iframe.src = "/api/latest/virtualhost/" + encodeURIComponent(that.modelObj.parent.name) + "/" + encodeURIComponent(that.name) + "?extractInitialConfig=true&contentDispositionAttachmentFilename=" + suggestedAttachmentName;
+ // It seems there is no way to remove this iframe in a manner that is cross browser compatible.
+ }
+ );
+
that.deleteButton = registry.byNode(query(".deleteButton", containerNode)[0]);
that.deleteButton.on("click",
function(e)
@@ -344,6 +357,7 @@ define(["dojo/_base/xhr",
this.virtualHost.startButton.set("disabled", !this.vhostData.state || this.vhostData.state != "STOPPED");
this.virtualHost.stopButton.set("disabled", !this.vhostData.state || this.vhostData.state != "ACTIVE");
this.virtualHost.editButton.set("disabled", !this.vhostData.state || this.vhostData.state == "UNAVAILABLE");
+ this.virtualHost.downloadButton.set("disabled", !this.vhostData.state || this.vhostData.state != "ACTIVE");
this.virtualHost.deleteButton.set("disabled", !this.vhostData.state);
util.flattenStatistics( thisObj.vhostData );
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js
index 0a18a8909b..aa515fbe19 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js
@@ -44,6 +44,7 @@ define(["dojo/_base/xhr",
"dijit/form/Form",
"dijit/form/CheckBox",
"dijit/form/RadioButton",
+ "dojox/form/Uploader",
"dojox/validate/us",
"dojox/validate/web",
"dojo/domReady!"],
@@ -61,6 +62,9 @@ define(["dojo/_base/xhr",
var virtualHostNodeName = registry.byId("addVirtualHostNode.nodeName");
virtualHostNodeName.set("regExpGen", util.nameOrContextVarRegexp);
+ // Readers are HTML5
+ this.reader = window.FileReader ? new FileReader() : undefined;
+
this.dialog = registry.byId("addVirtualHostNodeAndVirtualHost");
this.addButton = registry.byId("addVirtualHostNodeAndVirtualHost.addButton");
this.cancelButton = registry.byId("addVirtualHostNodeAndVirtualHost.cancelButton");
@@ -68,13 +72,22 @@ define(["dojo/_base/xhr",
this.addButton.on("click", function(e){that._add(e);});
this.virtualHostNodeTypeFieldsContainer = dom.byId("addVirtualHostNode.typeFields");
+ this.virtualHostNodeSelectedFileContainer = dom.byId("addVirtualHostNode.selectedFile");
+ this.virtualHostNodeSelectedFileStatusContainer = dom.byId("addVirtualHostNode.selectedFileStatus");
+ this.virtualHostNodeUploadFields = dom.byId("addVirtualHostNode.uploadFields");
+ this.virtualHostNodeFileFields = dom.byId("addVirtualHostNode.fileFields");
+
this.virtualHostNodeForm = registry.byId("addVirtualHostNode.form");
this.virtualHostNodeType = registry.byId("addVirtualHostNode.type");
+ this.virtualHostNodeFileCheck = registry.byId("addVirtualHostNode.upload");
+ this.virtualHostNodeFile = registry.byId("addVirtualHostNode.file");
+
this.virtualHostNodeType.set("disabled", true);
this.virtualHostTypeFieldsContainer = dom.byId("addVirtualHost.typeFields");
this.virtualHostForm = registry.byId("addVirtualHost.form");
this.virtualHostType = registry.byId("addVirtualHost.type");
+
this.virtualHostType.set("disabled", true);
this.supportedVirtualHostNodeTypes = metadata.getTypesForCategory("VirtualHostNode");
@@ -96,6 +109,21 @@ define(["dojo/_base/xhr",
this.virtualHostType.set("store", this.virtualHostTypeStore);
this.virtualHostType.set("disabled", false);
this.virtualHostType.on("change", function(type){that._vhTypeChanged(type, that.virtualHostTypeFieldsContainer, "qpid/management/virtualhost/");});
+
+ if (this.reader)
+ {
+ this.reader.onload = function(e) {that._vhnUploadFileComplete(e);};
+ this.virtualHostNodeFile.on("change", function(selected){that._vhnFileChanged(selected)});
+ this.virtualHostNodeFileCheck.on("change", function(selected){that._vhnFileFlagChanged(selected)});
+ }
+ else
+ {
+ // Fall back for IE8/9 which do not support FileReader
+ this.virtualHostNodeFile.set("disabled", true);
+ this.virtualHostNodeFileCheck.set("disabled", true);
+ }
+
+ this.virtualHostNodeUploadFields.style.display = "none";
},
show: function()
{
@@ -164,6 +192,14 @@ define(["dojo/_base/xhr",
this._processDropDownsForBdbHa(type);
this._processDropDownsForJson(type);
+ var vhnTypeSelected = !(type == '');
+ this.virtualHostNodeUploadFields.style.display = vhnTypeSelected ? "block" : "none";
+
+ if (!vhnTypeSelected)
+ {
+ this._vhnFileFlagChanged(false);
+ }
+
this._typeChanged(type, typeFieldsContainer, urlStem, "VirtualHostNode");
},
_vhTypeChanged: function (type, typeFieldsContainer, urlStem)
@@ -203,6 +239,37 @@ define(["dojo/_base/xhr",
);
}
},
+ _vhnFileFlagChanged: function (selected)
+ {
+ this.virtualHostForm.domNode.style.display = selected ? "none" : "block";
+ this.virtualHostNodeFileFields.style.display = selected ? "block" : "none";
+ this.virtualHostType.set("required", !selected);
+ this.virtualHostNodeFile.reset();
+ this.virtualHostInitialConfiguration = undefined;
+ this.virtualHostNodeSelectedFileContainer.innerHTML = "";
+ this.virtualHostNodeSelectedFileStatusContainer.className = "";
+ },
+ _vhnFileChanged: function (evt)
+ {
+ // We only ever expect a single file
+ var file = this.virtualHostNodeFile.domNode.children[0].files[0];
+
+ this.addButton.set("disabled", true);
+ this.virtualHostNodeSelectedFileContainer.innerHTML = file.name;
+ this.virtualHostNodeSelectedFileStatusContainer.className = "loadingIcon";
+
+ console.log("Beginning to read file " + file.name);
+ this.reader.readAsDataURL(file);
+ },
+ _vhnUploadFileComplete: function(evt)
+ {
+ var reader = evt.target;
+ var result = reader.result;
+ console.log("File read complete, contents " + result);
+ this.virtualHostInitialConfiguration = result;
+ this.addButton.set("disabled", false);
+ this.virtualHostNodeSelectedFileStatusContainer.className = "loadedIcon";
+ },
_processDropDownsForBdbHa: function (type)
{
if (type == "BDB_HA")
@@ -249,6 +316,10 @@ define(["dojo/_base/xhr",
},
_cancel: function(e)
{
+ if (this.reader)
+ {
+ this.reader.abort();
+ }
this.dialog.hide();
},
_add: function(e)
@@ -258,16 +329,32 @@ define(["dojo/_base/xhr",
},
_submit: function()
{
- if(this.virtualHostNodeForm.validate() && this.virtualHostForm.validate())
+
+ var uploadVHConfig = this.virtualHostNodeFileCheck.get("checked");
+ var virtualHostNodeData = undefined;
+
+ if (uploadVHConfig && this.virtualHostNodeFile.getFileList().length > 0 && this.virtualHostNodeForm.validate())
{
- var success = false,failureReason=null;
+ // VH config is being uploaded
+ virtualHostNodeData = this._getValues(this.virtualHostNodeForm);
+ var virtualHostNodeContext = this.virtualHostNodeContext.get("value");
+ if (virtualHostNodeContext)
+ {
+ virtualHostNodeData["context"] = virtualHostNodeContext;
+ }
- var virtualHostNodeData = this._getValues(this.virtualHostNodeForm);
+ // Add the loaded virtualhost configuration
+ virtualHostNodeData["virtualHostInitialConfiguration"] = this.virtualHostInitialConfiguration;
+ }
+ else if (!uploadVHConfig && this.virtualHostNodeForm.validate() && this.virtualHostForm.validate())
+ {
+ virtualHostNodeData = this._getValues(this.virtualHostNodeForm);
var virtualHostNodeContext = this.virtualHostNodeContext.get("value");
if (virtualHostNodeContext)
{
virtualHostNodeData["context"] = virtualHostNodeContext;
}
+
var virtualHostData = this._getValues(this.virtualHostForm);
var virtualHostContext = this.virtualHostContext.get("value");
if (virtualHostContext)
@@ -278,48 +365,35 @@ define(["dojo/_base/xhr",
//Default the VH name to be the same as the VHN name.
virtualHostData["name"] = virtualHostNodeData["name"];
- var encodedVirtualHostNodeName = encodeURIComponent(virtualHostNodeData.name);
- xhr.put({
- url: "api/latest/virtualhostnode/" + encodedVirtualHostNodeName,
- sync: true,
- handleAs: "json",
- headers: { "Content-Type": "application/json"},
- putData: json.stringify(virtualHostNodeData),
- load: function(x) {success = true; },
- error: function(error) {success = false; failureReason = error;}
- });
-
- if(success === true && virtualHostNodeData["type"] != "BDB_HA")
- {
- var encodedVirtualHostName = encodeURIComponent(virtualHostData.name);
- xhr.put({
- url: "api/latest/virtualhost/" + encodedVirtualHostNodeName + "/" + encodedVirtualHostName,
- sync: true,
- handleAs: "json",
- headers: { "Content-Type": "application/json"},
- putData: json.stringify(virtualHostData),
- load: function (x) {
- success = true;
- },
- error: function (error) {
- success = false;
- failureReason = error;
- }
- });
- }
+ virtualHostNodeData["virtualHostInitialConfiguration"] = json.stringify(virtualHostData)
- if (success == true)
- {
- this.dialog.hide();
- }
- else
- {
- util.xhrErrorHandler(failureReason);
- }
}
else
{
- alert('Form contains invalid data. Please correct first');
+ alert('Form contains invalid data. Please correct first');
+ return;
+ }
+
+ var success = false,failureReason=null;
+
+ var encodedVirtualHostNodeName = encodeURIComponent(virtualHostNodeData.name);
+ xhr.put({
+ url: "api/latest/virtualhostnode/" + encodedVirtualHostNodeName,
+ sync: true,
+ handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.stringify(virtualHostNodeData),
+ load: function(x) {success = true; },
+ error: function(error) {success = false; failureReason = error;}
+ });
+
+ if (success == true)
+ {
+ this.dialog.hide();
+ }
+ else
+ {
+ util.xhrErrorHandler(failureReason);
}
},
_getValues: function (form)
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html
index a99c73fbf9..1a2b5293b6 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html
@@ -114,6 +114,7 @@
<button data-dojo-type="dijit.form.Button" class="startButton" type="button" data-dojo-props="disabled: true">Start</button>
<button data-dojo-type="dijit.form.Button" class="stopButton" type="button" data-dojo-props="disabled: true">Stop</button>
<button data-dojo-type="dijit.form.Button" class="editButton" type="button" data-dojo-props="disabled: true">Edit</button>
+ <button data-dojo-type="dijit.form.Button" class="downloadButton" type="button" data-dojo-props="disabled: true">Download</button>
<button data-dojo-type="dijit.form.Button" class="deleteButton" data-dojo-props="iconClass: 'dijitIconDelete'">Delete</button>
</div>