summaryrefslogtreecommitdiff
path: root/qpid/java/broker-plugins/management-http/src/main
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2012-07-08 15:28:32 +0000
committerRobert Gemmell <robbie@apache.org>2012-07-08 15:28:32 +0000
commit961d36e600fab24b35c6920481a55f8d022f9c85 (patch)
tree2413a02b2df1ef076f529c4def5b30fbd6777a79 /qpid/java/broker-plugins/management-http/src/main
parent1b245e3abac8908522f478aab6ab0aa19bb6b668 (diff)
downloadqpid-python-961d36e600fab24b35c6920481a55f8d022f9c85.tar.gz
QPID-3998, QPID-3999, QPID-4093: rename new plugins
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1358757 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/broker-plugins/management-http/src/main')
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java155
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java72
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java77
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java79
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java109
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java208
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java118
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java215
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java53
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java86
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java74
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java177
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java503
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java577
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java253
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java104
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html42
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html53
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html174
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/addUser.html42
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/setPassword.html42
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html29
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css92
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/footer.html28
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.pngbin0 -> 6600 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js213
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js110
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/footer.js30
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/formatter.js99
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/properties.js26
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/updater.js45
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js56
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js122
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js205
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js213
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js229
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js438
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js327
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js223
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js147
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js158
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js327
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js104
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/moveCopyMessages.js137
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js142
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js313
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/management.html92
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/moveCopyMessages.html36
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html25
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html25
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html47
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showExchange.html46
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html73
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html97
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html84
55 files changed, 7551 insertions, 0 deletions
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java
new file mode 100644
index 0000000000..589f46749d
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java
@@ -0,0 +1,155 @@
+/*
+ *
+ * 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.qpid.server.management.plugin;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.management.plugin.servlet.DefinedFileServlet;
+import org.apache.qpid.server.management.plugin.servlet.FileServlet;
+import org.apache.qpid.server.management.plugin.servlet.api.ExchangesServlet;
+import org.apache.qpid.server.management.plugin.servlet.api.VhostsServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.*;
+import org.apache.qpid.server.model.*;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+public class Management
+{
+
+ private final Logger _logger = Logger.getLogger(Management.class);
+
+ private Broker _broker;
+
+ private Collection<Server> _servers = new ArrayList<Server>();
+
+
+ public Management()
+ {
+ _broker = ApplicationRegistry.getInstance().getBroker();
+
+ Collection<Port> ports = _broker.getPorts();
+ for(Port port : ports)
+ {
+ // TODO - cover cases where more than just HTTP supported, and SSL as a transport
+ if(port.getProtocols().contains(Protocol.HTTP))
+ {
+ if(port.getTransports().contains(Transport.TCP))
+ {
+ int portNumber = port.getPort();
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Creating web server on port " + portNumber);
+ }
+ _servers.add(createServer(portNumber));
+ }
+ }
+ }
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.info(_servers.size() + " server(s) defined");
+ }
+
+ }
+
+ private Server createServer(int port)
+ {
+ _logger.info("Starting up web server on port " + port);
+
+ Server server = new Server(port);
+ SocketAddress socketAddress = new InetSocketAddress(port);
+
+ ServletContextHandler root = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ root.setContextPath("/");
+ server.setHandler(root);
+
+ root.addServlet(new ServletHolder(new VhostsServlet(_broker)), "/api/vhosts/*");
+ root.addServlet(new ServletHolder(new ExchangesServlet(_broker)), "/api/exchanges/*");
+
+ addRestServlet(root, "broker", socketAddress);
+ addRestServlet(root, "virtualhost", socketAddress, VirtualHost.class);
+ addRestServlet(root, "authenticationprovider", socketAddress, AuthenticationProvider.class);
+ addRestServlet(root, "user", socketAddress, AuthenticationProvider.class, User.class);
+ addRestServlet(root, "exchange", socketAddress, VirtualHost.class, Exchange.class);
+ addRestServlet(root, "queue", socketAddress, VirtualHost.class, Queue.class);
+ addRestServlet(root, "connection", socketAddress, VirtualHost.class, Connection.class);
+ addRestServlet(root, "binding", socketAddress, VirtualHost.class, Exchange.class, Queue.class, Binding.class);
+ addRestServlet(root, "port", socketAddress, Port.class);
+ addRestServlet(root, "session", socketAddress, VirtualHost.class, Connection.class, Session.class);
+
+ root.addServlet(new ServletHolder(new StructureServlet(_broker, socketAddress)), "/rest/structure");
+ root.addServlet(new ServletHolder(new MessageServlet(_broker, socketAddress)), "/rest/message/*");
+ root.addServlet(new ServletHolder(new MessageContentServlet(_broker, socketAddress)), "/rest/message-content/*");
+
+ root.addServlet(new ServletHolder(new LogRecordsServlet(_broker, socketAddress)), "/rest/logrecords");
+
+
+ root.addServlet(new ServletHolder(new SaslServlet(_broker, socketAddress)), "/rest/sasl");
+
+ root.addServlet(new ServletHolder(new DefinedFileServlet("management.html")),"/management");
+
+
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.js");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.css");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.html");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.png");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.gif");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpg");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpeg");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.json");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.txt");
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.xsl");
+
+ final SessionManager sessionManager = root.getSessionHandler().getSessionManager();
+
+ sessionManager.setMaxInactiveInterval(60 * 15);
+
+ return server;
+ }
+
+ private void addRestServlet(ServletContextHandler root, String name, SocketAddress socketAddress, Class<? extends ConfiguredObject>... hierarchy)
+ {
+ root.addServlet(new ServletHolder(new RestServlet(_broker, socketAddress, hierarchy)), "/rest/"+name+"/*");
+ }
+
+ public void start() throws Exception
+ {
+ for(Server server : _servers)
+ {
+ server.start();
+ }
+ }
+
+ public void stop() throws Exception
+ {
+ for(Server server : _servers)
+ {
+ server.stop();
+ }
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java
new file mode 100644
index 0000000000..2600d8a7bf
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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.qpid.server.management.plugin;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class ManagementActivator implements BundleActivator
+{
+ private static final Logger _logger = Logger.getLogger(ManagementActivator.class);
+
+
+ private BundleContext _ctx;
+ private String _bundleName;
+ private Management _managementService;
+
+
+ public void start(final BundleContext ctx) throws Exception
+ {
+ _ctx = ctx;
+ if (!ApplicationRegistry.getInstance().getConfiguration().getHTTPManagementEnabled())
+ {
+ _logger.info("Management plugin is diabled!");
+ ctx.getBundle().uninstall();
+ return;
+ }
+ _managementService = new Management();
+ _managementService.start();
+ _bundleName = ctx.getBundle().getSymbolicName();
+
+ // register the service
+ _logger.info("Registering management plugin: " + _bundleName);
+ _ctx.registerService(Management.class.getName(), _managementService, null);
+ _ctx.registerService(ConfigurationPluginFactory.class.getName(), ManagementConfiguration.FACTORY, null);
+ }
+
+ public void stop(final BundleContext bundleContext) throws Exception
+ {
+ if (_managementService != null)
+ {
+ _logger.info("Stopping management plugin: " + _bundleName);
+
+ _managementService.stop();
+
+ // null object references
+ _managementService = null;
+ }
+ _ctx = null;
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java
new file mode 100644
index 0000000000..3866da8f89
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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.qpid.server.management.plugin;
+
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ManagementConfiguration extends ConfigurationPlugin
+{
+ CompositeConfiguration _finalConfig;
+
+ public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory()
+ {
+ public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException
+ {
+ ConfigurationPlugin instance = new ManagementConfiguration();
+ instance.setConfiguration(path, config);
+ return instance;
+ }
+
+ public List<String> getParentPaths()
+ {
+ return Arrays.asList("management");
+ }
+ };
+
+ public String[] getElementsProcessed()
+ {
+ return new String[] { "" };
+ }
+
+ public Configuration getConfiguration()
+ {
+ return _finalConfig;
+ }
+
+
+ @Override
+ public void validateConfiguration() throws ConfigurationException
+ {
+ // Valid Configuration either has xml links to new files
+ _finalConfig = new CompositeConfiguration(getConfig());
+ List subFiles = getConfig().getList("xml[@fileName]");
+ for (Object subFile : subFiles)
+ {
+ _finalConfig.addConfiguration(new XMLConfiguration((String) subFile));
+ }
+
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java
new file mode 100644
index 0000000000..d8a8395550
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java
@@ -0,0 +1,79 @@
+/*
+ * 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.qpid.server.management.plugin.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class DefinedFileServlet extends HttpServlet
+{
+
+ private static final String FILENAME_INIT_PARAMETER = "filename";
+
+ private String _filename;
+
+ public DefinedFileServlet()
+ {
+ super();
+ }
+
+ public DefinedFileServlet(String filename)
+ {
+ _filename = filename;
+ }
+
+ @Override
+ public void init() throws ServletException
+ {
+ ServletConfig config = getServletConfig();
+ String fileName = config.getInitParameter(FILENAME_INIT_PARAMETER);
+ if (fileName != null && !"".equals(fileName))
+ {
+ _filename = fileName;
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ final ServletOutputStream output = response.getOutputStream();
+ InputStream fileInput = getClass().getResourceAsStream("/resources/"+_filename);
+
+ if(fileInput != null)
+ {
+ byte[] buffer = new byte[1024];
+ response.setStatus(HttpServletResponse.SC_OK);
+ int read = 0;
+
+ while((read = fileInput.read(buffer)) > 0)
+ {
+ output.write(buffer, 0, read);
+ }
+ }
+ else
+ {
+ response.sendError(404, "unknown file: "+ _filename);
+ }
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java
new file mode 100644
index 0000000000..f8ca082d79
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.servlet;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class FileServlet extends HttpServlet
+{
+ public static final FileServlet INSTANCE = new FileServlet();
+
+ private static final Map<String, String> CONTENT_TYPES;
+
+ static
+ {
+
+ Map<String, String> contentTypes = new HashMap<String, String>();
+ contentTypes.put("js", "application/javascript");
+ contentTypes.put("html", "text/html");
+ contentTypes.put("css", "text/css");
+ contentTypes.put("json", "application/json");
+ contentTypes.put("jpg", "image/jpg");
+ contentTypes.put("png", "image/png");
+ contentTypes.put("gif", "image/gif");
+ CONTENT_TYPES = Collections.unmodifiableMap(contentTypes);
+ }
+
+
+ public FileServlet()
+ {
+ }
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ String filename = request.getServletPath();
+ if(filename.contains("."))
+ {
+ String suffix = filename.substring(filename.lastIndexOf('.')+1);
+ String contentType = CONTENT_TYPES.get(suffix);
+ if(contentType != null)
+ {
+ response.setContentType(contentType);
+ }
+ }
+ URL resourceURL = getClass().getResource("/resources" + filename);
+ if(resourceURL != null)
+ {
+ response.setStatus(HttpServletResponse.SC_OK);
+ InputStream fileInput = resourceURL.openStream();
+ try
+ {
+ byte[] buffer = new byte[1024];
+ int read = 0;
+ ServletOutputStream output = response.getOutputStream();
+ try
+ {
+ while((read = fileInput.read(buffer)) != -1)
+ {
+ output.write(buffer, 0, read);
+ }
+ }
+ finally
+ {
+ output.close();
+ }
+ }
+ finally
+ {
+ fileInput.close();
+ }
+ }
+ else
+ {
+ response.sendError(404, "unknown file: "+ filename);
+ }
+
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java
new file mode 100644
index 0000000000..a3c5ec68a2
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java
@@ -0,0 +1,208 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.servlet.api;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectReader;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExchangesServlet extends HttpServlet
+{
+
+
+ private Broker _broker;
+
+ public ExchangesServlet()
+ {
+ super();
+ _broker = ApplicationRegistry.getInstance().getBroker();
+ }
+
+ public ExchangesServlet(Broker broker)
+ {
+ _broker = broker;
+ }
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ Collection<VirtualHost> vhosts = _broker.getVirtualHosts();
+ Collection<Exchange> exchanges = new ArrayList<Exchange>();
+ Collection<Map<String,Object>> outputObject = new ArrayList<Map<String,Object>>();
+
+ final PrintWriter writer = response.getWriter();
+
+ ObjectMapper mapper = new ObjectMapper();
+ String vhostName = null;
+ String exchangeName = null;
+
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0)
+ {
+ String path = request.getPathInfo().substring(1);
+ String[] parts = path.split("/");
+ vhostName = parts.length == 0 ? "" : parts[0];
+ if(parts.length > 1)
+ {
+ exchangeName = parts[1];
+ }
+ }
+
+ for(VirtualHost vhost : vhosts)
+ {
+ if(vhostName == null || vhostName.equals(vhost.getName()))
+ {
+ for(Exchange exchange : vhost.getExchanges())
+ {
+ if(exchangeName == null || exchangeName.equals(exchange.getName()))
+ {
+ outputObject.add(convertToObject(exchange));
+ if(exchangeName != null)
+ {
+ break;
+ }
+ }
+ }
+ if(vhostName != null)
+ {
+ break;
+ }
+ }
+ }
+
+ mapper.writeValue(writer, outputObject);
+
+ }
+
+ private Map<String,Object> convertToObject(final Exchange exchange)
+ {
+ Map<String, Object> object = new LinkedHashMap<String, Object>();
+ object.put("name",exchange.getName());
+ object.put("type", exchange.getExchangeType());
+ object.put("durable", exchange.isDurable());
+ object.put("auto-delete", exchange.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE);
+
+ Map<String,Object> arguments = new HashMap<String, Object>();
+ for(String key : exchange.getAttributeNames())
+ {
+ if(!key.equals(Exchange.TYPE))
+ {
+ arguments.put(key, exchange.getAttribute(key));
+ }
+ }
+ object.put("arguments", arguments);
+ return object;
+ }
+
+ protected void doPut(final HttpServletRequest request, final HttpServletResponse response)
+ throws ServletException, IOException
+ {
+
+ response.setContentType("application/json");
+
+
+ String vhostName = null;
+ String exchangeName = null;
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0)
+ {
+ String path = request.getPathInfo().substring(1);
+ String[] parts = path.split("/");
+ vhostName = parts.length == 0 ? "" : parts[0];
+ if(parts.length > 1)
+ {
+ exchangeName = parts[1];
+ }
+ }
+ if(vhostName == null)
+ {
+ response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
+ }
+ else if (exchangeName == null)
+ {
+ response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
+ }
+ else
+ {
+ VirtualHost vhost = null;
+ for(VirtualHost host : _broker.getVirtualHosts())
+ {
+ if(host.getName().equals(vhostName))
+ {
+ vhost = host;
+ }
+ }
+ if(vhost == null)
+ {
+ response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
+ }
+ else
+ {
+ response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+ ObjectMapper mapper = new ObjectMapper();
+ Map<String,Object> exchangeObject = mapper.readValue(request.getInputStream(), LinkedHashMap.class);
+
+ final boolean isDurable = exchangeObject.get("durable") instanceof Boolean
+ && ((Boolean)exchangeObject.get("durable"));
+ final boolean isAutoDelete = exchangeObject.get("auto_delete") instanceof Boolean
+ && ((Boolean)exchangeObject.get("auto_delete"));
+
+ final String type = (String) exchangeObject.get("type");
+ final Map<String, Object> attributes = new HashMap<String, Object>(exchangeObject);
+ attributes.remove("durable");
+ attributes.remove("auto_delete");
+ attributes.remove("type");
+
+ vhost.createExchange(exchangeName, State.ACTIVE, isDurable,
+ isAutoDelete ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT,
+ 0l,
+ type,
+ attributes);
+ }
+
+
+
+ }
+
+
+
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java
new file mode 100644
index 0000000000..b2c0fcfe52
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.servlet.api;
+
+import org.codehaus.jackson.map.ObjectMapper;
+
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.protocol.AMQConnectionModel;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.*;
+
+public class VhostsServlet extends HttpServlet
+{
+
+
+ private Broker _broker;
+
+ public VhostsServlet()
+ {
+ super();
+ _broker = ApplicationRegistry.getInstance().getBroker();
+ }
+
+ public VhostsServlet(Broker broker)
+ {
+ _broker = broker;
+ }
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+System.out.println("Get /api/vhosts");
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ Collection<VirtualHost> vhosts = _broker.getVirtualHosts();
+
+
+
+ final PrintWriter writer = response.getWriter();
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ if(request.getPathInfo() == null || request.getPathInfo().length()==0)
+ {
+
+ LinkedHashMap<String, Object> vhostObject = new LinkedHashMap<String, Object>();
+ List<Map> vhostList = new ArrayList<Map>();
+
+ for(VirtualHost vhost : vhosts)
+ {
+ vhostList.add(Collections.singletonMap("name", vhost.getName()));
+ }
+ mapper.writeValue(writer, vhostList);
+ }
+ else
+ {
+ LinkedHashMap<String, Object> vhostObject = new LinkedHashMap<String, Object>();
+ String vhostName = request.getPathInfo().substring(1);
+
+ for(VirtualHost vhost : vhosts)
+ {
+ if(vhostName.equals(vhost.getName()))
+ {
+ vhostObject.put("name", vhost.getName());
+ break;
+ }
+ }
+ mapper.writeValue(writer, vhostObject);
+ }
+ }
+
+
+ protected void doPut(final HttpServletRequest request, final HttpServletResponse response)
+ throws ServletException, IOException
+ {
+
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0)
+ {
+ String vhostName = request.getPathInfo().substring(1);
+ _broker.createVirtualHost(vhostName, State.ACTIVE, true, LifetimePolicy.PERMANENT, 0L, Collections.EMPTY_MAP);
+ }
+
+
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
new file mode 100644
index 0000000000..123f352ec1
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
@@ -0,0 +1,215 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.security.Principal;
+import java.util.Collections;
+import javax.security.auth.Subject;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+
+public abstract class AbstractServlet extends HttpServlet
+{
+ private final Broker _broker;
+ private SocketAddress _socketAddress;
+
+ protected AbstractServlet()
+ {
+ super();
+ _broker = ApplicationRegistry.getInstance().getBroker();
+ _socketAddress = null;
+ }
+
+ protected AbstractServlet(Broker broker, SocketAddress socketAddress)
+ {
+ _broker = broker;
+ _socketAddress = socketAddress;
+ }
+
+ @Override
+ protected final void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException
+ {
+ setAuthorizedSubject(request);
+ try
+ {
+ onGet(request, resp);
+ }
+ finally
+ {
+ clearAuthorizedSubject();
+ }
+ }
+
+ protected void onGet(HttpServletRequest request, HttpServletResponse resp) throws IOException, ServletException
+ {
+ super.doGet(request, resp);
+ }
+
+ private void clearAuthorizedSubject()
+ {
+ org.apache.qpid.server.security.SecurityManager.setThreadSubject(null);
+ }
+
+
+ private void setAuthorizedSubject(HttpServletRequest request)
+ {
+ HttpSession session = request.getSession(true);
+ Subject subject = (Subject) session.getAttribute("subject");
+
+ if(subject == null)
+ {
+ Principal principal = request.getUserPrincipal();
+ if(principal != null)
+ {
+ subject = new Subject(false, Collections.singleton(principal),Collections.emptySet(),
+ Collections.emptySet());
+ }
+ else
+ {
+ String header = request.getHeader("Authorization");
+
+ /*
+ * TODO - Should configure whether basic authentication is allowed... and in particular whether it
+ * should be allowed over non-ssl connections
+ * */
+
+ if (header != null)
+ {
+ String[] tokens = header.split("\\s");
+ if(tokens.length >= 2
+ && "BASIC".equalsIgnoreCase(tokens[0]))
+ {
+ String[] credentials = (new String(Base64.decodeBase64(tokens[1].getBytes()))).split(":",2);
+ if(credentials.length == 2)
+ {
+ SocketAddress address = getSocketAddress(request);
+ AuthenticationManager authenticationManager =
+ ApplicationRegistry.getInstance().getAuthenticationManager(address);
+ AuthenticationResult authResult =
+ authenticationManager.authenticate(credentials[0], credentials[1]);
+ subject = authResult.getSubject();
+
+ }
+ }
+ }
+ }
+ }
+ if (subject == null)
+ {
+ subject = AnonymousAuthenticationManager.ANONYMOUS_SUBJECT;
+ }
+ org.apache.qpid.server.security.SecurityManager.setThreadSubject(subject);
+
+ }
+
+ protected Subject getSubject(HttpSession session)
+ {
+ return (Subject)session.getAttribute("subject");
+ }
+
+ @Override
+ protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ setAuthorizedSubject(req);
+ try
+ {
+ onPost(req, resp);
+ }
+ finally
+ {
+ clearAuthorizedSubject();
+ }
+
+ }
+
+ protected void onPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ super.doPost(req, resp);
+ }
+
+ @Override
+ protected final void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ setAuthorizedSubject(req);
+ try
+ {
+ onPut(req, resp);
+
+ }
+ finally
+ {
+ clearAuthorizedSubject();
+ }
+ }
+
+ protected void onPut(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
+ {
+ super.doPut(req,resp);
+ }
+
+ @Override
+ protected final void doDelete(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException
+ {
+ setAuthorizedSubject(req);
+ try
+ {
+ onDelete(req, resp);
+ }
+ finally
+ {
+ clearAuthorizedSubject();
+ }
+ }
+
+ protected void onDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ super.doDelete(req, resp);
+ }
+
+
+ protected Broker getBroker()
+ {
+ return _broker;
+ }
+
+ protected SocketAddress getSocketAddress(HttpServletRequest request)
+ {
+ if (_socketAddress == null)
+ {
+ return InetSocketAddress.createUnresolved(request.getServerName(), request.getServerPort());
+ }
+ return _socketAddress;
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java
new file mode 100644
index 0000000000..3d862ce321
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.util.Comparator;
+import java.util.Map;
+
+class KeyComparator implements Comparator<Map>
+{
+ private String _key;
+
+ public KeyComparator(final String key)
+ {
+ _key = key;
+ }
+
+ public int compare(final Map o1, final Map o2)
+ {
+ Comparable left = (Comparable) o1.get(_key);
+ Comparable right = (Comparable) o2.get(_key);
+
+ int result;
+ if(left == null)
+ {
+ result = right == null ? 0 : -1;
+ }
+ else
+ {
+ result = left.compareTo(right);
+ }
+
+ return result;
+
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
new file mode 100644
index 0000000000..7a4b92f907
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
@@ -0,0 +1,86 @@
+/*
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.qpid.server.logging.LogRecorder;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+
+public class LogRecordsServlet extends AbstractServlet
+{
+ public LogRecordsServlet()
+ {
+ super(ApplicationRegistry.getInstance().getBroker(), null);
+ }
+
+ public LogRecordsServlet(Broker broker, SocketAddress socketaddress)
+ {
+ super(broker, socketaddress);
+ }
+
+ @Override
+ protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+
+ ApplicationRegistry applicationRegistry = (ApplicationRegistry) ApplicationRegistry.getInstance();
+ List<Map<String,Object>> logRecords = new ArrayList<Map<String, Object>>();
+
+ for(LogRecorder.Record record : applicationRegistry.getLogRecorder())
+ {
+ logRecords.add(logRecordToObject(record));
+ }
+
+ final PrintWriter writer = response.getWriter();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, logRecords);
+
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ }
+
+ private Map<String, Object> logRecordToObject(LogRecorder.Record record)
+ {
+ Map<String, Object> recordMap = new LinkedHashMap<String, Object>();
+ recordMap.put("id",record.getId());
+ recordMap.put("timestamp", record.getTimestamp());
+ recordMap.put("level", record.getLevel());
+ recordMap.put("thread", record.getThreadName());
+ recordMap.put("logger", record.getLogger());
+ recordMap.put("message", record.getMessage());
+ return recordMap;
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java
new file mode 100644
index 0000000000..84d987813b
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Map;
+
+class MapComparator implements Comparator<Map>
+{
+ private Comparator<Map>[] _sortKeys;
+
+ public MapComparator(final String[] sortKeys)
+ {
+ _sortKeys = parseKeys(sortKeys);
+ }
+
+ private static Comparator<Map>[] parseKeys(final String[] sortKeys)
+ {
+ Comparator<Map>[] comparators = new Comparator[sortKeys.length];
+ for(int i = 0; i < sortKeys.length; i++)
+ {
+ String key = sortKeys[i];
+
+ if(key.startsWith("+") || key.startsWith(" "))
+ {
+ comparators[i] = new KeyComparator(key.substring(1));
+ }
+ else if(key.startsWith("-"))
+ {
+ comparators[i] = Collections.reverseOrder(new KeyComparator(key.substring(1)));
+ }
+ else
+ {
+ comparators[i] = new KeyComparator(key);
+ }
+ }
+ return comparators;
+ }
+
+
+ public int compare(final Map o1, final Map o2)
+ {
+ int result = 0;
+ for(int i = 0; i < _sortKeys.length; i++)
+ {
+ result = _sortKeys[i].compare(o1, o2);
+ if(result != 0)
+ {
+ return result;
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java
new file mode 100644
index 0000000000..4d58a9f3b0
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java
@@ -0,0 +1,177 @@
+/*
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.QueueEntryVisitor;
+
+public class MessageContentServlet extends AbstractServlet
+{
+ public MessageContentServlet()
+ {
+ super();
+ }
+
+ public MessageContentServlet(Broker broker, SocketAddress socketaddress)
+ {
+ super(broker, socketaddress);
+ }
+
+ @Override
+ protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0 && request.getPathInfo().substring(1).split("/").length > 2)
+ {
+ getMessageContent(request, response);
+ }
+
+ }
+
+ private void getMessageContent(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ Queue queue = getQueueFromRequest(request);
+ String path[] = request.getPathInfo().substring(1).split("/");
+ MessageFinder finder = new MessageFinder(Long.parseLong(path[2]));
+ queue.visit(finder);
+ if(finder.isFound())
+ {
+ response.setContentType(finder.getMimeType());
+ response.setContentLength((int) finder.getSize());
+ response.getOutputStream().write(finder.getContent());
+
+ }
+
+ }
+
+ private Queue getQueueFromRequest(HttpServletRequest request)
+ {
+ List<String> names = new ArrayList<String>();
+ // TODO - validation that there is a vhost and queue and only those in the path
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0)
+ {
+ String path = request.getPathInfo().substring(1);
+ names.addAll(Arrays.asList(path.split("/")));
+ }
+ String vhostName = names.get(0);
+ String queueName = names.get(1);
+
+ VirtualHost vhost = null;
+
+ for(VirtualHost vh : getBroker().getVirtualHosts())
+ {
+ if(vh.getName().equals(vhostName))
+ {
+ vhost = vh;
+ break;
+ }
+ }
+
+ return getQueueFromVirtualHost(queueName, vhost);
+ }
+
+ private Queue getQueueFromVirtualHost(String queueName, VirtualHost vhost)
+ {
+ Queue queue = null;
+
+ for(Queue q : vhost.getQueues())
+ {
+ if(q.getName().equals(queueName))
+ {
+ queue = q;
+ break;
+ }
+ }
+ return queue;
+ }
+
+ private class MessageFinder implements QueueEntryVisitor
+ {
+ private final long _messageNumber;
+ private String _mimeType;
+ private long _size;
+ private byte[] _content;
+ private boolean _found;
+
+ private MessageFinder(long messageNumber)
+ {
+ _messageNumber = messageNumber;
+ }
+
+
+ public boolean visit(QueueEntry entry)
+ {
+ ServerMessage message = entry.getMessage();
+ if(message != null)
+ {
+ if(_messageNumber == message.getMessageNumber())
+ {
+ MessageReference reference = message.newReference();
+
+ _mimeType = message.getMessageHeader().getMimeType();
+ _size = message.getSize();
+ _content = new byte[(int)_size];
+ _found = true;
+ message.getContent(ByteBuffer.wrap(_content),0);
+ reference.release();
+ return true;
+ }
+
+ }
+ return false;
+ }
+
+ public String getMimeType()
+ {
+ return _mimeType;
+ }
+
+ public long getSize()
+ {
+ return _size;
+ }
+
+ public byte[] getContent()
+ {
+ return _content;
+ }
+
+ public boolean isFound()
+ {
+ return _found;
+ }
+ }
+
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
new file mode 100644
index 0000000000..b47dc8b28e
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
@@ -0,0 +1,503 @@
+/*
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.QueueEntryVisitor;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.subscription.Subscription;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+
+public class MessageServlet extends AbstractServlet
+{
+ private static final Logger LOGGER = Logger.getLogger(MessageServlet.class);
+
+ public MessageServlet()
+ {
+ super();
+ }
+
+ public MessageServlet(Broker broker, SocketAddress socketaddress)
+ {
+ super(broker, socketaddress);
+ }
+
+ @Override
+ protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0 && request.getPathInfo().substring(1).split("/").length > 2)
+ {
+ getMessageContent(request, response);
+ }
+ else
+ {
+ getMessageList(request, response);
+ }
+
+ }
+
+ private void getMessageContent(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ Queue queue = getQueueFromRequest(request);
+ String path[] = request.getPathInfo().substring(1).split("/");
+ MessageFinder messageFinder = new MessageFinder(Long.parseLong(path[2]));
+ queue.visit(messageFinder);
+
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+
+ final PrintWriter writer = response.getWriter();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, messageFinder.getMessageObject());
+ }
+
+ private void getMessageList(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ Queue queue = getQueueFromRequest(request);
+
+ int first = -1;
+ int last = -1;
+ String range = request.getHeader("Range");
+ if(range != null)
+ {
+ String[] boundaries = range.split("=")[1].split("-");
+ first = Integer.parseInt(boundaries[0]);
+ last = Integer.parseInt(boundaries[1]);
+ }
+ final MessageCollector messageCollector = new MessageCollector(first, last);
+ queue.visit(messageCollector);
+
+ response.setContentType("application/json");
+ final List<Map<String, Object>> messages = messageCollector.getMessages();
+ int queueSize = ((Number) queue.getStatistics().getStatistic(Queue.QUEUE_DEPTH_MESSAGES)).intValue();
+ String min = messages.isEmpty() ? "0" : messages.get(0).get("position").toString();
+ String max = messages.isEmpty() ? "0" : messages.get(messages.size()-1).get("position").toString();
+ response.setHeader("Content-Range", (min + "-" + max + "/" + queueSize));
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+
+ final PrintWriter writer = response.getWriter();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, messages);
+ }
+
+ private Queue getQueueFromRequest(HttpServletRequest request)
+ {
+ List<String> names = new ArrayList<String>();
+ // TODO - validation that there is a vhost and queue and only those in the path
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0)
+ {
+ String path = request.getPathInfo().substring(1);
+ names.addAll(Arrays.asList(path.split("/")));
+ }
+ String vhostName = names.get(0);
+ String queueName = names.get(1);
+
+ VirtualHost vhost = null;
+
+ for(VirtualHost vh : getBroker().getVirtualHosts())
+ {
+ if(vh.getName().equals(vhostName))
+ {
+ vhost = vh;
+ break;
+ }
+ }
+
+ return getQueueFromVirtualHost(queueName, vhost);
+ }
+
+ private Queue getQueueFromVirtualHost(String queueName, VirtualHost vhost)
+ {
+ Queue queue = null;
+
+ for(Queue q : vhost.getQueues())
+ {
+
+ if(q.getName().equals(queueName))
+ {
+ queue = q;
+ break;
+ }
+ }
+ return queue;
+ }
+
+ private abstract static class QueueEntryTransaction implements VirtualHost.TransactionalOperation
+ {
+ private final Queue _sourceQueue;
+ private final List _messageIds;
+
+ protected QueueEntryTransaction(Queue sourceQueue, List messageIds)
+ {
+ _sourceQueue = sourceQueue;
+ _messageIds = messageIds;
+ }
+
+
+ public void withinTransaction(final VirtualHost.Transaction txn)
+ {
+
+ _sourceQueue.visit(new QueueEntryVisitor()
+ {
+
+ public boolean visit(final QueueEntry entry)
+ {
+ final ServerMessage message = entry.getMessage();
+ if(message != null)
+ {
+ final long messageId = message.getMessageNumber();
+ if (_messageIds.remove(messageId) || (messageId <= (long) Integer.MAX_VALUE
+ && _messageIds.remove(Integer.valueOf((int)messageId))))
+ {
+ updateEntry(entry, txn);
+ }
+ }
+ return _messageIds.isEmpty();
+ }
+ });
+ }
+
+
+ protected abstract void updateEntry(QueueEntry entry, VirtualHost.Transaction txn);
+ }
+
+ private static class MoveTransaction extends QueueEntryTransaction
+ {
+ private final Queue _destinationQueue;
+
+ public MoveTransaction(Queue sourceQueue, List<Long> messageIds, Queue destinationQueue)
+ {
+ super(sourceQueue, messageIds);
+ _destinationQueue = destinationQueue;
+ }
+
+ protected void updateEntry(QueueEntry entry, VirtualHost.Transaction txn)
+ {
+ txn.move(entry, _destinationQueue);
+ }
+ }
+
+ private static class CopyTransaction extends QueueEntryTransaction
+ {
+ private final Queue _destinationQueue;
+
+ public CopyTransaction(Queue sourceQueue, List<Long> messageIds, Queue destinationQueue)
+ {
+ super(sourceQueue, messageIds);
+ _destinationQueue = destinationQueue;
+ }
+
+ protected void updateEntry(QueueEntry entry, VirtualHost.Transaction txn)
+ {
+ txn.copy(entry, _destinationQueue);
+ }
+ }
+
+ private static class DeleteTransaction extends QueueEntryTransaction
+ {
+ public DeleteTransaction(Queue sourceQueue, List<Long> messageIds)
+ {
+ super(sourceQueue, messageIds);
+ }
+
+ protected void updateEntry(QueueEntry entry, VirtualHost.Transaction txn)
+ {
+ txn.dequeue(entry);
+ }
+ }
+
+
+
+ private class MessageCollector implements QueueEntryVisitor
+ {
+ private final int _first;
+ private final int _last;
+ private int _position = -1;
+ private final List<Map<String, Object>> _messages = new ArrayList<Map<String, Object>>();
+
+ private MessageCollector(int first, int last)
+ {
+ _first = first;
+ _last = last;
+ }
+
+
+ public boolean visit(QueueEntry entry)
+ {
+
+ _position++;
+ if((_first == -1 || _position >= _first) && (_last == -1 || _position <= _last))
+ {
+ final Map<String, Object> messageObject = convertToObject(entry, false);
+ messageObject.put("position", _position);
+ _messages.add(messageObject);
+ }
+ return _last != -1 && _position > _last;
+ }
+
+ public List<Map<String, Object>> getMessages()
+ {
+ return _messages;
+ }
+ }
+
+
+ private class MessageFinder implements QueueEntryVisitor
+ {
+ private final long _messageNumber;
+ private Map<String, Object> _messageObject;
+
+ private MessageFinder(long messageNumber)
+ {
+ _messageNumber = messageNumber;
+ }
+
+
+ public boolean visit(QueueEntry entry)
+ {
+ ServerMessage message = entry.getMessage();
+ if(message != null)
+ {
+ if(_messageNumber == message.getMessageNumber())
+ {
+ MessageReference reference = message.newReference();
+ _messageObject = convertToObject(entry, true);
+ reference.release();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Map<String, Object> getMessageObject()
+ {
+ return _messageObject;
+ }
+ }
+
+ private Map<String, Object> convertToObject(QueueEntry entry, boolean includeContent)
+ {
+ Map<String, Object> object = new LinkedHashMap<String, Object>();
+ object.put("size", entry.getSize());
+ object.put("deliveryCount", entry.getDeliveryCount());
+ object.put("state",entry.isAvailable()
+ ? "Available"
+ : entry.isAcquired()
+ ? "Acquired"
+ : "");
+ final Subscription deliveredSubscription = entry.getDeliveredSubscription();
+ object.put("deliveredTo", deliveredSubscription == null ? null : deliveredSubscription.getSubscriptionID());
+ ServerMessage message = entry.getMessage();
+
+ if(message != null)
+ {
+ convertMessageProperties(object, message);
+ if(includeContent)
+ {
+ convertMessageHeaders(object, message);
+ }
+ }
+
+ return object;
+ }
+
+ private void convertMessageProperties(Map<String, Object> object, ServerMessage message)
+ {
+ object.put("id", message.getMessageNumber());
+ object.put("arrivalTime",message.getArrivalTime());
+ object.put("persistent", message.isPersistent());
+
+ final AMQMessageHeader messageHeader = message.getMessageHeader();
+ if(messageHeader != null)
+ {
+ addIfPresent(object, "messageId", messageHeader.getMessageId());
+ addIfPresent(object, "expirationTime", messageHeader.getExpiration());
+ addIfPresent(object, "applicationId", messageHeader.getAppId());
+ addIfPresent(object, "correlationId", messageHeader.getCorrelationId());
+ addIfPresent(object, "encoding", messageHeader.getEncoding());
+ addIfPresent(object, "mimeType", messageHeader.getMimeType());
+ addIfPresent(object, "priority", messageHeader.getPriority());
+ addIfPresent(object, "replyTo", messageHeader.getReplyTo());
+ addIfPresent(object, "timestamp", messageHeader.getTimestamp());
+ addIfPresent(object, "type", messageHeader.getType());
+ addIfPresent(object, "userId", messageHeader.getUserId());
+ }
+
+ }
+
+ private void addIfPresent(Map<String, Object> object, String name, Object property)
+ {
+ if(property != null)
+ {
+ object.put(name, property);
+ }
+ }
+
+ private void convertMessageHeaders(Map<String, Object> object, ServerMessage message)
+ {
+ final AMQMessageHeader messageHeader = message.getMessageHeader();
+ if(messageHeader != null)
+ {
+ Map<String, Object> headers = new HashMap<String,Object>();
+ for(String headerName : messageHeader.getHeaderNames())
+ {
+ headers.put(headerName, messageHeader.getHeader(headerName));
+ }
+ object.put("headers", headers);
+ }
+ }
+
+ /*
+ * POST moves or copies messages to the given queue from a queue specified in the posted JSON data
+ */
+ @Override
+ protected void onPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+
+ try
+ {
+ final Queue sourceQueue = getQueueFromRequest(request);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ @SuppressWarnings("unchecked")
+ Map<String,Object> providedObject = mapper.readValue(request.getInputStream(), LinkedHashMap.class);
+
+ String destQueueName = (String) providedObject.get("destinationQueue");
+ Boolean move = (Boolean) providedObject.get("move");
+
+ final VirtualHost vhost = sourceQueue.getParent(VirtualHost.class);
+
+ boolean isMoveTransaction = move != null && Boolean.valueOf(move);
+
+ // FIXME: added temporary authorization check until we introduce management layer
+ // and review current ACL rules to have common rules for all management interfaces
+ String methodName = isMoveTransaction? "moveMessages":"copyMessages";
+ if (isQueueUpdateMethodAuthorized(methodName, vhost.getName()))
+ {
+ final Queue destinationQueue = getQueueFromVirtualHost(destQueueName, vhost);
+ final List messageIds = new ArrayList((List) providedObject.get("messages"));
+ QueueEntryTransaction txn =
+ isMoveTransaction
+ ? new MoveTransaction(sourceQueue, messageIds, destinationQueue)
+ : new CopyTransaction(sourceQueue, messageIds, destinationQueue);
+ vhost.executeTransaction(txn);
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+ else
+ {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ }
+ catch(RuntimeException e)
+ {
+ LOGGER.error("Failure to perform message opertion", e);
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+
+ /*
+ * DELETE removes messages from the queue
+ */
+ @Override
+ protected void onDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+
+ final Queue sourceQueue = getQueueFromRequest(request);
+
+ final VirtualHost vhost = sourceQueue.getParent(VirtualHost.class);
+
+
+ final List<Long> messageIds = new ArrayList<Long>();
+ for(String idStr : request.getParameterValues("id"))
+ {
+ messageIds.add(Long.valueOf(idStr));
+ }
+
+ // FIXME: added temporary authorization check until we introduce management layer
+ // and review current ACL rules to have common rules for all management interfaces
+ if (isQueueUpdateMethodAuthorized("deleteMessages", vhost.getName()))
+ {
+ vhost.executeTransaction(new DeleteTransaction(sourceQueue, messageIds));
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+ else
+ {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ }
+
+ private boolean isQueueUpdateMethodAuthorized(String methodName, String virtualHost)
+ {
+ SecurityManager securityManager = getSecurityManager(virtualHost);
+ return securityManager.authoriseMethod(Operation.UPDATE, "VirtualHost.Queue", methodName);
+ }
+
+ private SecurityManager getSecurityManager(String virtualHost)
+ {
+ IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
+ SecurityManager security;
+ if (virtualHost == null)
+ {
+ security = appRegistry.getSecurityManager();
+ }
+ else
+ {
+ security = appRegistry.getVirtualHostRegistry().getVirtualHost(virtualHost).getSecurityManager();
+ }
+ return security;
+ }
+
+}
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
new file mode 100644
index 0000000000..dbf9f9b48d
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
@@ -0,0 +1,577 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.SocketAddress;
+import java.util.*;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.server.model.*;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+
+
+public class RestServlet extends AbstractServlet
+{
+ /**
+ * An initialization parameter to specify hierarchy
+ */
+ private static final String HIERARCHY_INIT_PARAMETER = "hierarchy";
+
+ public static final String DEPTH_PARAM = "depth";
+ public static final String SORT_PARAM = "sort";
+
+ public static final Set<String> RESERVED_PARAMS = new HashSet<String>(Arrays.asList(DEPTH_PARAM, SORT_PARAM));
+
+ private Class<? extends ConfiguredObject>[] _hierarchy;
+
+ private volatile boolean initializationRequired = false;
+
+ public RestServlet()
+ {
+ super();
+ initializationRequired = true;
+ }
+
+ public RestServlet(Broker broker, SocketAddress socketaddress, Class<? extends ConfiguredObject>... hierarchy)
+ {
+ super(broker, socketaddress);
+ _hierarchy = hierarchy;
+ }
+
+ @Override
+ public void init() throws ServletException
+ {
+ if (initializationRequired)
+ {
+ doInitialization();
+ initializationRequired = false;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void doInitialization() throws ServletException
+ {
+ ServletConfig config = getServletConfig();
+ String hierarchy = config.getInitParameter(HIERARCHY_INIT_PARAMETER);
+ if (hierarchy != null && !"".equals(hierarchy))
+ {
+ List<Class<? extends ConfiguredObject>> classes = new ArrayList<Class<? extends ConfiguredObject>>();
+ String[] hierarchyItems = hierarchy.split(",");
+ for (String item : hierarchyItems)
+ {
+ Class<?> itemClass = null;
+ try
+ {
+ itemClass = Class.forName(item);
+ }
+ catch (ClassNotFoundException e)
+ {
+ try
+ {
+ itemClass = Class.forName("org.apache.qpid.server.model." + item);
+ }
+ catch (ClassNotFoundException e1)
+ {
+ throw new ServletException("Unknown configured object class '" + item
+ + "' is specified in hierarchy for " + config.getServletName());
+ }
+ }
+ Class<? extends ConfiguredObject> clazz = (Class<? extends ConfiguredObject>)itemClass;
+ classes.add(clazz);
+ }
+ Class<? extends ConfiguredObject>[] hierachyClasses = (Class<? extends ConfiguredObject>[])new Class[classes.size()];
+ _hierarchy = classes.toArray(hierachyClasses);
+ }
+ else
+ {
+ _hierarchy = (Class<? extends ConfiguredObject>[])new Class[0];
+ }
+ }
+
+ protected Collection<ConfiguredObject> getObjects(HttpServletRequest request)
+ {
+ List<String> names = new ArrayList<String>();
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0)
+ {
+ String path = request.getPathInfo().substring(1);
+ names.addAll(Arrays.asList(path.split("/")));
+
+ if(names.size() > _hierarchy.length)
+ {
+ throw new IllegalArgumentException("Too many entries in path");
+ }
+ }
+
+ Collection<ConfiguredObject> parents = Collections.singleton((ConfiguredObject) getBroker());
+ Collection<ConfiguredObject> children = new ArrayList<ConfiguredObject>();
+
+ Map<Class<? extends ConfiguredObject>, String> filters =
+ new HashMap<Class<? extends ConfiguredObject>, String>();
+
+ for(int i = 0; i < _hierarchy.length; i++)
+ {
+ if(i == 0 || Model.getChildTypes(_hierarchy[i - 1]).contains(_hierarchy[i]))
+ {
+
+ for(ConfiguredObject parent : parents)
+ {
+ if(names.size() > i
+ && names.get(i) != null
+ && !names.get(i).equals("*")
+ && names.get(i).trim().length() != 0)
+ {
+ for(ConfiguredObject child : parent.getChildren(_hierarchy[i]))
+ {
+ if(child.getName().equals(names.get(i)))
+ {
+ children.add(child);
+ }
+ }
+ }
+ else
+ {
+ children.addAll(parent.getChildren(_hierarchy[i]));
+ }
+ }
+ }
+ else
+ {
+ children = parents;
+ if(names.size() > i
+ && names.get(i) != null
+ && !names.get(i).equals("*")
+ && names.get(i).trim().length() != 0)
+ {
+ filters.put(_hierarchy[i], names.get(i));
+ }
+ }
+
+ parents = children;
+ children = new ArrayList<ConfiguredObject>();
+ }
+
+ if(!filters.isEmpty())
+ {
+ Collection<ConfiguredObject> potentials = parents;
+ parents = new ArrayList<ConfiguredObject>();
+
+ for(ConfiguredObject o : potentials)
+ {
+
+ boolean match = true;
+
+ for(Map.Entry<Class<? extends ConfiguredObject>, String> entry : filters.entrySet())
+ {
+ Collection<? extends ConfiguredObject> ancestors =
+ getAncestors(getConfiguredClass(),entry.getKey(), o);
+ match = false;
+ for(ConfiguredObject ancestor : ancestors)
+ {
+ if(ancestor.getName().equals(entry.getValue()))
+ {
+ match = true;
+ break;
+ }
+ }
+ if(!match)
+ {
+ break;
+ }
+ }
+ if(match)
+ {
+ parents.add(o);
+ }
+
+ }
+ }
+
+ return filter(parents, request);
+ }
+
+ private Collection<ConfiguredObject> filter(Collection<ConfiguredObject> objects, HttpServletRequest request)
+ {
+
+
+ Map<String, Collection<String>> filters = new HashMap<String, Collection<String>>();
+
+ for(String param : (Collection<String>) Collections.list(request.getParameterNames()))
+ {
+ if(!RESERVED_PARAMS.contains(param))
+ {
+ filters.put(param, Arrays.asList(request.getParameterValues(param)));
+ }
+ }
+
+ if(filters.isEmpty())
+ {
+ return objects;
+ }
+
+ Collection<ConfiguredObject> filteredObj = new ArrayList<ConfiguredObject>(objects);
+
+ Iterator<ConfiguredObject> iter = filteredObj.iterator();
+
+ while(iter.hasNext())
+ {
+ ConfiguredObject obj = iter.next();
+ for(Map.Entry<String, Collection<String>> entry : filters.entrySet())
+ {
+ Object value = obj.getAttribute(entry.getKey());
+ if(!entry.getValue().contains(String.valueOf(value)))
+ {
+ iter.remove();
+ }
+ }
+
+ }
+
+ return filteredObj;
+ }
+
+ private Collection<? extends ConfiguredObject> getAncestors(Class<? extends ConfiguredObject> childType,
+ Class<? extends ConfiguredObject> ancestorType,
+ ConfiguredObject child)
+ {
+ Collection<ConfiguredObject> ancestors = new HashSet<ConfiguredObject>();
+ Collection<Class<? extends ConfiguredObject>> parentTypes = Model.getParentTypes(childType);
+
+ for(Class<? extends ConfiguredObject> parentClazz : parentTypes)
+ {
+ if(parentClazz == ancestorType)
+ {
+ ConfiguredObject parent = child.getParent(parentClazz);
+ if(parent != null)
+ {
+ ancestors.add(parent);
+ }
+ }
+ else
+ {
+ ConfiguredObject parent = child.getParent(parentClazz);
+ if(parent != null)
+ {
+ ancestors.addAll(getAncestors(parentClazz, ancestorType, parent));
+ }
+ }
+ }
+
+ return ancestors;
+ }
+
+
+ protected Map<String, Object> convertObjectToMap(final ConfiguredObject confObject,
+ Class<? extends ConfiguredObject> clazz,
+ int depth)
+ {
+ Map<String, Object> object = new LinkedHashMap<String, Object>();
+
+ for(String name : confObject.getAttributeNames())
+ {
+ Object value = confObject.getAttribute(name);
+ if(value != null)
+ {
+ object.put(name, value);
+ }
+ }
+
+ Statistics statistics = confObject.getStatistics();
+ Map<String, Object> statMap = new HashMap<String, Object>();
+ for(String name : statistics.getStatisticNames())
+ {
+ Object value = statistics.getStatistic(name);
+ if(value != null)
+ {
+ statMap.put(name, value);
+ }
+ }
+
+ if(!statMap.isEmpty())
+ {
+ object.put("statistics", statMap);
+ }
+
+ if(depth > 0)
+ {
+ for(Class<? extends ConfiguredObject> childClass : Model.getChildTypes(clazz))
+ {
+ Collection<? extends ConfiguredObject> children = confObject.getChildren(childClass);
+ if(children != null)
+ {
+ List<Map<String, Object>> childObjects = new ArrayList<Map<String, Object>>();
+
+ for(ConfiguredObject child : children)
+ {
+ childObjects.add(convertObjectToMap(child, childClass, depth-1));
+ }
+
+ if(!childObjects.isEmpty())
+ {
+ object.put(childClass.getSimpleName().toLowerCase()+"s",childObjects);
+ }
+ }
+ }
+ }
+ return object;
+ }
+
+ @Override
+ protected void onGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+
+ Collection<ConfiguredObject> allObjects = getObjects(request);
+
+ @SuppressWarnings("unchecked")
+ Map params = new HashMap(request.getParameterMap());
+
+ int depth = 1;
+ try
+ {
+ depth = Integer.parseInt(String.valueOf(params.remove("depth")));
+ }
+ catch (NumberFormatException e)
+ {
+ // Ignore
+ }
+
+ List<Map<String, Object>> output = new ArrayList<Map<String, Object>>();
+
+ // TODO - depth and sort special params, everything else should act as a filter
+ if(request.getParameter(DEPTH_PARAM)!=null)
+ {
+ try
+ {
+ depth = Integer.parseInt(request.getParameter(DEPTH_PARAM));
+ }
+ catch (NumberFormatException e)
+ {
+
+ }
+ }
+
+ for(ConfiguredObject configuredObject : allObjects)
+ {
+ output.add(convertObjectToMap(configuredObject, getConfiguredClass(),depth));
+ }
+
+ final PrintWriter writer = response.getWriter();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, output);
+
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ }
+
+ private Class<? extends ConfiguredObject> getConfiguredClass()
+ {
+ return _hierarchy.length == 0 ? Broker.class : _hierarchy[_hierarchy.length-1];
+ }
+
+ @Override
+ protected void onPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.setContentType("application/json");
+
+ ObjectMapper mapper = new ObjectMapper();
+ @SuppressWarnings("unchecked")
+ Map<String,Object> providedObject = mapper.readValue(request.getInputStream(), LinkedHashMap.class);
+
+
+ List<String> names = new ArrayList<String>();
+ if(request.getPathInfo() != null && request.getPathInfo().length()>0)
+ {
+ String path = request.getPathInfo().substring(1);
+ names.addAll(Arrays.asList(path.split("/")));
+
+ if(names.size() != _hierarchy.length)
+ {
+ throw new IllegalArgumentException("Path to object to create must be fully specified");
+ }
+ }
+
+
+ providedObject.put("name", names.get(names.size()-1));
+
+ @SuppressWarnings("unchecked")
+ Collection<ConfiguredObject>[] objects = new Collection[_hierarchy.length];
+ if(_hierarchy.length == 1)
+ {
+ try
+ {
+ getBroker().createChild(_hierarchy[0], providedObject);
+ }
+ catch (RuntimeException e)
+ {
+ setResponseStatus(response, e);
+ return;
+ }
+
+ }
+ else
+ {
+ for(int i = 0; i < _hierarchy.length-1; i++)
+ {
+ objects[i] = new HashSet<ConfiguredObject>();
+ if(i == 0)
+ {
+ for(ConfiguredObject object : getBroker().getChildren(_hierarchy[0]))
+ {
+ if(object.getName().equals(names.get(0)))
+ {
+ objects[0].add(object);
+ break;
+ }
+ }
+ }
+ else
+ {
+ for(int j = i-1; j >=0; j--)
+ {
+ if(Model.getChildTypes(_hierarchy[j]).contains(_hierarchy[i]))
+ {
+ for(ConfiguredObject parent : objects[j])
+ {
+ for(ConfiguredObject object : parent.getChildren(_hierarchy[i]))
+ {
+ if(object.getName().equals(names.get(i)))
+ {
+ objects[i].add(object);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ }
+ List<ConfiguredObject> parents = new ArrayList<ConfiguredObject>();
+ Class<? extends ConfiguredObject> objClass = getConfiguredClass();
+ Collection<Class<? extends ConfiguredObject>> parentClasses = Model.getParentTypes(objClass);
+ for(int i = _hierarchy.length-2; i >=0 ; i--)
+ {
+ if(parentClasses.contains(_hierarchy[i]))
+ {
+ if(objects[i].size() == 1)
+ {
+ parents.add(objects[i].iterator().next());
+ }
+ else
+ {
+ throw new IllegalArgumentException("Cannot deduce parent of class "
+ + _hierarchy[i].getSimpleName());
+ }
+ }
+
+ }
+ ConfiguredObject theParent = parents.remove(0);
+ ConfiguredObject[] otherParents = parents.toArray(new ConfiguredObject[parents.size()]);
+
+ try
+ {
+
+ Collection<? extends ConfiguredObject> existingChildren = theParent.getChildren(objClass);
+ for(ConfiguredObject obj: existingChildren)
+ {
+ if((providedObject.containsKey("id") && String.valueOf(providedObject.get("id")).equals(obj.getId().toString()))
+ || (obj.getName().equals(providedObject.get("name")) && equalParents(obj, otherParents)))
+ {
+ doUpdate(obj, providedObject);
+ }
+ }
+ theParent.createChild(objClass, providedObject, otherParents);
+ }
+ catch (RuntimeException e)
+ {
+ setResponseStatus(response, e);
+ return;
+ }
+
+ }
+ response.setStatus(HttpServletResponse.SC_CREATED);
+ }
+
+ private void doUpdate(ConfiguredObject obj, Map<String, Object> providedObject)
+ {
+ for(Map.Entry<String,Object> entry : providedObject.entrySet())
+ {
+ obj.setAttribute(entry.getKey(), obj.getAttribute(entry.getKey()), entry.getValue());
+ }
+ //TODO - Implement.
+ }
+
+ private boolean equalParents(ConfiguredObject obj, ConfiguredObject[] otherParents)
+ {
+ if(otherParents == null || otherParents.length == 0)
+ {
+ return true;
+ }
+ return false; //TODO - Implement.
+ }
+
+ private void setResponseStatus(HttpServletResponse response, RuntimeException e) throws IOException
+ {
+ if (e.getCause() instanceof AMQSecurityException)
+ {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ else
+ {
+ // TODO
+ response.setStatus(HttpServletResponse.SC_CONFLICT);
+ }
+ }
+
+ @Override
+ protected void onDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+ try
+ {
+ Collection<ConfiguredObject> allObjects = getObjects(request);
+ for(ConfiguredObject o : allObjects)
+ {
+ o.setDesiredState(o.getActualState(), State.DELETED);
+ }
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+ catch(RuntimeException e)
+ {
+ setResponseStatus(response, e);
+ }
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
new file mode 100644
index 0000000000..0787e7ec1d
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
@@ -0,0 +1,253 @@
+/*
+ *
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import org.apache.commons.codec.binary.Base64;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+
+import javax.security.auth.Subject;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.SocketAddress;
+import java.security.Principal;
+import java.security.SecureRandom;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Random;
+
+public class SaslServlet extends AbstractServlet
+{
+ private static final Logger LOGGER = Logger.getLogger(SaslServlet.class);
+
+ private static final SecureRandom SECURE_RANDOM = new SecureRandom();
+ private static final String ATTR_RANDOM = "SaslServlet.Random";
+ private static final String ATTR_ID = "SaslServlet.ID";
+ private static final String ATTR_SASL_SERVER = "SaslServlet.SaslServer";
+ private static final String ATTR_EXPIRY = "SaslServlet.Expiry";
+ private static final long SASL_EXCHANGE_EXPIRY = 1000L;
+
+
+ public SaslServlet()
+ {
+ super();
+ }
+
+ public SaslServlet(Broker broker, SocketAddress socketaddress)
+ {
+ super(broker, socketaddress);
+ }
+
+ protected void onGet(HttpServletRequest request, HttpServletResponse response) throws
+ ServletException,
+ IOException
+ {
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+
+ HttpSession session = request.getSession();
+ Random rand = getRandom(session);
+
+ AuthenticationManager authManager = ApplicationRegistry.getInstance().getAuthenticationManager(getSocketAddress(request));
+ String[] mechanisms = authManager.getMechanisms().split(" ");
+ Map<String, Object> outputObject = new LinkedHashMap<String, Object>();
+ final Subject subject = (Subject) session.getAttribute("subject");
+ if(subject != null)
+ {
+ final Principal principal = subject.getPrincipals().iterator().next();
+ outputObject.put("user", principal.getName());
+ }
+
+ outputObject.put("mechanisms", (Object) mechanisms);
+
+ final PrintWriter writer = response.getWriter();
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, outputObject);
+
+ }
+
+ private Random getRandom(final HttpSession session)
+ {
+ Random rand = (Random) session.getAttribute(ATTR_RANDOM);
+ if(rand == null)
+ {
+ synchronized (SECURE_RANDOM)
+ {
+ rand = new Random(SECURE_RANDOM.nextLong());
+ }
+ session.setAttribute(ATTR_RANDOM, rand);
+ }
+ return rand;
+ }
+
+
+ @Override
+ protected void onPost(final HttpServletRequest request, final HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ try
+ {
+ response.setContentType("application/json");
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader("Expires", 0);
+
+ HttpSession session = request.getSession();
+
+ String mechanism = request.getParameter("mechanism");
+ String id = request.getParameter("id");
+ String saslResponse = request.getParameter("response");
+
+ AuthenticationManager authManager = ApplicationRegistry.getInstance().getAuthenticationManager(getSocketAddress(request));
+
+ if(mechanism != null)
+ {
+ if(id == null)
+ {
+ SaslServer saslServer = authManager.createSaslServer(mechanism, request.getServerName(), null/*TODO*/);
+ evaluateSaslResponse(response, session, saslResponse, saslServer);
+ }
+ else
+ {
+ response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
+ session.removeAttribute(ATTR_ID);
+ session.removeAttribute(ATTR_SASL_SERVER);
+ session.removeAttribute(ATTR_EXPIRY);
+
+ }
+
+ }
+ else
+ {
+ if(id != null)
+ {
+ if(id.equals(session.getAttribute(ATTR_ID)) && System.currentTimeMillis() < (Long) session.getAttribute(ATTR_EXPIRY))
+ {
+ SaslServer saslServer = (SaslServer) session.getAttribute(ATTR_SASL_SERVER);
+ evaluateSaslResponse(response, session, saslResponse, saslServer);
+
+ }
+ else
+ {
+ response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
+ session.removeAttribute(ATTR_ID);
+ session.removeAttribute(ATTR_SASL_SERVER);
+ session.removeAttribute(ATTR_EXPIRY);
+ }
+ }
+ else
+ {
+ response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
+ session.removeAttribute(ATTR_ID);
+ session.removeAttribute(ATTR_SASL_SERVER);
+ session.removeAttribute(ATTR_EXPIRY);
+
+ }
+ }
+ }
+ catch(IOException e)
+ {
+ LOGGER.error("Error processing SASL request", e);
+ throw e;
+ }
+ catch(RuntimeException e)
+ {
+ LOGGER.error("Error processing SASL request", e);
+ throw e;
+ }
+
+ }
+
+ private void evaluateSaslResponse(final HttpServletResponse response,
+ final HttpSession session,
+ final String saslResponse, final SaslServer saslServer) throws IOException
+ {
+ final String id;
+ byte[] challenge;
+ try
+ {
+ challenge = saslServer.evaluateResponse(saslResponse == null ? new byte[0] : Base64.decodeBase64(saslResponse.getBytes()));
+ }
+ catch(SaslException e)
+ {
+
+ session.removeAttribute(ATTR_ID);
+ session.removeAttribute(ATTR_SASL_SERVER);
+ session.removeAttribute(ATTR_EXPIRY);
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+
+ return;
+ }
+
+ if(saslServer.isComplete())
+ {
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new UsernamePrincipal(saslServer.getAuthorizationID()));
+ session.setAttribute("subject", subject);
+ session.removeAttribute(ATTR_ID);
+ session.removeAttribute(ATTR_SASL_SERVER);
+ session.removeAttribute(ATTR_EXPIRY);
+
+ response.setStatus(HttpServletResponse.SC_OK);
+
+
+ }
+ else
+ {
+ Random rand = getRandom(session);
+ id = String.valueOf(rand.nextLong());
+ session.setAttribute(ATTR_ID, id);
+ session.setAttribute(ATTR_SASL_SERVER, saslServer);
+ session.setAttribute(ATTR_EXPIRY, System.currentTimeMillis() + SASL_EXCHANGE_EXPIRY);
+
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ Map<String, Object> outputObject = new LinkedHashMap<String, Object>();
+ outputObject.put("id", id);
+ outputObject.put("challenge", new String(Base64.encodeBase64(challenge)));
+
+ final PrintWriter writer = response.getWriter();
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, outputObject);
+
+ }
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
new file mode 100644
index 0000000000..6295d74b42
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
@@ -0,0 +1,104 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Model;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+
+public class StructureServlet extends AbstractServlet
+{
+ public StructureServlet()
+ {
+ super();
+ }
+
+ public StructureServlet(Broker broker, SocketAddress socketaddress)
+ {
+ super(broker, socketaddress);
+ }
+
+ @Override
+ protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+
+ Map<String,Object> structure = generateStructure(getBroker(), Broker.class);
+
+ final PrintWriter writer = response.getWriter();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, structure);
+
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ }
+
+ private Map<String, Object> generateStructure(ConfiguredObject object, Class<? extends ConfiguredObject> clazz)
+ {
+ Map<String, Object> structure = new LinkedHashMap<String, Object>();
+ structure.put("id", object.getId());
+ structure.put("name", object.getName());
+
+ for(Class<? extends ConfiguredObject> childClass : Model.getChildTypes(clazz))
+ {
+ Collection<? extends ConfiguredObject> children = object.getChildren(childClass);
+ if(children != null)
+ {
+ List<Map<String, Object>> childObjects = new ArrayList<Map<String, Object>>();
+
+ for(ConfiguredObject child : children)
+ {
+ childObjects.add(generateStructure(child, childClass));
+ }
+
+ if(!childObjects.isEmpty())
+ {
+ structure.put(pluralize(childClass),childObjects);
+ }
+ }
+ }
+
+ return structure;
+ }
+
+ private String pluralize(Class<? extends ConfiguredObject> childClass)
+ {
+ String name = childClass.getSimpleName().toLowerCase();
+ return name + (name.endsWith("s") ? "es" : "s");
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html
new file mode 100644
index 0000000000..8dbd219c8d
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html
@@ -0,0 +1,42 @@
+<!--
+ ~ 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.
+ -->
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Binding'" id="addBinding">
+ <form id="formAddBinding" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Exchange Name*: </strong></td>
+ <td><div id="addBinding.selectExchangeDiv"></div></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Queue Name*: </strong></td>
+ <td><div id="addBinding.selectQueueDiv"></div></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Binding Key*: </strong></td>
+ <td><input type="text" required="true" name="name" id="formAddbinding.bindingKey" placeholder="Binding Key"
+ dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td>
+ </tr>
+ </table>
+ <br/>
+
+ <!-- submit buttons -->
+ <input type="submit" value="Create Binding" label="Create Binding" dojoType="dijit.form.Button" />
+
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html
new file mode 100644
index 0000000000..cccdfbd00c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html
@@ -0,0 +1,53 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Exchange'" id="addExchange">
+ <form id="formAddExchange" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Exchange Name*: </strong></td>
+ <td><input type="text" required="true" name="name" id="formAddExchange.name" placeholder="Exchange Name"
+ dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Durable? </strong></td>
+ <td><input type="checkbox" name="durable" id="formAddExchange.durable" value="durable" checked="checked" dojoType="dijit.form.CheckBox" /></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Exchange Type: </strong></td>
+ <td>
+ <select name="type" id="formAddExchange.type" dojoType="dijit.form.FilteringSelect">
+ <option value="direct">direct</option>
+ <option value="topic">topic</option>
+ <option value="headers">headers</option>
+ <option value="fanout">fanout</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+ <br/>
+
+ <!-- submit buttons -->
+ <input type="submit" value="Create Exchange" label="Create Exchange" dojoType="dijit.form.Button" />
+
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html
new file mode 100644
index 0000000000..8154f053cd
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html
@@ -0,0 +1,174 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Queue'" id="addQueue">
+ <form id="formAddQueue" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Queue Name*: </strong></td>
+ <td><input type="text" required="true" name="name" id="formAddQueue.name" placeholder="Queue Name"
+ dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Durable? </strong></td>
+ <td><input type="checkbox" name="durable" id="formAddQueue.durable" value="durable" checked="checked" dojoType="dijit.form.CheckBox" /></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Queue Type: </strong></td>
+ <td>
+ <input type="radio" id="formAddQueueTypeStandard" name="type" value="standard" checked="checked" dojoType="dijit.form.RadioButton" />
+ <label for="formAddQueueTypeStandard">Standard</label>
+ &nbsp;&nbsp;
+ <input type="radio" id="formAddQueueTypePriority" name="type" value="priority" dojoType="dijit.form.RadioButton" />
+ <label for="formAddQueueTypePriority">Priority</label>
+ &nbsp;&nbsp;
+ <input type="radio" id="formAddQueueTypeLVQ" name="type" value="lvq" dojoType="dijit.form.RadioButton" />
+ <label for="formAddQueueTypeLVQ">LVQ</label>
+ &nbsp;&nbsp;
+ <input type="radio" id="formAddQueueTypeSorted" name="type" value="sorted" dojoType="dijit.form.RadioButton" />
+ <label for="formAddQueueTypeSorted">Sorted</label>
+ </td>
+ </tr>
+ </table>
+ <br/>
+
+ <div id="formAddQueueTypePriority:fields" style="display:none"
+ data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Priority Queue Settings'">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Priorities: </strong></td>
+ <td><input data-dojo-type="dijit.form.NumberSpinner" id="formAddQueue.priorities"
+ name="numPriorities" value="3" smallDelta="1" constraints="{min:1,max:10,places:0}"/>
+ </tr>
+ </table>
+ </div>
+
+
+ <div id="formAddQueueTypeLVQ:fields" style="display:none"
+ data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Last Value Queue Settings'">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>LVQ Message Property: </strong></td>
+ <td><input type="text" name="lvqKey" id="formAddQueue.lvqkey"
+ placeholder="qpid.LVQ_key" dojoType="dijit.form.ValidationTextBox" /></td>
+ </tr>
+ </table>
+ </div>
+
+ <div id="formAddQueueTypeSorted:fields" style="display:none"
+ data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Sorted Queue Settings'">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Sort Message Property: </strong></td>
+ <td><input type="text" name="sortKey" id="formAddQueue.sortkey"
+ placeholder="" dojoType="dijit.form.ValidationTextBox" /></td>
+ </tr>
+ </table>
+ </div>
+
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Flow Control Settings', open: false">
+ <table cellpadding="0" cellspacing="2">
+
+ <!-- x-qpid-capacity -->
+ <tr>
+ <td valign="top"><strong>Capacity: </strong></td>
+ <td><input type="text" required="false" name="queueFlowControlSizeBytes" id="formAddQueue.capacity" placeholder="Size in bytes"
+ dojoType="dijit.form.ValidationTextBox"
+ trim="true"
+ regexp="(^[0-9]+(b|K(b)?|M(b)?|G(b)?)?$)"
+ invalidMessage= "Invalid value"/></td>
+ </tr>
+ <!-- x-qpid-flow-resume-capacity -->
+ <tr>
+ <td valign="top"><strong>Resume Capacity: </strong></td>
+ <td><input type="text" required="false" name="queueFlowResumeSizeBytes" id="formAddQueue.flowResumeCapacity" placeholder="Size in bytes"
+ dojoType="dijit.form.ValidationTextBox"
+ trim="true"
+ regexp="(^[0-9]+(b|K(b)?|M(b)?|G(b)?)?$)"
+ invalidMessage= "Invalid value"/></td>
+ </tr>
+ </table>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Settings', open: false">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Maximum Message Age: </strong></td>
+ <td><input type="text" required="false" name="alertThresholdMessageAge" id="formAddQueue.maximumMessageAge" placeholder="Time in ms"
+ dojoType="dijit.form.ValidationTextBox"
+ trim="true"
+ regexp="(^[0-9]+(s(ec(ond(s)?)?)?|m(in(ute)?(s)?)?|h|d|w|M|y)?$)"
+ invalidMessage= "Invalid value" /></td>
+ </tr>
+ <!-- x-qpid-maximum-message-size -->
+ <tr>
+ <td valign="top"><strong>Maximum Message Size: </strong></td>
+ <td><input type="text" required="false" name="alertThresholdMessageSize" id="formAddQueue.maximumMessageSize" placeholder="Size in bytes"
+ dojoType="dijit.form.ValidationTextBox"
+ trim="true"
+ regexp="(^[0-9]+(b|K(b)?|M(b)?|G(b)?)?$)"
+ invalidMessage= "Invalid value" /></td>
+ </tr>
+ <!-- x-qpid-maximum-message-count -->
+ <tr>
+ <td valign="top"><strong>Maximum Number in Queue: </strong></td>
+ <td><input type="text" required="false" name="alertThresholdQueueDepthMessages" id="formAddQueue.maximumMessageCount" placeholder="Count of messages"
+ dojoType="dijit.form.ValidationTextBox"
+ trim="true"
+ regexp="[0-9]+"
+ invalidMessage= "Invalid value"/></td>
+ </tr>
+ <!-- x-qpid-minimum-alert-repeat-gap -->
+ <tr>
+ <td valign="top"><strong>Gap between alerts: </strong></td>
+ <td><input type="text" required="false" name="alertRepeatGap" id="formAddQueue.minimumAlertRepeatGap" placeholder="Time in ms"
+ dojoType="dijit.form.ValidationTextBox"
+ trim="true"
+ regexp="(^[0-9]+(s(ec(ond(s)?)?)?|m(in(ute)?(s)?)?|h|d|w|M|y)?$)"
+ invalidMessage= "Invalid value" /></td>
+ </tr>
+ </table>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Other Settings', open: false">
+ <table cellpadding="0" cellspacing="2">
+
+ <!-- x-qpid-maximum-delivery-count -->
+ <tr>
+ <td valign="top"><strong>Maximum Delivery Retries: </strong></td>
+ <td><input type="text" required="false" name="maximumDeliveryAttempts" id="formAddQueue.maximumDeliveryCount"
+ dojoType="dijit.form.ValidationTextBox"
+ trim="true"
+ regexp="[0-9]+"
+ invalidMessage= "Invalid value"/></td>
+ </tr>
+
+
+ </table>
+ </div>
+ <br/>
+ <!-- submit buttons -->
+ <input type="submit" value="Create Queue" label="Create Queue" dojoType="dijit.form.Button" />
+
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/addUser.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/addUser.html
new file mode 100644
index 0000000000..785605f694
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/addUser.html
@@ -0,0 +1,42 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add User'" id="addUser">
+ <form id="formAddUser" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>User Name*: </strong></td>
+ <td><input type="text" required="true" name="name" id="formAddUser.name" placeholder="User Name"
+ dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Password*</strong></td>
+ <td><input type="password" required="true" name="password" id="formAddUser.password" dojoType="dijit.form.ValidationTextBox"/></td>
+ </tr>
+ </table>
+ <br/>
+
+ <!-- submit buttons -->
+ <input type="submit" value="Create User" label="Create User" dojoType="dijit.form.Button" />
+
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/setPassword.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/setPassword.html
new file mode 100644
index 0000000000..3d67463abd
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/setPassword.html
@@ -0,0 +1,42 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Set Password'" id="setPassword">
+ <form id="formSetPassword" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>User Name: </strong></td>
+ <td><input type="text" required="true" name="name" id="formSetPassword.name" placeholder="User Name"
+ dojoType="dijit.form.TextBox" enabled="false" /></td>
+ </tr>
+ <tr>
+ <td valign="top"><strong>Password*</strong></td>
+ <td><input type="password" required="true" name="password" id="formSetPassword.password" dojoType="dijit.form.ValidationTextBox"/></td>
+ </tr>
+ </table>
+ <br/>
+
+ <!-- submit buttons -->
+ <input type="submit" value="Set Password" label="Set Password" dojoType="dijit.form.Button" />
+
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html
new file mode 100644
index 0000000000..baadc8c35f
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html
@@ -0,0 +1,29 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="PrincipalDatabaseAuthenticationManager">
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Users'">
+ <div class="users"></div>
+ <button data-dojo-type="dijit.form.Button" class="addUserButton">Add User</button>
+ <button data-dojo-type="dijit.form.Button" class="deleteUserButton">Delete Users</button>
+
+ </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
new file mode 100644
index 0000000000..78780edcd9
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css
@@ -0,0 +1,92 @@
+/*
+ *
+ * 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.
+ *
+ */
+* {
+ outline: none !important;
+}
+
+html, body {
+ height: 100%;
+ margin: 0;
+ margin-right: 40px;
+ padding: 0;
+ overflow: hidden;
+ font-family: Lucida Sans,Lucida Grande,Arial !important;
+ font-size: 13px !important;
+ background: white;
+ color: #333;
+}
+
+#pageLayout {
+ height: 100%;
+}
+button {
+ -webkit-transition: background-color 0.2s linear;
+ border-radius:4px;
+ -moz-border-radius: 4px 4px 4px 4px;
+ -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
+ background-color: #E4F2FF;
+ background-image: url("../dojo/dijit/themes/claro/form/images/button.png");
+ background-position: center top;
+ background-repeat: repeat-x;
+ border: 1px solid #769DC0;
+ padding: 2px 8px 4px;
+ font-size:1em;
+}
+
+button:hover {
+ background-color: #AFD9FF;
+ color: #000000;
+}
+
+h1 {
+ font-size:1.5em;
+}
+
+.header {
+ height:100px;
+ background:url("../images/qpid-logo.png") left center no-repeat
+}
+
+.logo {
+ text-align:left;
+ vertical-align: top;
+ font-weight:600;
+ height: 90px;
+ padding-left: 200px;
+ padding-top: 1px;
+ padding-bottom: 10px;
+ font-size:14px;
+ font-family:"Verdana", cursive;
+}
+
+.footer {
+ color:#000000;
+ clear:both;
+ text-align:center;
+ font-size:11px;
+ line-height:17px;
+
+}
+
+div .messages {
+ width: 100%;
+ height: 350px;
+} \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/footer.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/footer.html
new file mode 100644
index 0000000000..fa84825e80
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/footer.html
@@ -0,0 +1,28 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+
+<div class="footer"><p>&#xA9; 2004-<span class="currentYear">2012</span> The Apache Software Foundation.
+ <br/>
+ Apache Qpid, Qpid, Apache, the Apache feather logo, and the Apache Qpid project logo are trademarks of
+ The Apache Software Foundation.
+ <br/>
+ All other marks mentioned may be trademarks or registered trademarks of their respective owners.
+</div> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png
new file mode 100644
index 0000000000..95d49ea469
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js
new file mode 100644
index 0000000000..152504da86
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js
@@ -0,0 +1,213 @@
+/*
+ *
+ * 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.
+ *
+ */
+require(["dijit/form/DropDownButton", "dijit/TooltipDialog", "dijit/form/TextBox",
+ "dojo/_base/xhr", "dojox/encoding/base64", "dojox/encoding/digests/_base", "dojox/encoding/digests/MD5"]);
+var button;
+var usernameSpan;
+
+var encodeUTF8 = function encodeUTF8(str) {
+ var byteArray = [];
+ for (var i = 0; i < str.length; i++) {
+ if (str.charCodeAt(i) <= 0x7F) {
+ byteArray.push(str.charCodeAt(i));
+ }
+ else {
+ var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
+ for (var j = 0; j < h.length; j++)
+ byteArray.push(parseInt(h[j], 16));
+ }
+ }
+ return byteArray;
+};
+
+var decodeUTF8 = function decodeUTF8(byteArray)
+{
+ var str = '';
+ for (var i = 0; i < byteArray.length; i++)
+ str += byteArray[i] <= 0x7F?
+ byteArray[i] === 0x25 ? "%25" :
+ String.fromCharCode(byteArray[i]) :
+ "%" + byteArray[i].toString(16).toUpperCase();
+ return decodeURIComponent(str);
+};
+
+
+var saslPlain = function saslPlain(user, password)
+{
+ var responseArray = [ 0 ].concat(encodeUTF8( user )).concat( [ 0 ] ).concat( encodeUTF8( password ) );
+ var plainResponse = dojox.encoding.base64.encode(responseArray);
+
+ // Using dojo.xhrGet, as very little information is being sent
+ dojo.xhrPost({
+ // The URL of the request
+ url: "rest/sasl",
+ content: {
+ mechanism: "PLAIN",
+ response: plainResponse
+ },
+ handleAs: "json",
+ failOk: true
+ }).then(function()
+ {
+ updateAuthentication();
+ },
+ function(error)
+ {
+ if(error.status == 401)
+ {
+ alert("Authentication Failed");
+ }
+ else
+ {
+ alert(error);
+ }
+ updateAuthentication();
+ });
+};
+
+var saslCramMD5 = function saslCramMD5(user, password)
+{
+
+ // Using dojo.xhrGet, as very little information is being sent
+ dojo.xhrPost({
+ // The URL of the request
+ url: "rest/sasl",
+ content: {
+ mechanism: "CRAM-MD5"
+ },
+ handleAs: "json",
+ failOk: true
+ }).then(function(data)
+ {
+
+ var challengeBytes = dojox.encoding.base64.decode(data.challenge);
+ var wa=[];
+ var bitLength = challengeBytes.length*8;
+ for(var i=0; i<bitLength; i+=8)
+ {
+ wa[i>>5] |= (challengeBytes[i/8] & 0xFF)<<(i%32);
+ }
+ var challengeStr = dojox.encoding.digests.wordToString(wa).substring(0,challengeBytes.length);
+
+ var digest = user + " " + dojox.encoding.digests.MD5._hmac(challengeStr, password, dojox.encoding.digests.outputTypes.Hex);
+ var id = data.id;
+
+ var response = dojox.encoding.base64.encode(encodeUTF8( digest ));
+
+ dojo.xhrPost({
+ // The URL of the request
+ url: "rest/sasl",
+ content: {
+ id: id,
+ response: response
+ },
+ handleAs: "json",
+ failOk: true
+ }).then(function()
+ {
+ updateAuthentication();
+ },
+ function(error)
+ {
+ if(error.status == 401)
+ {
+ alert("Authentication Failed");
+ }
+ else
+ {
+ alert(error);
+ }
+ updateAuthentication();
+ });
+
+ },
+ function(error)
+ {
+ if(error.status == 401)
+ {
+ alert("Authentication Failed");
+ }
+ else
+ {
+ alert(error);
+ }
+ });
+};
+
+var doAuthenticate = function doAuthenticate()
+{
+ saslCramMD5(dojo.byId("username").value, dojo.byId("pass").value);
+ updateAuthentication();
+};
+
+
+var updateAuthentication = function updateAuthentication()
+{
+ dojo.xhrGet({
+ // The URL of the request
+ url: "rest/sasl",
+ handleAs: "json"
+ }).then(function(data)
+ {
+ if(data.user)
+ {
+ dojo.byId("authenticatedUser").innerHTML = data.user;
+ dojo.style(button.domNode, {visibility: 'hidden'});
+ dojo.style(usernameSpan, {visibility: 'visible'});
+ }
+ else
+ {
+ dojo.style(button.domNode, {visibility: 'visible'});
+ dojo.style(usernameSpan, {visibility: 'hidden'});
+ }
+ }
+ );
+};
+
+require(["dijit/form/DropDownButton", "dijit/TooltipDialog", "dijit/form/TextBox", "dojo/_base/xhr", "dojo/dom", "dojo/dom-construct", "dojo/domReady!"],
+ function(DropDownButton, TooltipDialog, TextBox, xhr, dom, domConstruct){
+ var dialog = new TooltipDialog({
+ content:
+ '<strong><label for="username" style="display:inline-block;width:100px;">Username:</label></strong>' +
+ '<div data-dojo-type="dijit.form.TextBox" id="username"></div><br/>' +
+ '<strong><label for="pass" style="display:inline-block;width:100px;">Password:</label></strong>' +
+ '<div data-dojo-type="dijit.form.TextBox" type="password" id="pass"></div><br/>' +
+ '<button data-dojo-type="dijit.form.Button" data-dojo-props="onClick:doAuthenticate" type="submit">Login</button>'
+ });
+
+ button = new DropDownButton({
+ label: "Login",
+ dropDown: dialog
+ });
+
+ usernameSpan = domConstruct.create("span", { innerHTML: '<strong>User: </strong><span id="authenticatedUser"></span>',
+ style: { visibility: "hidden" }});
+
+
+ var loginDiv = dom.byId("login");
+ loginDiv.appendChild(button.domNode);
+ loginDiv.appendChild(usernameSpan);
+
+
+
+
+ updateAuthentication();
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js
new file mode 100644
index 0000000000..f7ede1a7f7
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js
@@ -0,0 +1,110 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/store/Memory",
+ "dojox/grid/DataGrid",
+ "dojo/data/ObjectStore",
+ "dojo/store/Observable"], function (Memory, DataGrid, ObjectStore, Observable) {
+
+ function UpdatableStore( data, divName, structure, func, props, Grid ) {
+
+ var that = this;
+ var GridType = DataGrid;
+
+ that.store = Observable(Memory({data: data, idProperty: "id"}));
+ that.dataStore = ObjectStore({objectStore: that.store});
+
+ var gridProperties = { store: that.dataStore,
+ structure: structure,
+ autoHeight: true
+ };
+ if(props) {
+ for(var prop in props) {
+ if(props.hasOwnProperty(prop))
+ {
+ gridProperties[ prop ] = props[ prop ];
+ }
+ }
+ }
+
+ if(Grid)
+ {
+ GridType = Grid;
+ }
+
+ that.grid = new GridType(gridProperties, divName);
+
+ // since we created this grid programmatically, call startup to render it
+ that.grid.startup();
+
+ if( func )
+ {
+ func(that);
+ }
+
+ }
+
+ UpdatableStore.prototype.update = function(data)
+ {
+
+ var store = this.store;
+ var theItem;
+
+ // handle deletes
+ // iterate over existing store... if not in new data then remove
+ store.query({ }).forEach(function(object) {
+ if(data) {
+ for(var i=0; i < data.length; i++) {
+ if(data[i].id == object.id) {
+ return;
+ }
+ }
+ }
+ store.remove(object.id);
+
+ });
+
+ // iterate over data...
+ if(data) {
+ for(var i=0; i < data.length; i++) {
+ if(theItem = store.get(data[i].id)) {
+ var modified;
+ for(var propName in data[i]) {
+ if(data[i].hasOwnProperty(propName)) {
+ if(theItem[ propName ] != data[i][ propName ]) {
+ theItem[ propName ] = data[i][ propName ];
+ modified = true;
+ }
+ }
+ }
+ if(modified) {
+ // ... check attributes for updates
+ store.notify(theItem, data[i].id);
+ }
+ } else {
+ // ,,, if not in the store then add
+ store.put(data[i]);
+ }
+ }
+ }
+
+ };
+ return UpdatableStore;
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/footer.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/footer.js
new file mode 100644
index 0000000000..ea13b1fc53
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/footer.js
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr", "dojo/query", "dojo/domReady!"], function (xhr, query) {
+ query('div[qpid-type="footer"]').forEach(function(node, index, arr) {
+ xhr.get({url: "footer.html",
+ sync: true,
+ load: function(data) {
+ node.innerHTML = data;
+ } });
+ });
+});
+
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/formatter.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/formatter.js
new file mode 100644
index 0000000000..2f8683ee1c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/formatter.js
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+define(function () {
+ return {
+
+ formatBytes: function formatBytes(amount)
+ {
+ var returnVal = { units: "B",
+ value: "0"};
+
+
+ if(amount < 1000)
+ {
+ returnVal.value = amount.toPrecision(3);;
+ }
+ else if(amount < 1000 * 1024)
+ {
+ returnVal.units = "KB";
+ returnVal.value = (amount / 1024).toPrecision(3);
+ }
+ else if(amount < 1000 * 1024 * 1024)
+ {
+ returnVal.units = "MB";
+ returnVal.value = (amount / (1024 * 1024)).toPrecision(3);
+ }
+ else if(amount < 1000 * 1024 * 1024 * 1024)
+ {
+ returnVal.units = "GB";
+ returnVal.value = (amount / (1024 * 1024 * 1024)).toPrecision(3);
+ }
+
+ return returnVal;
+
+ },
+
+ formatTime: function formatTime(amount)
+ {
+ var returnVal = { units: "ms",
+ value: "0"};
+
+ if(amount < 1000)
+ {
+ returnVal.units = "ms";
+ returnVal.value = amount.toString();
+ }
+ else if(amount < 1000 * 60)
+ {
+ returnVal.units = "s";
+ returnVal.value = (amount / 1000).toPrecision(3);
+ }
+ else if(amount < 1000 * 60 * 60)
+ {
+ returnVal.units = "min";
+ returnVal.value = (amount / (1000 * 60)).toPrecision(3);
+ }
+ else if(amount < 1000 * 60 * 60 * 24)
+ {
+ returnVal.units = "hr";
+ returnVal.value = (amount / (1000 * 60 * 60)).toPrecision(3);
+ }
+ else if(amount < 1000 * 60 * 60 * 24 * 7)
+ {
+ returnVal.units = "d";
+ returnVal.value = (amount / (1000 * 60 * 60 * 24)).toPrecision(3);
+ }
+ else if(amount < 1000 * 60 * 60 * 24 * 365)
+ {
+ returnVal.units = "wk";
+ returnVal.value = (amount / (1000 * 60 * 60 * 24 * 7)).toPrecision(3);
+ }
+ else
+ {
+ returnVal.units = "yr";
+ returnVal.value = (amount / (1000 * 60 * 60 * 24 * 365)).toPrecision(3);
+ }
+
+ return returnVal;
+ }
+ };
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/properties.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/properties.js
new file mode 100644
index 0000000000..8d85345b74
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/properties.js
@@ -0,0 +1,26 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/has", "dojo/_base/sniff", "dojo/domReady!"],
+ function (has) {
+ var properties = {};
+ properties.useSyncGet = (has("ie") <= 8);
+ return properties;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/updater.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/updater.js
new file mode 100644
index 0000000000..86bbaa46ba
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/updater.js
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(function () {
+ var updateList = new Array();
+
+ setInterval(function() {
+ for(var i = 0; i < updateList.length; i++) {
+ var obj = updateList[i];
+ obj.update();
+ }
+ }, 5000); // TODO: Should make this configurable
+
+ return {
+ add: function(obj) {
+ updateList.push(obj);
+ },
+
+ remove: function(obj) {
+ for(var i = 0; i < updateList.length; i++) {
+ if(updateList[i] === obj) {
+ updateList.splice(i,1);
+ return;
+ }
+ }
+ }
+ };
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
new file mode 100644
index 0000000000..d7917b640e
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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.
+ *
+ */
+define([],
+ function () {
+ var util = {};
+ if (Array.isArray) {
+ util.isArray = function (object) {
+ return Array.isArray(object);
+ };
+ } else {
+ util.isArray = function (object) {
+ return object instanceof Array;
+ };
+ }
+
+ util.flattenStatistics = function (data) {
+ var attrName, stats, propName, theList;
+ for(attrName in data) {
+ if(data.hasOwnProperty(attrName)) {
+ if(attrName == "statistics") {
+ stats = data.statistics;
+ for(propName in stats) {
+ if(stats.hasOwnProperty( propName )) {
+ data[ propName ] = stats[ propName ];
+ }
+ }
+ } else if(data[ attrName ] instanceof Array) {
+ theList = data[ attrName ];
+
+ for(var i=0; i < theList.length; i++) {
+ util.flattenStatistics( theList[i] );
+ }
+ }
+ }
+ }
+ };
+ return util;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js
new file mode 100644
index 0000000000..7613fd5d71
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/UpdatableStore",
+ "dojox/grid/EnhancedGrid",
+ "dojox/grid/enhanced/plugins/Pagination",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid) {
+
+ function AuthenticationProvider(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "authenticationprovider", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+ AuthenticationProvider.prototype.getTitle = function() {
+ return "AuthenticationProvider";
+ };
+
+ AuthenticationProvider.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showAuthProvider.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.authProviderAdapter = new AuthProviderUpdater(contentPane.containerNode, that.modelObj, that.controller);
+
+ updater.add( that.authProviderAdapter );
+
+ that.authProviderAdapter.update();
+
+ }});
+ };
+
+ AuthenticationProvider.prototype.close = function() {
+ updater.remove( this.authProviderAdapter );
+ };
+
+ function AuthProviderUpdater(node, authProviderObj, controller)
+ {
+ this.controller = controller;
+ this.name = query(".name", node)[0];
+ /*this.state = dom.byId("state");
+ this.durable = dom.byId("durable");
+ this.lifetimePolicy = dom.byId("lifetimePolicy");
+ */
+ this.query = "rest/authenticationprovider/"+encodeURIComponent(authProviderObj.name);
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data)
+ {
+ that.authProviderData = data[0];
+
+ util.flattenStatistics( that.authProviderData );
+
+ that.updateHeader();
+
+ require(["qpid/management/authenticationprovider/"+that.authProviderData.type],
+ function(SpecificProvider) {
+ that.details = new SpecificProvider(node, authProviderObj, controller);
+ that.details.update();
+ });
+
+ });
+
+ }
+
+ AuthProviderUpdater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.authProviderData[ "name" ];
+ /* this.state.innerHTML = this.brokerData[ "state" ];
+ this.durable.innerHTML = this.brokerData[ "durable" ];
+ this.lifetimePolicy.innerHTML = this.brokerData[ "lifetimePolicy" ];
+*/
+ };
+
+ AuthProviderUpdater.prototype.update = function()
+ {
+
+ var that = this;
+
+
+ };
+
+
+
+ return AuthenticationProvider;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
new file mode 100644
index 0000000000..dcf6711073
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
@@ -0,0 +1,205 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/UpdatableStore",
+ "dojox/grid/EnhancedGrid",
+ "dojox/grid/enhanced/plugins/Pagination",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid) {
+
+ function Broker(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "broker", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+ Broker.prototype.getTitle = function()
+ {
+ return "Broker";
+ };
+
+ Broker.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showBroker.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.brokerUpdater = new BrokerUpdater(contentPane.containerNode, that.modelObj, that.controller);
+
+ updater.add( that.brokerUpdater );
+
+ that.brokerUpdater.update();
+
+ }});
+ };
+
+ Broker.prototype.close = function() {
+ updater.remove( this.brokerUpdater );
+ };
+
+ function BrokerUpdater(node, brokerObj, controller)
+ {
+ this.controller = controller;
+ this.name = query(".broker-name", node)[0];
+ /*this.state = dom.byId("state");
+ this.durable = dom.byId("durable");
+ this.lifetimePolicy = dom.byId("lifetimePolicy");
+ */
+ this.query = "rest/broker";
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data)
+ {
+ that.brokerData= data[0];
+
+ util.flattenStatistics( that.brokerData);
+
+ that.updateHeader();
+ that.vhostsGrid =
+ new UpdatableStore(that.brokerData.vhosts, query(".broker-virtualhosts")[0],
+ [ { name: "Virtual Host", field: "name", width: "120px"},
+ { name: "Connections", field: "connectionCount", width: "80px"},
+ { name: "Queues", field: "queueCount", width: "80px"},
+ { name: "Exchanges", field: "exchangeCount", width: "100%"}
+ ], function(obj) {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var name = obj.dataStore.getValue(theItem,"name");
+ that.controller.show("virtualhost", name, brokerObj);
+ });
+ });
+
+ that.portsGrid =
+ new UpdatableStore(that.brokerData.ports, query(".broker-ports")[0],
+ [ { name: "Address", field: "bindingAddress", width: "70px"},
+ { name: "Port", field: "port", width: "70px"},
+ { name: "Transports", field: "transports", width: "150px"},
+ { name: "Protocols", field: "protocols", width: "100%"}
+ ], function(obj) {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var name = obj.dataStore.getValue(theItem,"name");
+ that.controller.show("port", name, brokerObj);
+ });
+ });
+
+ });
+
+ xhr.get({url: "rest/logrecords", sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data)
+ {
+ that.logData = data;
+
+ var gridProperties = {
+ height: 400,
+ plugins: {
+ pagination: {
+ pageSizes: ["10", "25", "50", "100"],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ }
+ }};
+
+
+ that.logfileGrid =
+ new UpdatableStore(that.logData, query(".broker-logfile")[0],
+ [ { name: "Timestamp", field: "timestamp", width: "200px",
+ formatter: function(val) {
+ var d = new Date(0);
+ d.setUTCSeconds(val/1000);
+
+ return d.toLocaleString();
+ }},
+ { name: "Level", field: "level", width: "60px"},
+ { name: "Logger", field: "logger", width: "280px"},
+ { name: "Thread", field: "thread", width: "120px"},
+ { name: "Log Message", field: "message", width: "100%"}
+
+ ], null, gridProperties, EnhancedGrid);
+ });
+ }
+
+ BrokerUpdater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.brokerData[ "name" ];
+ /* this.state.innerHTML = this.brokerData[ "state" ];
+ this.durable.innerHTML = this.brokerData[ "durable" ];
+ this.lifetimePolicy.innerHTML = this.brokerData[ "lifetimePolicy" ];
+*/
+ };
+
+ BrokerUpdater.prototype.update = function()
+ {
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.brokerData = data[0];
+ util.flattenStatistics( that.brokerData );
+
+ that.updateHeader();
+
+ that.vhostsGrid.update(that.brokerData.virtualhosts);
+
+ that.portsGrid.update(that.brokerData.ports);
+
+
+ });
+
+
+ xhr.get({url: "rest/logrecords", sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data)
+ {
+ that.logData = data;
+ that.logfileGrid.update(that.logData);
+ });
+
+ };
+
+
+
+ return Broker;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js
new file mode 100644
index 0000000000..01f9a325c5
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js
@@ -0,0 +1,213 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/formatter",
+ "qpid/common/UpdatableStore",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, properties, updater, util, formatter, UpdatableStore) {
+
+ function Connection(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "exchange", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+ Connection.prototype.getTitle = function()
+ {
+ return "Connection: " + this.name;
+ };
+
+ Connection.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showConnection.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.connectionUpdater = new ConnectionUpdater(contentPane.containerNode, that.modelObj, that.controller);
+
+ updater.add( that.connectionUpdater );
+
+ that.connectionUpdater.update();
+
+ }});
+ };
+
+ Connection.prototype.close = function() {
+ updater.remove( this.connectionUpdater );
+ };
+
+ function ConnectionUpdater(containerNode, connectionObj, controller)
+ {
+ var that = this;
+
+ function findNode(name) {
+ return query("." + name, containerNode)[0];
+ }
+
+ function storeNodes(names)
+ {
+ for(var i = 0; i < names.length; i++) {
+ that[names[i]] = findNode(names[i]);
+ }
+ }
+
+ storeNodes(["name",
+ "state",
+ "durable",
+ "lifetimePolicy",
+ "msgInRate",
+ "bytesInRate",
+ "bytesInRateUnits",
+ "msgOutRate",
+ "bytesOutRate",
+ "bytesOutRateUnits"]);
+
+
+
+ this.query = "rest/connection/"+ encodeURIComponent(connectionObj.parent.virtualhost.name) + "/" + encodeURIComponent(connectionObj.name);
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.connectionData = data[0];
+
+ util.flattenStatistics( that.connectionData );
+
+ that.updateHeader();
+ that.sessionsGrid = new UpdatableStore(that.connectionData.sessions, findNode("sessions"),
+ [ { name: "Name", field: "name", width: "70px"},
+ { name: "Mode", field: "distributionMode", width: "70px"},
+ { name: "Msgs Rate", field: "msgRate",
+ width: "150px"},
+ { name: "Bytes Rate", field: "bytesRate",
+ width: "100%"}
+ ]);
+
+
+ });
+
+ }
+
+ ConnectionUpdater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.connectionData[ "name" ];
+ this.state.innerHTML = this.connectionData[ "state" ];
+ this.durable.innerHTML = this.connectionData[ "durable" ];
+ this.lifetimePolicy.innerHTML = this.connectionData[ "lifetimePolicy" ];
+
+ };
+
+ ConnectionUpdater.prototype.update = function()
+ {
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.connectionData = data[0];
+
+ util.flattenStatistics( that.connectionData );
+
+ var sessions = that.connectionData[ "sessions" ];
+
+ that.updateHeader();
+
+ var sampleTime = new Date();
+ var messageIn = that.connectionData["messagesIn"];
+ var bytesIn = that.connectionData["bytesIn"];
+ var messageOut = that.connectionData["messagesOut"];
+ var bytesOut = that.connectionData["bytesOut"];
+
+ if(that.sampleTime)
+ {
+ var samplePeriod = sampleTime.getTime() - that.sampleTime.getTime();
+
+ var msgInRate = (1000 * (messageIn - that.messageIn)) / samplePeriod;
+ var msgOutRate = (1000 * (messageOut - that.messageOut)) / samplePeriod;
+ var bytesInRate = (1000 * (bytesIn - that.bytesIn)) / samplePeriod;
+ var bytesOutRate = (1000 * (bytesOut - that.bytesOut)) / samplePeriod;
+
+ that.msgInRate.innerHTML = msgInRate.toFixed(0);
+ var bytesInFormat = formatter.formatBytes( bytesInRate );
+ that.bytesInRate.innerHTML = "(" + bytesInFormat.value;
+ that.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)";
+
+ that.msgOutRate.innerHTML = msgOutRate.toFixed(0);
+ var bytesOutFormat = formatter.formatBytes( bytesOutRate );
+ that.bytesOutRate.innerHTML = "(" + bytesOutFormat.value;
+ that.bytesOutRateUnits.innerHTML = bytesOutFormat.units + "/s)";
+
+ if(sessions && that.sessions)
+ {
+ for(var i=0; i < sessions.length; i++)
+ {
+ var session = sessions[i];
+ for(var j = 0; j < that.sessions.length; j++)
+ {
+ var oldSession = that.sessions[j];
+ if(oldSession.id == session.id)
+ {
+ var msgRate = (1000 * (session.messagesOut - oldSession.messagesOut)) /
+ samplePeriod;
+ session.msgRate = msgRate.toFixed(0) + "msg/s";
+
+ var bytesRate = (1000 * (session.bytesOut - oldSession.bytesOut)) /
+ samplePeriod;
+ var bytesRateFormat = formatter.formatBytes( bytesRate );
+ session.bytesRate = bytesRateFormat.value + bytesRateFormat.units + "/s";
+ }
+
+
+ }
+
+ }
+ }
+
+ }
+
+ that.sampleTime = sampleTime;
+ that.messageIn = messageIn;
+ that.bytesIn = bytesIn;
+ that.messageOut = messageOut;
+ that.bytesOut = bytesOut;
+ that.sessions = sessions;
+
+
+ // update sessions
+ that.sessionsGrid.update(that.connectionData.sessions)
+ });
+ };
+
+
+ return Connection;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js
new file mode 100644
index 0000000000..0450ef53ac
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js
@@ -0,0 +1,229 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "dijit/registry",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/formatter",
+ "qpid/common/UpdatableStore",
+ "qpid/management/addBinding",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, registry, properties, updater, util, formatter, UpdatableStore, addBinding) {
+
+ function Exchange(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "exchange", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+
+ Exchange.prototype.getExchangeName = function()
+ {
+ return this.name;
+ };
+
+
+ Exchange.prototype.getVirtualHostName = function()
+ {
+ return this.modelObj.parent.virtualhost.name;
+ };
+
+ Exchange.prototype.getTitle = function()
+ {
+ return "Exchange: " + this.name;
+ };
+
+ Exchange.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showExchange.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.exchangeUpdater = new ExchangeUpdater(contentPane.containerNode, that.modelObj, that.controller);
+
+ updater.add( that.exchangeUpdater );
+
+ that.exchangeUpdater.update();
+
+
+ var addBindingButton = query(".addBindingButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addBindingButton), "onClick",
+ function(evt){
+ addBinding.show({ virtualhost: that.getVirtualHostName(),
+ exchange: that.getExchangeName()});
+ });
+
+ }});
+ };
+
+ Exchange.prototype.close = function() {
+ updater.remove( this.exchangeUpdater );
+ };
+
+ function ExchangeUpdater(containerNode, exchangeObj, controller)
+ {
+ var that = this;
+
+ function findNode(name) {
+ return query("." + name, containerNode)[0];
+ }
+
+ function storeNodes(names)
+ {
+ for(var i = 0; i < names.length; i++) {
+ that[names[i]] = findNode(names[i]);
+ }
+ }
+
+ storeNodes(["name",
+ "state",
+ "durable",
+ "lifetimePolicy",
+ "alertRepeatGap",
+ "alertRepeatGapUnits",
+ "alertThresholdMessageAge",
+ "alertThresholdMessageAgeUnits",
+ "alertThresholdMessageSize",
+ "alertThresholdMessageSizeUnits",
+ "alertThresholdQueueDepthBytes",
+ "alertThresholdQueueDepthBytesUnits",
+ "alertThresholdQueueDepthMessages",
+ "msgInRate",
+ "bytesInRate",
+ "bytesInRateUnits",
+ "msgDropRate",
+ "bytesDropRate",
+ "bytesDropRateUnits"]);
+
+
+
+ this.query = "rest/exchange/"+ encodeURIComponent(exchangeObj.parent.virtualhost.name) + "/" + encodeURIComponent(exchangeObj.name);
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.exchangeData = data[0];
+ util.flattenStatistics( that.exchangeData );
+
+ that.updateHeader();
+ that.bindingsGrid = new UpdatableStore(that.exchangeData.bindings, findNode("bindings"),
+ [ { name: "Queue", field: "queue", width: "90px"},
+ { name: "Binding Key", field: "name", width: "120px"},
+ { name: "Arguments", field: "argumentString", width: "100%"}
+ ]);
+
+ });
+
+ }
+
+ ExchangeUpdater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.exchangeData[ "name" ];
+ this.state.innerHTML = this.exchangeData[ "state" ];
+ this.durable.innerHTML = this.exchangeData[ "durable" ];
+ this.lifetimePolicy.innerHTML = this.exchangeData[ "lifetimePolicy" ];
+
+ };
+
+ ExchangeUpdater.prototype.update = function()
+ {
+
+ var thisObj = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ thisObj.exchangeData = data[0];
+
+ util.flattenStatistics( thisObj.exchangeData );
+
+ var bindings = thisObj.exchangeData[ "bindings" ];
+
+ if(bindings)
+ {
+ for(var i=0; i < bindings.length; i++)
+ {
+ if(bindings[i].arguments)
+ {
+ bindings[i].argumentString = dojo.toJson(bindings[i].arguments);
+ }
+ else
+ {
+ bindings[i].argumentString = "";
+ }
+ }
+ }
+
+
+ var sampleTime = new Date();
+
+ thisObj.updateHeader();
+
+ var messageIn = thisObj.exchangeData["messagesIn"];
+ var bytesIn = thisObj.exchangeData["bytesIn"];
+ var messageDrop = thisObj.exchangeData["messagesDropped"];
+ var bytesDrop = thisObj.exchangeData["bytesDropped"];
+
+ if(thisObj.sampleTime)
+ {
+ var samplePeriod = sampleTime.getTime() - thisObj.sampleTime.getTime();
+
+ var msgInRate = (1000 * (messageIn - thisObj.messageIn)) / samplePeriod;
+ var msgDropRate = (1000 * (messageDrop - thisObj.messageDrop)) / samplePeriod;
+ var bytesInRate = (1000 * (bytesIn - thisObj.bytesIn)) / samplePeriod;
+ var bytesDropRate = (1000 * (bytesDrop - thisObj.bytesDrop)) / samplePeriod;
+
+ thisObj.msgInRate.innerHTML = msgInRate.toFixed(0);
+ var bytesInFormat = formatter.formatBytes( bytesInRate );
+ thisObj.bytesInRate.innerHTML = "(" + bytesInFormat.value;
+ thisObj.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)";
+
+ thisObj.msgDropRate.innerHTML = msgDropRate.toFixed(0);
+ var bytesDropFormat = formatter.formatBytes( bytesDropRate );
+ thisObj.bytesDropRate.innerHTML = "(" + bytesDropFormat.value;
+ thisObj.bytesDropRateUnits.innerHTML = bytesDropFormat.units + "/s)"
+
+ }
+
+ thisObj.sampleTime = sampleTime;
+ thisObj.messageIn = messageIn;
+ thisObj.bytesIn = bytesIn;
+ thisObj.messageDrop = messageDrop;
+ thisObj.bytesDrop = bytesDrop;
+
+ // update bindings
+ thisObj.bindingsGrid.update(thisObj.exchangeData.bindings)
+
+ });
+ };
+
+
+ return Exchange;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js
new file mode 100644
index 0000000000..1eb0bfdd79
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js
@@ -0,0 +1,438 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dijit/registry",
+ "dojo/_base/connect",
+ "dojo/_base/event",
+ "dojo/json",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/formatter",
+ "qpid/common/UpdatableStore",
+ "qpid/management/addBinding",
+ "qpid/management/moveCopyMessages",
+ "qpid/management/showMessage",
+ "dojo/store/JsonRest",
+ "dojox/grid/EnhancedGrid",
+ "dojo/data/ObjectStore",
+ "dojox/grid/enhanced/plugins/Pagination",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojo/domReady!"],
+ function (xhr, parser, query, registry, connect, event, json, properties, updater, util, formatter,
+ UpdatableStore, addBinding, moveMessages, showMessage, JsonRest, EnhancedGrid, ObjectStore) {
+
+ function Queue(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "queue", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+ Queue.prototype.getQueueName = function()
+ {
+ return this.name;
+ };
+
+
+ Queue.prototype.getVirtualHostName = function()
+ {
+ return this.modelObj.parent.virtualhost.name;
+ };
+
+ Queue.prototype.getTitle = function()
+ {
+ return "Queue: " + this.name;
+ };
+
+ Queue.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showQueue.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.queueUpdater = new QueueUpdater(contentPane.containerNode, that, that.controller);
+
+ updater.add( that.queueUpdater );
+
+ that.queueUpdater.update();
+
+ var myStore = new JsonRest({target:"rest/message/"+ encodeURIComponent(that.getVirtualHostName()) +
+ "/" + encodeURIComponent(that.getQueueName())});
+ var messageGridDiv = query(".messages",contentPane.containerNode)[0];
+ that.dataStore = new ObjectStore({objectStore: myStore});
+ that.grid = new EnhancedGrid({
+ store: that.dataStore,
+ autoHeight: 10,
+ keepSelection: true,
+ structure: [
+ {name:"Size", field:"size", width: "60px"},
+ {name:"State", field:"state", width: "120px"},
+
+ {name:"Arrival", field:"arrivalTime", width: "100%",
+ formatter: function(val) {
+ var d = new Date(0);
+ d.setUTCSeconds(val/1000);
+
+ return d.toLocaleString();
+ } }
+ ],
+ plugins: {
+ pagination: {
+ pageSizes: ["10", "25", "50", "100"],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ indirectSelection: true
+ }
+ }, messageGridDiv);
+
+ connect.connect(that.grid, "onRowDblClick", that.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var id = that.dataStore.getValue(theItem,"id");
+ showMessage.show({ messageNumber: id,
+ queue: that.getQueueName(),
+ virtualhost: that.getVirtualHostName() });
+ });
+
+ var deleteMessagesButton = query(".deleteMessagesButton", contentPane.containerNode)[0];
+ var deleteWidget = registry.byNode(deleteMessagesButton);
+ connect.connect(deleteWidget, "onClick",
+ function(evt){
+ event.stop(evt);
+ that.deleteMessages();
+ });
+ var moveMessagesButton = query(".moveMessagesButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(moveMessagesButton), "onClick",
+ function(evt){
+ event.stop(evt);
+ that.moveOrCopyMessages({move: true});
+ });
+
+
+ var copyMessagesButton = query(".copyMessagesButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(copyMessagesButton), "onClick",
+ function(evt){
+ event.stop(evt);
+ that.moveOrCopyMessages({move: false});
+ });
+
+ var addBindingButton = query(".addBindingButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addBindingButton), "onClick",
+ function(evt){
+ event.stop(evt);
+ addBinding.show({ virtualhost: that.getVirtualHostName(),
+ queue: that.getQueueName()});
+ });
+
+ }});
+
+
+
+ };
+
+ Queue.prototype.deleteMessages = function() {
+ var data = this.grid.selection.getSelected();
+ if(data.length) {
+ var that = this;
+ if(confirm("Delete " + data.length + " messages?")) {
+ var i, queryParam;
+ for(i = 0; i<data.length; i++) {
+ if(queryParam) {
+ queryParam += "&";
+ } else {
+ queryParam = "?";
+ }
+
+ queryParam += "id=" + data[i].id;
+ }
+ var query = "rest/message/"+ encodeURIComponent(that.getVirtualHostName())
+ + "/" + encodeURIComponent(that.getQueueName()) + queryParam;
+ that.success = true
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ that.grid.setQuery({id: "*"});
+ that.grid.selection.deselectAll();
+ that.queueUpdater.update();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!that.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+ }
+ };
+
+ Queue.prototype.moveOrCopyMessages = function(obj) {
+ var that = this;
+ var move = obj.move;
+ var data = this.grid.selection.getSelected();
+ if(data.length) {
+ var that = this;
+ var i, putData = { messages:[] };
+ if(move) {
+ putData.move = true;
+ }
+ for(i = 0; i<data.length; i++) {
+ putData.messages.push(data[i].id);
+ }
+ moveMessages.show({ virtualhost: this.getVirtualHostName(),
+ queue: this.getQueueName(),
+ data: putData}, function() {
+ if(move)
+ {
+ that.grid.setQuery({id: "*"});
+ that.grid.selection.deselectAll();
+ }
+ });
+
+ }
+
+
+
+ };
+
+ Queue.prototype.startup = function() {
+ this.grid.startup();
+ };
+
+ Queue.prototype.close = function() {
+ updater.remove( this.queueUpdater );
+ };
+
+ function QueueUpdater(containerNode, queueObj, controller)
+ {
+ var that = this;
+
+ function findNode(name) {
+ return query("." + name, containerNode)[0];
+ }
+
+ function storeNodes(names)
+ {
+ for(var i = 0; i < names.length; i++) {
+ that[names[i]] = findNode(names[i]);
+ }
+ }
+
+ storeNodes(["name",
+ "state",
+ "durable",
+ "lifetimePolicy",
+ "alertRepeatGap",
+ "alertRepeatGapUnits",
+ "alertThresholdMessageAge",
+ "alertThresholdMessageAgeUnits",
+ "alertThresholdMessageSize",
+ "alertThresholdMessageSizeUnits",
+ "alertThresholdQueueDepthBytes",
+ "alertThresholdQueueDepthBytesUnits",
+ "alertThresholdQueueDepthMessages",
+ "queueDepthMessages",
+ "queueDepthBytes",
+ "queueDepthBytesUnits",
+ "unacknowledgedMessages",
+ "unacknowledgedBytes",
+ "unacknowledgedBytesUnits",
+ "msgInRate",
+ "bytesInRate",
+ "bytesInRateUnits",
+ "msgOutRate",
+ "bytesOutRate",
+ "bytesOutRateUnits"]);
+
+
+
+ this.query = "rest/queue/"+ encodeURIComponent(queueObj.getVirtualHostName()) + "/" + encodeURIComponent(queueObj.getQueueName());
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.queueData = data[0];
+
+ util.flattenStatistics( that.queueData );
+
+ that.updateHeader();
+ that.bindingsGrid = new UpdatableStore(that.queueData.bindings, findNode("bindings"),
+ [ { name: "Exchange", field: "exchange", width: "90px"},
+ { name: "Binding Key", field: "name", width: "120px"},
+ { name: "Arguments", field: "argumentString", width: "100%"}
+ ]);
+
+ that.consumersGrid = new UpdatableStore(that.queueData.consumers, findNode("consumers"),
+ [ { name: "Name", field: "name", width: "70px"},
+ { name: "Mode", field: "distributionMode", width: "70px"},
+ { name: "Msgs Rate", field: "msgRate",
+ width: "150px"},
+ { name: "Bytes Rate", field: "bytesRate",
+ width: "100%"}
+ ]);
+
+
+
+
+ });
+
+ }
+
+ QueueUpdater.prototype.updateHeader = function()
+ {
+
+ var bytesDepth;
+ this.name.innerHTML = this.queueData[ "name" ];
+ this.state.innerHTML = this.queueData[ "state" ];
+ this.durable.innerHTML = this.queueData[ "durable" ];
+ this.lifetimePolicy.innerHTML = this.queueData[ "lifetimePolicy" ];
+
+ this.queueDepthMessages.innerHTML = this.queueData["queueDepthMessages"];
+ bytesDepth = formatter.formatBytes( this.queueData["queueDepthBytes"] );
+ this.queueDepthBytes.innerHTML = "(" + bytesDepth.value;
+ this.queueDepthBytesUnits.innerHTML = bytesDepth.units + ")";
+
+ this.unacknowledgedMessages.innerHTML = this.queueData["unacknowledgedMessages"];
+ bytesDepth = formatter.formatBytes( this.queueData["unacknowledgedBytes"] );
+ this.unacknowledgedBytes.innerHTML = "(" + bytesDepth.value;
+ this.unacknowledgedBytesUnits.innerHTML = bytesDepth.units + ")"
+
+
+ };
+
+ QueueUpdater.prototype.update = function()
+ {
+
+ var thisObj = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) {
+ var i,j;
+ thisObj.queueData = data[0];
+ util.flattenStatistics( thisObj.queueData );
+
+ var bindings = thisObj.queueData[ "bindings" ];
+ var consumers = thisObj.queueData[ "consumers" ];
+
+ for(i=0; i < bindings.length; i++) {
+ bindings[i].argumentString = json.stringify(bindings[i].arguments);
+ }
+
+ thisObj.updateHeader();
+
+
+ // update alerting info
+ var alertRepeatGap = formatter.formatTime( thisObj.queueData["alertRepeatGap"] );
+
+ thisObj.alertRepeatGap.innerHTML = alertRepeatGap.value;
+ thisObj.alertRepeatGapUnits.innerHTML = alertRepeatGap.units;
+
+
+ var alertMsgAge = formatter.formatTime( thisObj.queueData["alertThresholdMessageAge"] );
+
+ thisObj.alertThresholdMessageAge.innerHTML = alertMsgAge.value;
+ thisObj.alertThresholdMessageAgeUnits.innerHTML = alertMsgAge.units;
+
+ var alertMsgSize = formatter.formatBytes( thisObj.queueData["alertThresholdMessageSize"] );
+
+ thisObj.alertThresholdMessageSize.innerHTML = alertMsgSize.value;
+ thisObj.alertThresholdMessageSizeUnits.innerHTML = alertMsgSize.units;
+
+ var alertQueueDepth = formatter.formatBytes( thisObj.queueData["alertThresholdQueueDepthBytes"] );
+
+ thisObj.alertThresholdQueueDepthBytes.innerHTML = alertQueueDepth.value;
+ thisObj.alertThresholdQueueDepthBytesUnits.innerHTML = alertQueueDepth.units;
+
+ thisObj.alertThresholdQueueDepthMessages.innerHTML = thisObj.queueData["alertThresholdQueueDepthMessages"];
+
+ var sampleTime = new Date();
+ var messageIn = thisObj.queueData["totalEnqueuedMessages"];
+ var bytesIn = thisObj.queueData["totalEnqueuedBytes"];
+ var messageOut = thisObj.queueData["totalDequeuedMessages"];
+ var bytesOut = thisObj.queueData["totalDequeuedBytes"];
+
+ if(thisObj.sampleTime) {
+ var samplePeriod = sampleTime.getTime() - thisObj.sampleTime.getTime();
+
+ var msgInRate = (1000 * (messageIn - thisObj.messageIn)) / samplePeriod;
+ var msgOutRate = (1000 * (messageOut - thisObj.messageOut)) / samplePeriod;
+ var bytesInRate = (1000 * (bytesIn - thisObj.bytesIn)) / samplePeriod;
+ var bytesOutRate = (1000 * (bytesOut - thisObj.bytesOut)) / samplePeriod;
+
+ thisObj.msgInRate.innerHTML = msgInRate.toFixed(0);
+ var bytesInFormat = formatter.formatBytes( bytesInRate );
+ thisObj.bytesInRate.innerHTML = "(" + bytesInFormat.value;
+ thisObj.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)";
+
+ thisObj.msgOutRate.innerHTML = msgOutRate.toFixed(0);
+ var bytesOutFormat = formatter.formatBytes( bytesOutRate );
+ thisObj.bytesOutRate.innerHTML = "(" + bytesOutFormat.value;
+ thisObj.bytesOutRateUnits.innerHTML = bytesOutFormat.units + "/s)";
+
+ if(consumers && thisObj.consumers) {
+ for(i=0; i < consumers.length; i++) {
+ var consumer = consumers[i];
+ for(j = 0; j < thisObj.consumers.length; j++) {
+ var oldConsumer = thisObj.consumers[j];
+ if(oldConsumer.id == consumer.id) {
+ var msgRate = (1000 * (consumer.messagesOut - oldConsumer.messagesOut)) /
+ samplePeriod;
+ consumer.msgRate = msgRate.toFixed(0) + "msg/s";
+
+ var bytesRate = (1000 * (consumer.bytesOut - oldConsumer.bytesOut)) /
+ samplePeriod;
+ var bytesRateFormat = formatter.formatBytes( bytesRate );
+ consumer.bytesRate = bytesRateFormat.value + bytesRateFormat.units + "/s";
+ }
+ }
+ }
+ }
+
+ }
+
+ thisObj.sampleTime = sampleTime;
+ thisObj.messageIn = messageIn;
+ thisObj.bytesIn = bytesIn;
+ thisObj.messageOut = messageOut;
+ thisObj.bytesOut = bytesOut;
+ thisObj.consumers = consumers;
+
+ // update bindings
+ thisObj.bindingsGrid.update(thisObj.queueData.bindings);
+
+ // update consumers
+ thisObj.consumersGrid.update(thisObj.queueData.consumers)
+
+ });
+ };
+
+
+ return Queue;
+ });
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
new file mode 100644
index 0000000000..ce24145930
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
@@ -0,0 +1,327 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "dijit/registry",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/formatter",
+ "qpid/common/UpdatableStore",
+ "qpid/management/addQueue",
+ "qpid/management/addExchange",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, registry, properties, updater, util, formatter, UpdatableStore, addQueue, addExchange) {
+
+ function VirtualHost(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "virtualhost", name: name};
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+ VirtualHost.prototype.getTitle = function()
+ {
+ return "VirtualHost: " + this.name;
+ };
+
+ VirtualHost.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showVirtualHost.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.vhostUpdater = new Updater(contentPane.containerNode, that.modelObj, that.controller);
+
+ updater.add( that.vhostUpdater );
+
+ that.vhostUpdater.update();
+
+ var addQueueButton = query(".addQueueButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addQueueButton), "onClick", function(evt){ addQueue.show(that.name) });
+
+ var addExchangeButton = query(".addExchangeButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addExchangeButton), "onClick", function(evt){ addExchange.show(that.name) });
+ }});
+
+ };
+
+ VirtualHost.prototype.close = function() {
+ updater.remove( this.vhostUpdater );
+ };
+
+
+ function Updater(node, vhost, controller)
+ {
+
+ var that = this;
+
+ function findNode(name) {
+ return query("." + name, node)[0];
+ }
+
+ function storeNodes(names)
+ {
+ for(var i = 0; i < names.length; i++) {
+ that[names[i]] = findNode(names[i]);
+ }
+ }
+
+ storeNodes(["name",
+ "state",
+ "durable",
+ "lifetimePolicy",
+ "alertRepeatGap",
+ "alertRepeatGapUnits",
+ "alertThresholdMessageAge",
+ "alertThresholdMessageAgeUnits",
+ "alertThresholdMessageSize",
+ "alertThresholdMessageSizeUnits",
+ "alertThresholdQueueDepthBytes",
+ "alertThresholdQueueDepthBytesUnits",
+ "alertThresholdQueueDepthMessages",
+ "msgInRate",
+ "bytesInRate",
+ "bytesInRateUnits",
+ "msgOutRate",
+ "bytesOutRate",
+ "bytesOutRateUnits"]);
+
+ this.query = "rest/virtualhost/"+ encodeURIComponent(vhost.name);
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) {
+ that.vhostData = data[0];
+
+ // flatten statistics into attributes
+ util.flattenStatistics( that.vhostData );
+
+ that.updateHeader();
+ that.queuesGrid = new UpdatableStore(that.vhostData.queues, findNode("queues"),
+ [ { name: "Name", field: "name", width: "90px"},
+ { name: "Messages", field: "queueDepthMessages", width: "90px"},
+ { name: "Arguments", field: "arguments", width: "100%"}
+ ],
+ function(obj)
+ {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var queueName = obj.dataStore.getValue(theItem,"name");
+ controller.show("queue", queueName, vhost);
+ });
+ } );
+
+ that.exchangesGrid = new UpdatableStore(that.vhostData.exchanges, findNode("exchanges"),
+ [ { name: "Name", field: "name", width: "120px"},
+ { name: "Type", field: "type", width: "120px"},
+ { name: "Binding Count", field: "bindingCount",
+ width: "100%"}
+ ],
+ function(obj)
+ {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var exchangeName = obj.dataStore.getValue(theItem,"name");
+ controller.show("exchange", exchangeName, vhost);
+ });
+ } );
+
+
+ that.connectionsGrid = new UpdatableStore(that.vhostData.connections,
+ findNode("connections"),
+ [ { name: "Name", field: "name", width: "150px"},
+ { name: "Sessions", field: "sessionCount", width: "70px"},
+ { name: "Msgs In", field: "msgInRate",
+ width: "80px"},
+ { name: "Bytes In", field: "bytesInRate",
+ width: "80px"},
+ { name: "Msgs Out", field: "msgOutRate",
+ width: "80px"},
+ { name: "Bytes Out", field: "bytesOutRate",
+ width: "100%"}
+ ],
+ function(obj)
+ {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var connectionName = obj.dataStore.getValue(theItem,"name");
+ controller.show("connection", connectionName, vhost);
+ });
+ } );
+
+
+
+ });
+
+ }
+
+ Updater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.vhostData[ "name" ];
+ this.state.innerHTML = this.vhostData[ "state" ];
+ this.durable.innerHTML = this.vhostData[ "durable" ];
+ this.lifetimePolicy.innerHTML = this.vhostData[ "lifetimePolicy" ];
+
+
+ };
+
+ Updater.prototype.update = function()
+ {
+
+ var thisObj = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ thisObj.vhostData = data[0];
+ util.flattenStatistics( thisObj.vhostData );
+ var connections = thisObj.vhostData[ "connections" ];
+ var queues = thisObj.vhostData[ "queues" ];
+ var exchanges = thisObj.vhostData[ "exchanges" ];
+
+ thisObj.updateHeader();
+
+
+ // update alerting info
+ var alertRepeatGap = formatter.formatTime( thisObj.vhostData["alertRepeatGap"] );
+
+ thisObj.alertRepeatGap.innerHTML = alertRepeatGap.value;
+ thisObj.alertRepeatGapUnits.innerHTML = alertRepeatGap.units;
+
+
+ var alertMsgAge = formatter.formatTime( thisObj.vhostData["alertThresholdMessageAge"] );
+
+ thisObj.alertThresholdMessageAge.innerHTML = alertMsgAge.value;
+ thisObj.alertThresholdMessageAgeUnits.innerHTML = alertMsgAge.units;
+
+ var alertMsgSize = formatter.formatBytes( thisObj.vhostData["alertThresholdMessageSize"] );
+
+ thisObj.alertThresholdMessageSize.innerHTML = alertMsgSize.value;
+ thisObj.alertThresholdMessageSizeUnits.innerHTML = alertMsgSize.units;
+
+ var alertQueueDepth = formatter.formatBytes( thisObj.vhostData["alertThresholdQueueDepthBytes"] );
+
+ thisObj.alertThresholdQueueDepthBytes.innerHTML = alertQueueDepth.value;
+ thisObj.alertThresholdQueueDepthBytesUnits.innerHTML = alertQueueDepth.units;
+
+ thisObj.alertThresholdQueueDepthMessages.innerHTML = thisObj.vhostData["alertThresholdQueueDepthMessages"];
+
+ var stats = thisObj.vhostData[ "statistics" ];
+
+ var sampleTime = new Date();
+ var messageIn = stats["messagesIn"];
+ var bytesIn = stats["bytesIn"];
+ var messageOut = stats["messagesOut"];
+ var bytesOut = stats["bytesOut"];
+
+ if(thisObj.sampleTime)
+ {
+ var samplePeriod = sampleTime.getTime() - thisObj.sampleTime.getTime();
+
+ var msgInRate = (1000 * (messageIn - thisObj.messageIn)) / samplePeriod;
+ var msgOutRate = (1000 * (messageOut - thisObj.messageOut)) / samplePeriod;
+ var bytesInRate = (1000 * (bytesIn - thisObj.bytesIn)) / samplePeriod;
+ var bytesOutRate = (1000 * (bytesOut - thisObj.bytesOut)) / samplePeriod;
+
+ thisObj.msgInRate.innerHTML = msgInRate.toFixed(0);
+ var bytesInFormat = formatter.formatBytes( bytesInRate );
+ thisObj.bytesInRate.innerHTML = "(" + bytesInFormat.value;
+ thisObj.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)";
+
+ thisObj.msgOutRate.innerHTML = msgOutRate.toFixed(0);
+ var bytesOutFormat = formatter.formatBytes( bytesOutRate );
+ thisObj.bytesOutRate.innerHTML = "(" + bytesOutFormat.value;
+ thisObj.bytesOutRateUnits.innerHTML = bytesOutFormat.units + "/s)";
+
+ if(connections && thisObj.connections)
+ {
+ for(var i=0; i < connections.length; i++)
+ {
+ var connection = connections[i];
+ for(var j = 0; j < thisObj.connections.length; j++)
+ {
+ var oldConnection = thisObj.connections[j];
+ if(oldConnection.id == connection.id)
+ {
+ msgOutRate = (1000 * (connection.messagesOut - oldConnection.messagesOut)) /
+ samplePeriod;
+ connection.msgOutRate = msgOutRate.toFixed(0) + "msg/s";
+
+ bytesOutRate = (1000 * (connection.bytesOut - oldConnection.bytesOut)) /
+ samplePeriod;
+ var bytesOutRateFormat = formatter.formatBytes( bytesOutRate );
+ connection.bytesOutRate = bytesOutRateFormat.value + bytesOutRateFormat.units + "/s";
+
+
+ msgInRate = (1000 * (connection.messagesIn - oldConnection.messagesIn)) /
+ samplePeriod;
+ connection.msgInRate = msgInRate.toFixed(0) + "msg/s";
+
+ bytesInRate = (1000 * (connection.bytesIn - oldConnection.bytesIn)) /
+ samplePeriod;
+ var bytesInRateFormat = formatter.formatBytes( bytesInRate );
+ connection.bytesInRate = bytesInRateFormat.value + bytesInRateFormat.units + "/s";
+ }
+
+
+ }
+
+ }
+ }
+ }
+
+ thisObj.sampleTime = sampleTime;
+ thisObj.messageIn = messageIn;
+ thisObj.bytesIn = bytesIn;
+ thisObj.messageOut = messageOut;
+ thisObj.bytesOut = bytesOut;
+ thisObj.connections = connections;
+
+ // update queues
+ thisObj.queuesGrid.update(thisObj.vhostData.queues);
+
+ // update exchanges
+ thisObj.exchangesGrid.update(thisObj.vhostData.exchanges);
+
+ // update connections
+ thisObj.connectionsGrid.update(thisObj.vhostData.connections)
+
+
+ });
+ };
+
+
+ return VirtualHost;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js
new file mode 100644
index 0000000000..83e724d0e9
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dojo/_base/window",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "dojo/store/Memory",
+ "dijit/form/FilteringSelect",
+ "dijit/form/NumberSpinner", // required by the form
+ /* dojox/ validate resources */
+ "dojox/validate/us", "dojox/validate/web",
+ /* basic dijit classes */
+ "dijit/Dialog",
+ "dijit/form/CheckBox", "dijit/form/Textarea",
+ "dijit/form/FilteringSelect", "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox", "dijit/form/DateTextBox",
+ "dijit/form/TimeTextBox", "dijit/form/Button",
+ "dijit/form/RadioButton", "dijit/form/Form",
+ "dijit/form/DateTextBox",
+ /* basic dojox classes */
+ "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect",
+ "dojo/domReady!"],
+ function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, FilteringSelect) {
+
+ var addBinding = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ var convertToBinding = function convertToBinding(formValues)
+ {
+ var newBinding = {};
+
+ newBinding.name = formValues.name;
+ for(var propName in formValues)
+ {
+ if(formValues.hasOwnProperty(propName))
+ {
+ if(propName === "durable")
+ {
+ if (formValues.durable[0] && formValues.durable[0] == "durable") {
+ newBinding.durable = true;
+ }
+ } else {
+ if(formValues[ propName ] !== "") {
+ newBinding[ propName ] = formValues[propName];
+ }
+ }
+
+ }
+ }
+ if(addBinding.queue) {
+ newBinding.queue = addBinding.queue;
+ }
+ if(addBinding.exchange) {
+ newBinding.exchange = addBinding.exchange;
+ }
+ return newBinding;
+ };
+
+
+ xhr.get({url: "addBinding.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ node.innerHTML = data;
+ addBinding.dialogNode = dom.byId("addBinding");
+ parser.instantiate([addBinding.dialogNode]);
+
+ theForm = registry.byId("formAddBinding");
+ array.forEach(theForm.getDescendants(), function(widget)
+ {
+ if(widget.name === "type") {
+ widget.on("change", function(isChecked) {
+
+ var obj = registry.byId(widget.id + ":fields");
+ if(obj) {
+ if(isChecked) {
+ obj.domNode.style.display = "block";
+ obj.resize();
+ } else {
+ obj.domNode.style.display = "none";
+ obj.resize();
+ }
+ }
+ })
+ }
+
+ });
+
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ var newBinding = convertToBinding(theForm.getValues());
+ var that = this;
+
+ xhr.put({url: "rest/binding/"+encodeURIComponent(addBinding.vhost)
+ +"/"+encodeURIComponent(newBinding.exchange)
+ +"/"+encodeURIComponent(newBinding.queue)
+ +"/"+encodeURIComponent(newBinding.name),
+ sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newBinding),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(this.success === true)
+ {
+ registry.byId("addBinding").hide();
+ }
+ else
+ {
+ alert("Error:" + this.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+ }});
+
+ addBinding.show = function(obj) {
+ var that = this;
+
+ addBinding.vhost = obj.virtualhost;
+ addBinding.queue = obj.queue;
+ addBinding.exchange = obj.exchange;
+ registry.byId("formAddBinding").reset();
+
+
+
+ xhr.get({url: "rest/queue/" + encodeURIComponent(obj.virtualhost) + "?depth=0",
+ handleAs: "json"}).then(
+ function(data) {
+ var queues = [];
+ for(var i=0; i < data.length; i++) {
+ queues[i] = {id: data[i].name, name: data[i].name};
+ }
+ var queueStore = new Memory({ data: queues });
+
+
+ if(that.queueChooser) {
+ that.queueChooser.destroy( false );
+ }
+ var queueDiv = dom.byId("addBinding.selectQueueDiv");
+ var input = construct.create("input", {id: "addBindingSelectQueue"}, queueDiv);
+
+ that.queueChooser = new FilteringSelect({ id: "addBindingSelectQueue",
+ name: "queue",
+ store: queueStore,
+ searchAttr: "name"}, input);
+
+ if(obj.queue)
+ {
+ that.queueChooser.set("value", obj.queue);
+ that.queueChooser.set("disabled", true);
+ }
+
+ xhr.get({url: "rest/exchange/" + encodeURIComponent(obj.virtualhost) + "?depth=0",
+ handleAs: "json"}).then(
+ function(data) {
+
+ var exchanges = [];
+ for(var i=0; i < data.length; i++) {
+ exchanges[i] = {id: data[i].name, name: data[i].name};
+ }
+ var exchangeStore = new Memory({ data: exchanges });
+
+
+ if(that.exchangeChooser) {
+ that.exchangeChooser.destroy( false );
+ }
+ var exchangeDiv = dom.byId("addBinding.selectExchangeDiv");
+ var input = construct.create("input", {id: "addBindingSelectExchange"}, exchangeDiv);
+
+ that.exchangeChooser = new FilteringSelect({ id: "addBindingSelectExchange",
+ name: "exchange",
+ store: exchangeStore,
+ searchAttr: "name"}, input);
+
+ if(obj.exchange)
+ {
+ that.exchangeChooser.set("value", obj.exchange);
+ that.exchangeChooser.set("disabled", true);
+ }
+
+
+ registry.byId("addBinding").show();
+ });
+
+
+ });
+
+
+ };
+
+ return addBinding;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js
new file mode 100644
index 0000000000..f88daa54bb
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js
@@ -0,0 +1,147 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dojo/_base/window",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "dijit/form/NumberSpinner", // required by the form
+ /* dojox/ validate resources */
+ "dojox/validate/us", "dojox/validate/web",
+ /* basic dijit classes */
+ "dijit/Dialog",
+ "dijit/form/CheckBox", "dijit/form/Textarea",
+ "dijit/form/FilteringSelect", "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox", "dijit/form/DateTextBox",
+ "dijit/form/TimeTextBox", "dijit/form/Button",
+ "dijit/form/RadioButton", "dijit/form/Form",
+ "dijit/form/DateTextBox",
+ /* basic dojox classes */
+ "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect",
+ "dojo/domReady!"],
+ function (xhr, dom, construct, win, registry, parser, array, event, json) {
+
+ var addExchange = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ var convertToExchange = function convertToExchange(formValues)
+ {
+ var newExchange = {};
+ newExchange.name = formValues.name;
+ for(var propName in formValues)
+ {
+ if(formValues.hasOwnProperty(propName))
+ {
+ if(propName === "durable")
+ {
+ if (formValues.durable[0] && formValues.durable[0] == "durable") {
+ newExchange.durable = true;
+ }
+ } else {
+ if(formValues[ propName ] !== "") {
+ newExchange[ propName ] = formValues[propName];
+ }
+ }
+
+ }
+ }
+
+ return newExchange;
+ };
+
+
+ xhr.get({url: "addExchange.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ node.innerHTML = data;
+ addExchange.dialogNode = dom.byId("addExchange");
+ parser.instantiate([addExchange.dialogNode]);
+
+ theForm = registry.byId("formAddExchange");
+ array.forEach(theForm.getDescendants(), function(widget)
+ {
+ if(widget.name === "type") {
+ widget.on("change", function(isChecked) {
+
+ var obj = registry.byId(widget.id + ":fields");
+ if(obj) {
+ if(isChecked) {
+ obj.domNode.style.display = "block";
+ obj.resize();
+ } else {
+ obj.domNode.style.display = "none";
+ obj.resize();
+ }
+ }
+ })
+ }
+
+ });
+
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ var newExchange = convertToExchange(theForm.getValues());
+ var that = this;
+
+ xhr.put({url: "rest/exchange/"+encodeURIComponent(addExchange.vhost) +
+ "/"+encodeURIComponent(newExchange.name), sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newExchange),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(this.success === true)
+ {
+ registry.byId("addExchange").hide();
+ }
+ else
+ {
+ alert("Error:" + this.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+ }});
+
+ addExchange.show = function(vhost) {
+ addExchange.vhost = vhost;
+ registry.byId("formAddExchange").reset();
+ registry.byId("addExchange").show();
+ };
+
+ return addExchange;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js
new file mode 100644
index 0000000000..4a2dccde5f
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js
@@ -0,0 +1,158 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dojo/_base/window",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "dijit/form/NumberSpinner", // required by the form
+ /* dojox/ validate resources */
+ "dojox/validate/us", "dojox/validate/web",
+ /* basic dijit classes */
+ "dijit/Dialog",
+ "dijit/form/CheckBox", "dijit/form/Textarea",
+ "dijit/form/FilteringSelect", "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox", "dijit/form/DateTextBox",
+ "dijit/form/TimeTextBox", "dijit/form/Button",
+ "dijit/form/RadioButton", "dijit/form/Form",
+ "dijit/form/DateTextBox",
+ /* basic dojox classes */
+ "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect",
+ "dojo/domReady!"],
+ function (xhr, dom, construct, win, registry, parser, array, event, json) {
+
+ var addQueue = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ var typeSpecificFields = {
+ numPriorities: "priority",
+ lvqKey: "lvq",
+ sortKey: "sorted"
+ };
+
+
+ var convertToQueue = function convertToQueue(formValues)
+ {
+ var newQueue = {};
+ newQueue.name = formValues.name;
+ for(var propName in formValues)
+ {
+ if(formValues.hasOwnProperty(propName))
+ {
+ if(propName === "durable")
+ {
+ if (formValues.durable[0] && formValues.durable[0] == "durable") {
+ newQueue.durable = true;
+ }
+ } else if (!typeSpecificFields.hasOwnProperty(propName) ||
+ formValues.type === typeSpecificFields[ propName ]) {
+ if(formValues[ propName ] !== "") {
+ newQueue[ propName ] = formValues[propName];
+ }
+ }
+
+ }
+ }
+
+ return newQueue;
+ };
+
+
+ xhr.get({url: "addQueue.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ node.innerHTML = data;
+ addQueue.dialogNode = dom.byId("addQueue");
+ parser.instantiate([addQueue.dialogNode]);
+
+ // for children which have name type, add a function to make all the associated rows
+ // visible / invisible as the radio button is checked / unchecked
+
+ theForm = registry.byId("formAddQueue");
+ array.forEach(theForm.getDescendants(), function(widget)
+ {
+ if(widget.name === "type") {
+ widget.on("change", function(isChecked) {
+
+ var obj = registry.byId(widget.id + ":fields");
+ if(obj) {
+ if(isChecked) {
+ obj.domNode.style.display = "block";
+ obj.resize();
+ } else {
+ obj.domNode.style.display = "none";
+ obj.resize();
+ }
+ }
+ })
+ }
+
+ });
+
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ var newQueue = convertToQueue(theForm.getValues());
+ var that = this;
+
+ xhr.put({url: "rest/queue/"+encodeURIComponent(addQueue.vhost)
+ +"/"+encodeURIComponent(newQueue.name), sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newQueue),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(this.success === true)
+ {
+ registry.byId("addQueue").hide();
+ }
+ else
+ {
+ alert("Error:" + this.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+ }});
+
+ addQueue.show = function(vhost) {
+ addQueue.vhost = vhost;
+ registry.byId("formAddQueue").reset();
+ registry.byId("addQueue").show();
+ };
+
+ return addQueue;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js
new file mode 100644
index 0000000000..ffebc98af7
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js
@@ -0,0 +1,327 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/dom-construct",
+ "dojo/_base/connect",
+ "dojo/_base/window",
+ "dojo/_base/event",
+ "dojo/_base/json",
+ "dijit/registry",
+ "qpid/common/util",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/UpdatableStore",
+ "dojox/grid/EnhancedGrid",
+ "dojox/grid/enhanced/plugins/Pagination",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojox/validate/us", "dojox/validate/web",
+ "dijit/Dialog",
+ "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox",
+ "dijit/form/TimeTextBox", "dijit/form/Button",
+ "dijit/form/Form",
+ "dijit/form/DateTextBox",
+ "dojo/domReady!"],
+ function (xhr, dom, parser, query, construct, connect, win, event, json, registry, util, properties, updater, UpdatableStore, EnhancedGrid) {
+ function DatabaseAuthManager(containerNode, authProviderObj, controller) {
+ var node = construct.create("div", null, containerNode, "last");
+ var that = this;
+ this.name = authProviderObj.name;
+ xhr.get({url: "authenticationprovider/showPrincipalDatabaseAuthenticationManager.html",
+ sync: true,
+ load: function(data) {
+ node.innerHTML = data;
+ parser.parse(node);
+
+
+ that.authDatabaseUpdater= new AuthProviderUpdater(node, authProviderObj, controller);
+
+ updater.add( that.authDatabaseUpdater);
+
+ that.authDatabaseUpdater.update();
+
+
+ }});
+ }
+
+ DatabaseAuthManager.prototype.update = function() {
+ this.authDatabaseUpdater.update();
+ };
+
+ DatabaseAuthManager.prototype.close = function() {
+ updater.remove( this.authDatabaseUpdater );
+ };
+
+ function AuthProviderUpdater(node, authProviderObj, controller)
+ {
+ this.controller = controller;
+ this.query = "rest/authenticationprovider/"+encodeURIComponent(authProviderObj.name);
+ this.name = authProviderObj.name;
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ that.authProviderData = data[0];
+
+ util.flattenStatistics( that.authProviderData );
+
+ var userDiv = query(".users")[0];
+
+ var gridProperties = {
+ height: 400,
+ keepSelection: true,
+ plugins: {
+ pagination: {
+ pageSizes: ["10", "25", "50", "100"],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ indirectSelection: true
+
+ }};
+
+
+ that.usersGrid =
+ new UpdatableStore(that.authProviderData.users, userDiv,
+ [ { name: "User Name", field: "name", width: "100%" }
+ ], function(obj) {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var name = obj.dataStore.getValue(theItem,"name");
+ var id = obj.dataStore.getValue(theItem,"id");
+ setPassword.show(authProviderObj.name, {name: name, id: id});
+ });
+ }, gridProperties, EnhancedGrid);
+
+
+ var addUserButton = query(".addUserButton", node)[0];
+ connect.connect(registry.byNode(addUserButton), "onClick", function(evt){ addUser.show(authProviderObj.name) });
+
+ var deleteMessagesButton = query(".deleteUserButton", node)[0];
+ var deleteWidget = registry.byNode(deleteMessagesButton);
+ connect.connect(deleteWidget, "onClick",
+ function(evt){
+ event.stop(evt);
+ that.deleteUsers();
+ });
+ });
+ }
+
+ AuthProviderUpdater.prototype.deleteUsers = function()
+ {
+ var grid = this.usersGrid.grid;
+ var data = grid.selection.getSelected();
+ if(data.length) {
+ var that = this;
+ if(confirm("Delete " + data.length + " users?")) {
+ var i, queryParam;
+ for(i = 0; i<data.length; i++) {
+ if(queryParam) {
+ queryParam += "&";
+ } else {
+ queryParam = "?";
+ }
+
+ queryParam += "id=" + data[i].id;
+ }
+ var query = "rest/user/"+ encodeURIComponent(that.name)
+ + queryParam;
+ that.success = true
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ grid.setQuery({id: "*"});
+ grid.selection.deselectAll();
+ that.update();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!that.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+}
+ };
+
+ AuthProviderUpdater.prototype.update = function()
+ {
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ that.authProviderData = data[0];
+ util.flattenStatistics( that.authProviderData );
+
+ that.usersGrid.update(that.authProviderData.users);
+
+ });
+
+
+ };
+
+ var addUser = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ var convertToUser = function convertToUser(formValues) {
+ var newUser = {};
+ newUser.name = formValues.name;
+ for(var propName in formValues)
+ {
+ if(formValues.hasOwnProperty(propName)) {
+ if(formValues[ propName ] !== "") {
+ newUser[ propName ] = formValues[propName];
+ }
+ }
+ }
+
+ return newUser;
+ };
+
+
+ xhr.get({url: "authenticationprovider/addUser.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ node.innerHTML = data;
+ addUser.dialogNode = dom.byId("addUser");
+ parser.instantiate([addUser.dialogNode]);
+
+ var that = this;
+
+ theForm = registry.byId("formAddUser");
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ var newUser = convertToUser(theForm.getValues());
+
+
+ var url = "rest/user/"+encodeURIComponent(addUser.authProvider) +
+ "/"+encodeURIComponent(newUser.name);
+
+ xhr.put({url: url, sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newUser),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(this.success === true) {
+ registry.byId("addUser").hide();
+ } else {
+ alert("Error:" + this.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+ }});
+
+ addUser.show = function(authProvider) {
+ addUser.authProvider = authProvider;
+ registry.byId("formAddUser").reset();
+ registry.byId("addUser").show();
+ };
+
+
+ var setPassword = {};
+
+ var setPasswordNode = construct.create("div", null, win.body(), "last");
+
+ xhr.get({url: "authenticationprovider/setPassword.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ setPasswordNode.innerHTML = data;
+ setPassword.dialogNode = dom.byId("setPassword");
+ parser.instantiate([setPassword.dialogNode]);
+
+ var that = this;
+
+ theForm = registry.byId("formSetPassword");
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ var newUser = convertToUser(theForm.getValues());
+ newUser.name = setPassword.name;
+ newUser.id = setPassword.id;
+
+ var url = "rest/user/"+encodeURIComponent(setPassword.authProvider) +
+ "/"+encodeURIComponent(newUser.name);
+
+ xhr.put({url: url, sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newUser),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(that.success === true) {
+ registry.byId("setPassword").hide();
+ } else {
+ alert("Error:" + that.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+ }});
+
+ setPassword.show = function(authProvider, user) {
+ setPassword.authProvider = authProvider;
+ setPassword.name = user.name;
+ setPassword.id = user.id;
+ registry.byId("formSetPassword").reset();
+
+ var namebox = registry.byId("formSetPassword.name");
+ namebox.set("value", user.name);
+ namebox.set("disabled", true);
+
+ registry.byId("setPassword").show();
+
+ };
+
+
+
+ return DatabaseAuthManager;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
new file mode 100644
index 0000000000..1aa05a5a3c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
@@ -0,0 +1,104 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/dom",
+ "dijit/registry",
+ "dijit/layout/ContentPane",
+ "qpid/management/Broker",
+ "qpid/management/VirtualHost",
+ "qpid/management/Exchange",
+ "qpid/management/Queue",
+ "qpid/management/Connection",
+ "qpid/management/AuthenticationProvider",
+ "dojo/ready",
+ "dojo/domReady!"],
+ function (dom, registry, ContentPane, Broker, VirtualHost, Exchange, Queue, Connection, AuthProvider, ready) {
+ var controller = {};
+
+ var constructors = { broker: Broker, virtualhost: VirtualHost, exchange: Exchange,
+ queue: Queue, connection: Connection, authenticationprovider: AuthProvider };
+
+ var tabDiv = dom.byId("managedViews");
+
+ ready(function() {
+ controller.tabContainer = registry.byId("managedViews");
+ });
+
+
+ controller.viewedObjects = {};
+
+ controller.show = function(objType, name, parent) {
+
+ function generateName(obj)
+ {
+ if(obj) {
+ var name = "";
+ if(obj.parent)
+ {
+ for(var prop in obj.parent) {
+ if(obj.parent.hasOwnProperty(prop)) {
+ name = name + generateName( obj.parent[ prop ]);
+ }
+ }
+
+ }
+ return name + parent.type +":" + parent.name + "/"
+ }
+ }
+
+ var that = this;
+ var objId = generateName(parent) + objType+":"+name;
+ if( this.viewedObjects[ objId ] ) {
+ this.tabContainer.selectChild(this.viewedObjects[ objId ].contentPane);
+ } else {
+ var Constructor = constructors[ objType ];
+ if(Constructor) {
+ var obj = new Constructor(name, parent, this);
+ this.viewedObjects[ objId ] = obj;
+
+ var contentPane = new ContentPane({ region: "center" ,
+ title: obj.getTitle(),
+ closable: true,
+ onClose: function() {
+ obj.close();
+ delete that.viewedObjects[ objId ];
+ return true;
+ }
+ });
+ this.tabContainer.addChild( contentPane );
+ obj.open(contentPane);
+ contentPane.startup();
+ if(obj.startup) {
+ obj.startup();
+ }
+ this.tabContainer.selectChild( contentPane );
+ }
+
+ }
+
+ };
+
+ ready(function() {
+ controller.show("broker","");
+ });
+
+
+ return controller;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/moveCopyMessages.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/moveCopyMessages.js
new file mode 100644
index 0000000000..8cc488324f
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/moveCopyMessages.js
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dojo/_base/window",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "dojo/store/Memory",
+ "dijit/form/FilteringSelect",
+ "dojo/query",
+ "dojo/_base/connect",
+ "dojo/domReady!"],
+ function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, FilteringSelect, query, connect) {
+
+ var moveMessages = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ xhr.get({url: "moveCopyMessages.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ node.innerHTML = data;
+ moveMessages.dialogNode = dom.byId("moveMessages");
+ parser.instantiate([moveMessages.dialogNode]);
+
+ theForm = registry.byId("formMoveMessages");
+
+
+ var cancelButton = query(".moveMessageCancel")[0];
+ connect.connect(registry.byNode(cancelButton), "onClick",
+ function(evt){
+ event.stop(evt);
+ registry.byId("moveMessages").hide();
+ });
+
+
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ moveMessages.data.destinationQueue = theForm.getValues()["queue"];
+ var that = this;
+
+ xhr.post({url: "rest/message/"+encodeURIComponent(moveMessages.vhost)
+ +"/"+encodeURIComponent(moveMessages.queue),
+ sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ postData: json.toJson(moveMessages.data),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(this.success === true) {
+ registry.byId("moveMessages").hide();
+ if(moveMessages.next) {
+ moveMessages.next();
+ }
+ } else {
+ alert("Error:" + this.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+
+ }});
+
+ moveMessages.show = function(obj, next) {
+ var that = this;
+
+ moveMessages.vhost = obj.virtualhost;
+ moveMessages.queue = obj.queue;
+ moveMessages.data = obj.data;
+ moveMessages.next = next;
+ registry.byId("formMoveMessages").reset();
+
+
+
+ xhr.get({url: "rest/queue/" + encodeURIComponent(obj.virtualhost) + "?depth=0",
+ handleAs: "json"}).then(
+ function(data) {
+ var queues = [];
+ for(var i=0; i < data.length; i++) {
+ queues[i] = {id: data[i].name, name: data[i].name};
+ }
+ var queueStore = new Memory({ data: queues });
+
+
+ if(that.queueChooser) {
+ that.queueChooser.destroy( false );
+ }
+ var queueDiv = dom.byId("moveMessages.selectQueueDiv");
+ var input = construct.create("input", {id: "moveMessagesSelectQueue"}, queueDiv);
+
+ that.queueChooser = new FilteringSelect({ id: "moveMessagesSelectQueue",
+ name: "queue",
+ store: queueStore,
+ searchAttr: "name"}, input);
+
+
+
+ registry.byId("moveMessages").show();
+
+
+ });
+
+
+ };
+
+ return moveMessages;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
new file mode 100644
index 0000000000..b1ccc0ca07
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dojo/dom-class",
+ "dojo/_base/window",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "dojo/query",
+ "dojo/_base/connect",
+ "qpid/common/properties",
+ "dojox/html/entities",
+ "dojo/domReady!"],
+ function (xhr, dom, construct, domClass, win, registry, parser, array, event, json, query, connect, properties, entities) {
+
+
+ function encode(val){
+ return typeof val === 'string' ? entities.encode(val) : val;
+ }
+
+ var showMessage = {};
+
+ showMessage.hide = function () {
+ if(this.populatedFields) {
+ for(var i = 0 ; i < this.populatedFields.length; i++) {
+ this.populatedFields[i].innerHTML = "";
+ }
+ this.populatedFields = [];
+ }
+ registry.byId("showMessage").hide();
+ };
+
+ showMessage.loadViewMessage = function(data) {
+ var that = this;
+ node.innerHTML = data;
+ showMessage.dialogNode = dom.byId("showMessage");
+ parser.instantiate([showMessage.dialogNode]);
+
+ var closeButton = query(".closeViewMessage")[0];
+ connect.connect(closeButton, "onclick",
+ function (evt) {
+ event.stop(evt);
+ showMessage.hide();
+ });
+ };
+
+ showMessage.populateShowMessage = function(data) {
+
+ this.populatedFields = [];
+
+ for(var attrName in data) {
+ if(data.hasOwnProperty(attrName)) {
+ var fields = query(".message-"+attrName, this.dialogNode);
+ if(fields && fields.length != 0) {
+ var field = fields[0];
+ this.populatedFields.push(field);
+ var val = data[attrName];
+ if(val) {
+ if(domClass.contains(field,"map")) {
+ var tableStr = "<table style='border: 1pt'><tr><th style='width: 6em; font-weight: bold'>Header</th><th style='font-weight: bold'>Value</th></tr>";
+ for(var name in val) {
+ if(val.hasOwnProperty(name)) {
+
+ tableStr += "<tr><td>"+encode(name)+"</td>";
+ tableStr += "<td>"+encode(val[ name ])+"</td></tr>";
+ }
+ field.innerHTML = tableStr;
+ }
+ tableStr += "</table>";
+ } else if(domClass.contains(field,"datetime")) {
+ var d = new Date(0);
+ d.setUTCSeconds(val/1000);
+ field.innerHTML = d.toLocaleString();
+ } else {
+ field.innerHTML = encode(val);
+ }
+ }
+ }
+ }
+ }
+ var contentField = query(".message-content", this.dialogNode)[0];
+
+ if(data.mimeType && data.mimeType.match(/text\/.*/)) {
+ xhr.get({url: "rest/message-content/" + encodeURIComponent(showMessage.virtualhost)
+ + "/" + encodeURIComponent(showMessage.queue)
+ + "/" + encodeURIComponent(showMessage.messageNumber),
+ sync: true
+
+ }).then(function(obj) { contentField.innerHTML = encode(obj) });
+ } else {
+ contentField.innerHTML = "<a href=\"" + "rest/message-content/" + encodeURIComponent(showMessage.virtualhost)
+ + "/" + encodeURIComponent(showMessage.queue)
+ + "/" + encodeURIComponent(showMessage.messageNumber)
+ + "\" target=\"_blank\">Download</a>";
+ }
+ this.populatedFields.push(contentField);
+
+ registry.byId("showMessage").show();
+ };
+
+ showMessage.show = function(obj) {
+ showMessage.virtualhost = obj.virtualhost;
+ showMessage.queue = obj.queue;
+ showMessage.messageNumber = obj.messageNumber;
+
+ xhr.get({url: "rest/message/" + encodeURIComponent(obj.virtualhost)
+ + "/" + encodeURIComponent(obj.queue)
+ + "/" + encodeURIComponent(obj.messageNumber),
+ sync: properties.useSyncGet,
+ handleAs: "json",
+ load: this.populateShowMessage
+ });
+ };
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ xhr.get({url: "showMessage.html",
+ sync: true,
+ load: showMessage.loadViewMessage
+ });
+
+ return showMessage;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
new file mode 100644
index 0000000000..b1d4abf8c1
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
@@ -0,0 +1,313 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/query",
+ "dojo/io-query",
+ "dijit/Tree",
+ "qpid/common/util",
+ "qpid/common/updater",
+ "qpid/management/controller",
+ "dojo/domReady!"],
+ function (xhr, query, ioQuery, Tree, util, updater, controller) {
+
+ function TreeViewModel(queryString) {
+ this.query = queryString;
+
+ this.onChildrenChange = function (parent, children) {
+ // fired when the set of children for an object change
+ };
+
+ this.onChange = function (object) {
+ // fired when the properties of an object change
+ };
+
+ this.onDelete = function (object) {
+ // fired when an object is deleted
+ };
+
+ }
+
+
+ TreeViewModel.prototype.buildModel = function (data) {
+ this.model = data;
+
+ };
+
+ TreeViewModel.prototype.updateModel = function (data) {
+ var that = this;
+
+ function checkForChanges(oldData, data) {
+ var propName;
+ if (oldData.name != data.name) {
+ that.onChange(data);
+ }
+
+ var childChanges = false;
+ // Iterate over old childTypes, check all are in new
+ for (propName in oldData) {
+ if (oldData.hasOwnProperty(propName)) {
+ var oldChildren = oldData[ propName ];
+ if (util.isArray(oldChildren)) {
+
+ var newChildren = data[ propName ];
+
+ if (!(newChildren && util.isArray(newChildren))) {
+ childChanges = true;
+ } else {
+ var subChanges = false;
+ // iterate over elements in array, make sure in both, in which case recurse
+ for (var i = 0; i < oldChildren.length; i++) {
+ var matched = false;
+ for (var j = 0; j < newChildren.length; j++) {
+ if (oldChildren[i].id == newChildren[j].id) {
+ checkForChanges(oldChildren[i], newChildren[j]);
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ subChanges = true;
+ }
+ }
+ if (subChanges == true || oldChildren.length != newChildren.length) {
+ that.onChildrenChange({ id:data.id + propName, _dummyChild:propName, data:data },
+ newChildren);
+ }
+ }
+ }
+ }
+ }
+
+ for (propName in data) {
+ if (data.hasOwnProperty(propName)) {
+ var prop = data[ propName ];
+ if (util.isArray(prop)) {
+ if (!(oldData[ propName ] && util.isArray(oldData[propName]))) {
+ childChanges = true;
+ }
+ }
+ }
+ }
+
+ if (childChanges) {
+ var children = [];
+ that.getChildren(data, function (theChildren) {
+ children = theChildren
+ });
+ that.onChildrenChange(data, children);
+ }
+ }
+
+ var oldData = this.model;
+ this.model = data;
+
+ checkForChanges(oldData, data);
+ };
+
+
+ TreeViewModel.prototype.fetchItemByIdentity = function (id) {
+
+ function fetchItem(id, data) {
+ var propName;
+
+ if (data.id == id) {
+ return data;
+ } else if (id.indexOf(data.id) == 0) {
+ return { id:id, _dummyChild:id.substring(id.length), data:data };
+ } else {
+ for (propName in data) {
+ if (data.hasOwnProperty(propName)) {
+ var prop = data[ propName ];
+ if (util.isArray(prop)) {
+ for (var i = 0; i < prop.length; i++) {
+ var theItem = fetchItem(id, prop[i]);
+ if (theItem) {
+ return theItem;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ return fetchItem(id, this.model);
+ };
+
+ TreeViewModel.prototype.getChildren = function (parentItem, onComplete) {
+
+ if (parentItem) {
+ if (parentItem._dummyChild) {
+ onComplete(parentItem.data[ parentItem._dummyChild ]);
+ } else {
+ var children = [];
+ for (var propName in parentItem) {
+ if (parentItem.hasOwnProperty(propName)) {
+ var prop = parentItem[ propName ];
+
+ if (util.isArray(prop)) {
+ children.push({ id:parentItem.id
+ + propName, _dummyChild:propName, data:parentItem });
+ }
+ }
+ }
+ onComplete(children);
+ }
+ } else {
+ onComplete([]);
+ }
+ };
+
+ TreeViewModel.prototype.getIdentity = function (theItem) {
+ if (theItem) {
+ return theItem.id;
+ }
+
+ };
+
+ TreeViewModel.prototype.getLabel = function (theItem) {
+ if (theItem) {
+ if (theItem._dummyChild) {
+ return theItem._dummyChild;
+ } else {
+ return theItem.name;
+ }
+ } else {
+ return "";
+ }
+ };
+
+ TreeViewModel.prototype.getRoot = function (onItem) {
+ onItem(this.model);
+ };
+
+ TreeViewModel.prototype.mayHaveChildren = function (theItem) {
+ if (theItem) {
+ if (theItem._dummyChild) {
+ return true;
+ } else {
+ for (var propName in theItem) {
+ if (theItem.hasOwnProperty(propName)) {
+ var prop = theItem[ propName ];
+ if (util.isArray(prop)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ } else {
+ return false;
+ }
+ };
+
+ TreeViewModel.prototype.relocate = function (theItem) {
+
+ function findItemDetails(theItem, details, type, object) {
+ if (theItem.id == object.id) {
+ details.type = type;
+ details[ type ] = object.name;
+ } else {
+ details[ type ] = object.name;
+
+ // iterate over children
+ for (var propName in object) {
+ if (object.hasOwnProperty(propName)) {
+ var prop = object[ propName ];
+ if (util.isArray(prop)) {
+ for (var i = 0; i < prop.length; i++) {
+ findItemDetails(theItem, details, propName.substring(0, propName.length - 1),
+ prop[i]);
+
+ if (details.type) {
+ break;
+ }
+ }
+ }
+ if (details.type) {
+ break;
+ }
+ }
+ }
+
+ if (!details.type) {
+ details[ type ] = null;
+ }
+ }
+ }
+
+ var details = new Object();
+
+ findItemDetails(theItem, details, "broker", this.model);
+
+ if (details.type == "broker") {
+ controller.show("broker", "");
+ } else if (details.type == "virtualhost") {
+ controller.show("virtualhost", details.virtualhost, {type:"broker", name:""});
+ } else if (details.type == "exchange") {
+ controller.show("exchange", details.exchange, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}});
+ } else if (details.type == "queue") {
+ controller.show("queue", details.queue, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}});
+ } else if (details.type == "connection") {
+ controller.show("connection", details.connection, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}});
+ } else if (details.type == 'port') {
+ controller.show("port", details.port, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}});
+ } else if (details.type == 'authenticationprovider') {
+ controller.show("authenticationprovider", details.authenticationprovider, {broker: {type:"broker", name:""}});
+ }
+
+
+
+ };
+
+ TreeViewModel.prototype.update = function () {
+ var thisObj = this;
+
+ xhr.get({url:this.query, sync: true, handleAs:"json"})
+ .then(function (data) {
+ if (thisObj.model) {
+ thisObj.updateModel(data);
+ }
+ else {
+ thisObj.buildModel(data);
+ }
+ });
+
+ };
+
+ query('div[qpid-type="treeView"]').forEach(function(node, index, arr) {
+ var treeModel = new TreeViewModel("rest/structure");
+ treeModel.update();
+ var tree = new Tree({ model: treeModel }, node);
+ tree.on("dblclick",
+ function (object) {
+ if (object && !object._dummyChild) {
+ treeModel.relocate(object);
+ }
+
+ }, true);
+ tree.startup();
+ updater.add( treeModel );
+ });
+
+ return TreeViewModel;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/management.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/management.html
new file mode 100644
index 0000000000..a8345a8503
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/management.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<!--
+ ~ 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.
+ -->
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Qpid Management</title>
+ <link rel="stylesheet" href="dojo/dojo/resources/dojo.css">
+ <link rel="stylesheet" href="dojo/dijit/themes/claro/claro.css">
+ <link rel="stylesheet" href="dojo/dojox/grid/resources/claroGrid.css">
+ <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="css/common.css" media="screen">
+ <script>
+ function getContextPath()
+ {
+ var contextPath = "/";
+ var documentURL = document.URL;
+ var managementPageStart = documentURL.lastIndexOf("/");
+ var firstSlashPos = documentURL.indexOf("/", documentURL.indexOf("//") + 2);
+ if (managementPageStart > firstSlashPos)
+ {
+ contextPath = documentURL.substring(firstSlashPos, managementPageStart);
+ }
+ return contextPath;
+ }
+
+ var dojoConfig = {
+ tlmSiblingOfDojo:false,
+ parseOnLoad:true,
+ async:true,
+ baseUrl: getContextPath(),
+ packages:[
+ { name:"dojo", location:"dojo/dojo" },
+ { name:"dijit", location:"dojo/dijit" },
+ { name:"dojox", location:"dojo/dojox" },
+ { name:"qpid", location:"js/qpid" }
+ ]
+ };
+
+ </script>
+ <script src="dojo/dojo/dojo.js">
+ </script>
+
+ <script>
+ require(["dijit/layout/BorderContainer",
+ "dijit/layout/TabContainer",
+ "dijit/layout/ContentPane",
+ "dijit/TitlePane",
+ "dojo/parser",
+ "qpid/management/treeView",
+ "qpid/management/controller",
+ "qpid/common/footer",
+ "qpid/authorization/sasl"]);
+ </script>
+
+</head>
+<body class="claro">
+
+<div id="pageLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline', gutters: false">
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'">
+ <div id="header" class="header"></div>
+ </div>
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'">
+ <div id="login"></div>
+ </div>
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'leading', splitter: true">
+ <div qpid-type="treeView" qpid-props="query: 'rest/structure'" ></div>
+ </div>
+ <div id="managedViews" data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region:'center', tabPosition: 'top'">
+ </div>
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'bottom'">
+ <div qpid-type="footer"></div>
+ </div>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/moveCopyMessages.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/moveCopyMessages.html
new file mode 100644
index 0000000000..f188c3001c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/moveCopyMessages.html
@@ -0,0 +1,36 @@
+<!--
+ ~ 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.
+ -->
+
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Move/Copy Messages'" id="moveMessages">
+ <form id="formMoveMessages" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Queue: </strong></td>
+ <td><div id="moveMessages.selectQueueDiv"></div></td>
+ </tr>
+ </table>
+ <br/>
+
+ <!-- submit buttons -->
+
+ <input type="button" value="Cancel" label="Cancel" dojoType="dijit.form.Button" class="moveMessageCancel"/>
+ <input type="submit" value="Move Messages" label="Move Messages" dojoType="dijit.form.Button" />
+
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html
new file mode 100644
index 0000000000..c5d4e48a75
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html
@@ -0,0 +1,25 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="authorizationProvider">
+ <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span>
+ <br/>
+ <span style="">Type:</span><span class="type" style="position:absolute; left:6em"></span>
+</div> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
new file mode 100644
index 0000000000..cb2f4a4b9a
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
@@ -0,0 +1,25 @@
+<div class="broker">
+ <span>Broker:</span><span class="broker-name" style="position:absolute; left:6em"></span>
+ <br/>
+<!-- <span>State:</span><span class="broker-state" style="position:absolute; left:6em"></span>
+ <br/>
+ <span>Durable:</span><span class="broker-durable" style="position:absolute; left:6em"></span>
+ <br/>
+ <span>Lifespan:</span><span class="broker-lifetimePolicy" style="position:absolute; left:6em" ></span>
+ <br/> -->
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Virtual Hosts'">
+ <div class="broker-virtualhosts"></div>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Ports'">
+ <div class="broker-ports"></div>
+ </div>
+ <br/>
+
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Log File', open: false">
+ <div class="broker-logfile"></div>
+ </div>
+ <br/>
+</div>
+
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html
new file mode 100644
index 0000000000..84854daf47
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html
@@ -0,0 +1,47 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="connection">
+ <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span>
+ <br/>
+ <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span>
+ <span style="position:absolute; left:26em">Pre-fetched:</span>
+ <br/>
+ <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span>
+ <span style="position:absolute; left:26em">Inbound:</span>
+ <span class="msgInRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesInRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span>
+ <span style="position:absolute; left:26em">Outbound:</span>
+ <span class="msgOutRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesOutRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesOutRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Sessions'">
+ <div class="sessions"></div>
+ </div>
+ <br/>
+
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showExchange.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showExchange.html
new file mode 100644
index 0000000000..64f351d218
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showExchange.html
@@ -0,0 +1,46 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="exchange">
+ <span style="">Exchange:</span><span class="name" style="position:absolute; left:6em"></span>
+ <br/>
+ <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span>
+ <br/>
+ <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span>
+ <span style="position:absolute; left:26em">Inbound:</span>
+ <span class="msgInRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesInRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span>
+ <span style="position:absolute; left:26em">Dropped:</span>
+ <span class="msgDropRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesDropRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesDropRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Bindings'">
+ <div class="bindings"></div>
+ <button data-dojo-type="dijit.form.Button" class="addBindingButton">Add Binding</button>
+ </div>
+ <br/>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html
new file mode 100644
index 0000000000..0dea508c60
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html
@@ -0,0 +1,73 @@
+<!--
+ ~ 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.
+ -->
+
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'View Message'" id="showMessage">
+
+ <table style="border: 0;">
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Message Number:</span></td>
+ <td><span class="message-id"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Message Id:</span></td>
+ <td><span class="message-messageId"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">State:</span></td>
+ <td><span class="message-state"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Persistent:</span></td>
+ <td><span class="message-persistent boolean"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Priority:</span></td>
+ <td><span class="message-priority"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Arrival Time:</span>
+ </td><td><span class="message-arrivalTime datetime"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Expiration:</span></td>
+ <td><span class="message-expiration datetime"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">MIME Type:</span></td>
+ <td><span class="message-mimeType"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">User:</span></td>
+ <td><span class="message-userId"></span></td>
+ </tr>
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Headers:</span></td>
+ <td><div class="message-headers map"></div></td>
+ </tr>
+
+ <tr style="margin-bottom: 4pt">
+ <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Content:</span></td>
+ <td><div class="message-content"></div></td>
+ </tr>
+ </table>
+ <br/>
+ <input type="button" value="Close" label="Close" dojoType="dijit.form.Button" class="closeViewMessage"/>
+
+ </div>
+</div>
+
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html
new file mode 100644
index 0000000000..c87a462760
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html
@@ -0,0 +1,97 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="queue">
+ <span style="">Queue:</span><span class="name" style="position:absolute; left:6em"></span>
+ <span style="position:absolute; left:26em">Size:</span>
+ <span class="queueDepthMessages" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msgs</span>
+ <span class="queueDepthBytes" style="position:absolute; right: 3.3em">(</span>
+ <span class="queueDepthBytesUnits" style="position:absolute; right: 0em; width: 3em">)</span>
+ <br/>
+ <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span>
+ <span style="position:absolute; left:26em">Pre-fetched:</span>
+ <span class="unacknowledgedMessages" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msgs</span>
+ <span class="unacknowledgedBytes" style="position:absolute; right: 3.3em"></span>
+ <span class="unacknowledgedBytesUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span>
+ <span style="position:absolute; left:26em">Inbound:</span>
+ <span class="msgInRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesInRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span>
+ <span style="position:absolute; left:26em">Outbound:</span>
+ <span class="msgOutRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesOutRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesOutRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Bindings'">
+ <div class="bindings"></div>
+ <button data-dojo-type="dijit.form.Button" class="addBindingButton" type="button">Add Binding</button>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Consumers'">
+ <div class="consumers"></div>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Messages'">
+ <div class="messages"></div>
+ <button data-dojo-type="dijit.form.Button" class="deleteMessagesButton" type="button">Delete Messages</button>
+ <button data-dojo-type="dijit.form.Button" class="moveMessagesButton" type="button">Move Messages</button>
+ <button data-dojo-type="dijit.form.Button" class="copyMessagesButton" type="button">Copy Messages</button>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Thresholds', open: false">
+ <span style="">Max. Queue Size:</span>
+ <span class="alertThresholdQueueDepthMessages"
+ style="position:absolute; left:8em; width:8em; text-align:right"></span>
+ <span style="position:absolute; left:16.2em">msgs</span>
+
+ <span class="alertThresholdQueueDepthBytes"
+ style="position:absolute; left:20em; width:8em; text-align:right"></span>
+ <span class="alertThresholdQueueDepthBytesUnits" style="position:absolute; left:28.2em"></span>
+ <br>
+ <span style="">Max. Message Age:</span>
+ <span class="alertThresholdMessageAge"
+ style="position:absolute; left:8em; width:8em; text-align:right"></span>
+ <span class="alertThresholdMessageAgeUnits" style="position:absolute; left:16.2em"></span>
+
+ <span style="position:absolute; left:21em">Size: </span>
+ <span class="alertThresholdMessageSize"
+ style="position:absolute; left:23em; width:5em; text-align:right"></span>
+ <span class="alertThresholdMessageSizeUnits" style="position:absolute; left:28.2em"></span>
+ <br/>
+ <br/>
+ <span style="">Alert frequency:</span>
+ <span class="alertRepeatGap"
+ style="position:absolute; left:8em; width:8em; text-align:right"></span>
+ <span class="alertRepeatGapUnits" style="position:absolute; left:16.2em"></span>
+
+
+
+ </div>
+</div>
+
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
new file mode 100644
index 0000000000..9d16d523d6
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<!--
+ -
+ - 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.
+ -
+ -->
+
+<div class="virtualhost">
+ <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span>
+ <br/>
+ <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span>
+ <br/>
+ <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span>
+ <span style="position:absolute; left:26em">Inbound:</span>
+ <span class="msgInRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesInRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span>
+ <span style="position:absolute; left:26em">Outbound:</span>
+ <span class="msgOutRate" style="position:absolute; right:9.5em"></span>
+ <span style="position:absolute; right: 5em; width: 4em"> msg/s</span>
+ <span class="bytesOutRate" style="position:absolute; right: 3.3em"></span>
+ <span class="bytesOutRateUnits" style="position:absolute; right: 0em; width: 3em"></span>
+ <br/>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Exchanges'">
+ <div class="exchanges"></div>
+ <button data-dojo-type="dijit.form.Button" class="addExchangeButton">Add Exchange</button>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Queues'">
+ <div class="queues"></div>
+ <button data-dojo-type="dijit.form.Button" class="addQueueButton">Add Queue</button>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Connections'">
+ <div class="connections"></div>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Thresholds', open: false">
+ <span style="">Max. Queue Size:</span>
+ <span class="alertThresholdQueueDepthMessages"
+ style="position:absolute; left:8em; width:8em; text-align:right"></span>
+ <span style="position:absolute; left:16.2em">msgs</span>
+
+ <span class="alertThresholdQueueDepthBytes"
+ style="position:absolute; left:20em; width:8em; text-align:right"></span>
+ <span class="alertThresholdQueueDepthBytesUnits" style="position:absolute; left:28.2em"></span>
+ <br>
+ <span style="">Max. Message Age:</span>
+ <span class="alertThresholdMessageAge"
+ style="position:absolute; left:8em; width:8em; text-align:right"></span>
+ <span class="alertThresholdMessageAgeUnits" style="position:absolute; left:16.2em"></span>
+
+ <span style="position:absolute; left:21em">Size: </span>
+ <span class="alertThresholdMessageSize"
+ style="position:absolute; left:23em; width:5em; text-align:right"></span>
+ <span class="alertThresholdMessageSizeUnits" style="position:absolute; left:28.2em"></span>
+ <br/>
+ <br/>
+ <span style="">Alert frequency:</span>
+ <span class="alertRepeatGap"
+ style="position:absolute; left:8em; width:8em; text-align:right"></span>
+ <span class="alertRepeatGapUnits" style="position:absolute; left:16.2em"></span>
+ </div>
+</div>
+