summaryrefslogtreecommitdiff
path: root/java/broker-plugins/management-http/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/broker-plugins/management-http/src')
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java248
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java73
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java77
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java79
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java109
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java208
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java118
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java208
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java53
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java85
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java74
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java176
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java502
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java586
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java256
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java103
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/addBinding.html42
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/addExchange.html54
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/addQueue.html182
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/addUser.html42
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/setPassword.html42
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html29
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/css/common.css92
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/footer.html28
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.pngbin0 -> 6600 bytes
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js213
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js110
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/footer.js30
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/formatter.js99
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/properties.js26
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/updater.js45
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js120
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js122
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js205
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js213
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js291
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js485
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js378
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js223
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js146
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js191
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js327
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js104
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/moveCopyMessages.js137
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js142
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js313
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/management.html92
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/moveCopyMessages.html36
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html25
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showBroker.html25
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showConnection.html47
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showExchange.html50
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showMessage.html73
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showQueue.html103
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html87
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/Asserts.java249
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java53
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java109
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java86
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java118
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java213
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java67
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java42
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java354
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java41
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java245
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java225
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java22
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java115
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java92
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java434
71 files changed, 10389 insertions, 0 deletions
diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java
new file mode 100644
index 0000000000..c2f9b73b54
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java
@@ -0,0 +1,248 @@
+/*
+ *
+ * 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.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.configuration.ConfigurationException;
+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.LogRecordsServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.MessageContentServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.MessageServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.RestServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.SaslServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.StructureServlet;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.Session;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.server.ssl.SslSocketConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+public class Management
+{
+
+ private final Logger _logger = Logger.getLogger(Management.class);
+
+ private Broker _broker;
+
+ private Collection<Server> _servers = new ArrayList<Server>();
+
+ public Management() throws ConfigurationException, IOException
+ {
+ _broker = ApplicationRegistry.getInstance().getBroker();
+
+ Collection<Port> ports = _broker.getPorts();
+ int httpPort = -1, httpsPort = -1;
+ for (Port port : ports)
+ {
+ if (port.getProtocols().contains(Protocol.HTTP))
+ {
+ if (port.getTransports().contains(Transport.TCP))
+ {
+ httpPort = port.getPort();
+ }
+ }
+ if (port.getProtocols().contains(Protocol.HTTPS))
+ {
+ if (port.getTransports().contains(Transport.SSL))
+ {
+ httpsPort = port.getPort();
+ }
+ }
+ }
+
+ if (httpPort != -1 || httpsPort != -1)
+ {
+ _servers.add(createServer(httpPort, httpsPort));
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug(_servers.size() + " server(s) defined");
+ }
+ }
+ else
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Cannot create web server as neither HTTP nor HTTPS port specified");
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Server createServer(int port, int sslPort) throws IOException, ConfigurationException
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Starting up web server on" + (port == -1 ? "" : " HTTP port " + port)
+ + (sslPort == -1 ? "" : " HTTPS port " + sslPort));
+ }
+
+ Server server = new Server();
+
+ if (port != -1)
+ {
+ SelectChannelConnector connector = new SelectChannelConnector();
+ connector.setPort(port);
+ if (sslPort != -1)
+ {
+ connector.setConfidentialPort(sslPort);
+ }
+ server.addConnector(connector);
+ }
+
+ if (sslPort != -1)
+ {
+ IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
+ String keyStorePath = getKeyStorePath(appRegistry);
+
+ SslContextFactory factory = new SslContextFactory();
+ factory.setKeyStorePath(keyStorePath);
+ factory.setKeyStorePassword(appRegistry.getConfiguration().getManagementKeyStorePassword());
+
+ SslSocketConnector connector = new SslSocketConnector(factory);
+ connector.setPort(sslPort);
+ server.addConnector(connector);
+ }
+
+ 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");
+ addRestServlet(root, "virtualhost", VirtualHost.class);
+ addRestServlet(root, "authenticationprovider", AuthenticationProvider.class);
+ addRestServlet(root, "user", AuthenticationProvider.class, User.class);
+ addRestServlet(root, "exchange", VirtualHost.class, Exchange.class);
+ addRestServlet(root, "queue", VirtualHost.class, Queue.class);
+ addRestServlet(root, "connection", VirtualHost.class, Connection.class);
+ addRestServlet(root, "binding", VirtualHost.class, Exchange.class, Queue.class, Binding.class);
+ addRestServlet(root, "port", Port.class);
+ addRestServlet(root, "session", VirtualHost.class, Connection.class, Session.class);
+
+ root.addServlet(new ServletHolder(new StructureServlet(_broker)), "/rest/structure");
+ root.addServlet(new ServletHolder(new MessageServlet(_broker)), "/rest/message/*");
+ root.addServlet(new ServletHolder(new MessageContentServlet(_broker)), "/rest/message-content/*");
+
+ root.addServlet(new ServletHolder(new LogRecordsServlet(_broker)), "/rest/logrecords");
+
+ root.addServlet(new ServletHolder(new SaslServlet(_broker)), "/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, Class<? extends ConfiguredObject>... hierarchy)
+ {
+ root.addServlet(new ServletHolder(new RestServlet(_broker, 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();
+ }
+ }
+
+ private String getKeyStorePath(IApplicationRegistry appRegistry) throws ConfigurationException, FileNotFoundException
+ {
+ String keyStorePath = null;
+ if (System.getProperty("javax.net.ssl.keyStore") != null)
+ {
+ keyStorePath = System.getProperty("javax.net.ssl.keyStore");
+ }
+ else
+ {
+ keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath();
+ }
+
+ if (keyStorePath == null)
+ {
+ throw new ConfigurationException("Management SSL keystore path not defined, unable to start SSL protected HTTP connector");
+ }
+ else
+ {
+ File ksf = new File(keyStorePath);
+ if (!ksf.exists())
+ {
+ throw new FileNotFoundException("Cannot find management SSL keystore file: " + ksf);
+ }
+ if (!ksf.canRead())
+ {
+ throw new FileNotFoundException("Cannot read management SSL keystore file: " + ksf + ". Check permissions.");
+ }
+ }
+ return keyStorePath;
+ }
+
+}
diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java
new file mode 100644
index 0000000000..09b7e08bfb
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java
@@ -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.
+ *
+ */
+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()
+ && !ApplicationRegistry.getInstance().getConfiguration().getHTTPSManagementEnabled())
+ {
+ _logger.info("Management plugin is disabled!");
+ 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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java b/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/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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java b/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/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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java b/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/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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java b/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/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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java b/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/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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
new file mode 100644
index 0000000000..a76bd98179
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.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.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;
+
+ protected AbstractServlet()
+ {
+ super();
+ _broker = ApplicationRegistry.getInstance().getBroker();
+ }
+
+ protected AbstractServlet(Broker broker)
+ {
+ _broker = broker;
+ }
+
+ @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)
+ {
+ return InetSocketAddress.createUnresolved(request.getServerName(), request.getServerPort());
+ }
+}
diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java b/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/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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
new file mode 100644
index 0000000000..404793b592
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
@@ -0,0 +1,85 @@
+/*
+ * 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.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());
+ }
+
+ public LogRecordsServlet(Broker broker)
+ {
+ super(broker);
+ }
+
+ @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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java b/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/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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java
new file mode 100644
index 0000000000..bc87f0bcc5
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java
@@ -0,0 +1,176 @@
+/*
+ * 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.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)
+ {
+ super(broker);
+ }
+
+ @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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
new file mode 100644
index 0000000000..6e7bc1d935
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
@@ -0,0 +1,502 @@
+/*
+ * 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.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)
+ {
+ super(broker);
+ }
+
+ @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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
new file mode 100644
index 0000000000..593377beed
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
@@ -0,0 +1,586 @@
+/**
+ * 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.log4j.Logger;
+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
+{
+ private static final Logger LOGGER = Logger.getLogger(RestServlet.class);
+ /**
+ * 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, Class<? extends ConfiguredObject>... hierarchy)
+ {
+ super(broker);
+ _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 instanceof ConfiguredObject)
+ {
+ object.put(name, ((ConfiguredObject) value).getName());
+ }
+ else 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
+ {
+ LOGGER.warn("Unexpected exception is caught", e);
+
+ // 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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
new file mode 100644
index 0000000000..1b78611a50
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
@@ -0,0 +1,256 @@
+/*
+ *
+ * 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.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)
+ {
+ super(broker);
+ }
+
+ 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());
+ }
+ else if (request.getRemoteUser() != null)
+ {
+ outputObject.put("user", request.getRemoteUser());
+ }
+
+ 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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
new file mode 100644
index 0000000000..e4ba374f89
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
@@ -0,0 +1,103 @@
+/**
+ * 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.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)
+ {
+ super(broker);
+ }
+
+ @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/java/broker-plugins/management-http/src/main/java/resources/addBinding.html b/java/broker-plugins/management-http/src/main/java/resources/addBinding.html
new file mode 100644
index 0000000000..8dbd219c8d
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/addExchange.html b/java/broker-plugins/management-http/src/main/java/resources/addExchange.html
new file mode 100644
index 0000000000..10ac5388ff
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/addExchange.html
@@ -0,0 +1,54 @@
+<!--
+ -
+ - 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"
+ data-dojo-props="regExp:'^(?!qpid\.|amq\.|\<\<default\>\>).*$', invalidMessage:'Reserved exchange name!'"/></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/java/broker-plugins/management-http/src/main/java/resources/addQueue.html b/java/broker-plugins/management-http/src/main/java/resources/addQueue.html
new file mode 100644
index 0000000000..d396f28877
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/addQueue.html
@@ -0,0 +1,182 @@
+<!--
+ -
+ - 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="priorities" value="10" 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" required="false"
+ 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]+"
+ 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]+"
+ 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">
+ <!-- x-qpid-maximum-message-count -->
+ <tr>
+ <td valign="top"><strong>Queue Depth: </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-maximum-message-age -->
+ <tr>
+ <td valign="top"><strong>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]+"
+ invalidMessage= "Invalid value" /></td>
+ </tr>
+ <!-- x-qpid-maximum-message-size -->
+ <tr>
+ <td valign="top"><strong>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]+"
+ 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]+"
+ 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>
+ <tr>
+ <td valign="top"><strong>Create DLQ? </strong></td>
+ <td><input type="checkbox" name="dlqEnabled" id="formAddQueue.dlqEnabled" value="dlqEnabled" dojoType="dijit.form.CheckBox" /></td>
+ </tr>
+ </table>
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top">NOTE: Configuring maximum delivery retries on a queue which has no DLQ / AlternateExchange will result in messages being discarded after the limit is reached.</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/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/addUser.html b/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/addUser.html
new file mode 100644
index 0000000000..785605f694
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/setPassword.html b/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/setPassword.html
new file mode 100644
index 0000000000..3d67463abd
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html b/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html
new file mode 100644
index 0000000000..baadc8c35f
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/css/common.css b/java/broker-plugins/management-http/src/main/java/resources/css/common.css
new file mode 100644
index 0000000000..78780edcd9
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/footer.html b/java/broker-plugins/management-http/src/main/java/resources/footer.html
new file mode 100644
index 0000000000..fa84825e80
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png b/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png
new file mode 100644
index 0000000000..95d49ea469
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png
Binary files differ
diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js
new file mode 100644
index 0000000000..152504da86
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js
new file mode 100644
index 0000000000..f7ede1a7f7
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/footer.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/footer.js
new file mode 100644
index 0000000000..ea13b1fc53
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/formatter.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/formatter.js
new file mode 100644
index 0000000000..2f8683ee1c
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/properties.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/properties.js
new file mode 100644
index 0000000000..8d85345b74
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/updater.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/updater.js
new file mode 100644
index 0000000000..86bbaa46ba
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
new file mode 100644
index 0000000000..08fdf5c99b
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
@@ -0,0 +1,120 @@
+/*
+ *
+ * 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"],
+ function (xhr) {
+ 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] );
+ }
+ }
+ }
+ }
+ };
+
+ util.isReservedExchangeName = function(exchangeName)
+ {
+ return exchangeName == null || exchangeName == "" || "<<default>>" == exchangeName || exchangeName.indexOf("amq.") == 0 || exchangeName.indexOf("qpid.") == 0;
+ };
+
+ util.deleteGridSelections = function(updater, gridName, url, confirmationMessageStart)
+ {
+ var grid = updater[gridName].grid;
+ var data = grid.selection.getSelected();
+ if(data.length)
+ {
+ var confirmationMessage = null;
+ if (data.length == 1)
+ {
+ confirmationMessage = confirmationMessageStart + " '" + data[0].name + "'?";
+ }
+ else
+ {
+ var names = '';
+ for(var i = 0; i<data.length; i++)
+ {
+ if (names)
+ {
+ names += ', ';
+ }
+ names += "\""+ data[i].name + "\"";
+ }
+ confirmationMessage = confirmationMessageStart + "s " + names + "?";
+ }
+ if(confirm(confirmationMessage))
+ {
+ var i, queryParam;
+ for(i = 0; i<data.length; i++)
+ {
+ if(queryParam)
+ {
+ queryParam += "&";
+ }
+ else
+ {
+ queryParam = "?";
+ }
+ queryParam += "id=" + data[i].id;
+ }
+ var query = url + queryParam;
+ var success = true
+ var failureReason = "";
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data)
+ {
+ grid.setQuery({id: "*"});
+ grid.selection.deselectAll();
+ updater.update();
+ },
+ function(error) {success = false; failureReason = error;});
+ if(!success )
+ {
+ alert("Error:" + failureReason);
+ }
+ }
+ }
+ }
+
+ return util;
+ }); \ No newline at end of file
diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js
new file mode 100644
index 0000000000..7613fd5d71
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
new file mode 100644
index 0000000000..dcf6711073
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js
new file mode 100644
index 0000000000..01f9a325c5
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js
new file mode 100644
index 0000000000..37bae1ef8e
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js
@@ -0,0 +1,291 @@
+/*
+ *
+ * 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",
+ "dojox/grid/EnhancedGrid",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, registry, properties, updater, util, formatter, UpdatableStore, addBinding, EnhancedGrid) {
+
+ 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()});
+ });
+
+ var deleteBindingButton = query(".deleteBindingButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(deleteBindingButton), "onClick",
+ function(evt){
+ that.deleteBindings();
+ });
+
+ var isStandard = util.isReservedExchangeName(that.name);
+ var deleteExchangeButton = query(".deleteExchangeButton", contentPane.containerNode)[0];
+ var node = registry.byNode(deleteExchangeButton);
+ if(isStandard)
+ {
+ node.set('disabled', true);
+ }
+ else
+ {
+ connect.connect(node, "onClick",
+ function(evt){
+ that.deleteExchange();
+ });
+ }
+
+ }});
+ };
+
+ Exchange.prototype.close = function() {
+ updater.remove( this.exchangeUpdater );
+ };
+
+ Exchange.prototype.deleteBindings = function()
+ {
+ util.deleteGridSelections(
+ this.exchangeUpdater,
+ "bindingsGrid",
+ "rest/binding/"+ encodeURIComponent(this.getVirtualHostName()) + "/" + encodeURIComponent(this.name),
+ "Are you sure you want to delete binding for queue");
+ }
+
+ 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%"}
+ ], null, {
+ keepSelection: true,
+ plugins: {
+ pagination: {
+ pageSizes: ["10", "25", "50", "100"],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ indirectSelection: true
+
+ }}, EnhancedGrid);
+
+ });
+
+ }
+
+ 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)
+
+ });
+ };
+
+ Exchange.prototype.deleteExchange = function() {
+ if(confirm("Are you sure you want to delete exchange '" +this.name+"'?")) {
+ var query = "rest/exchange/"+ encodeURIComponent(this.getVirtualHostName()) + "/" + encodeURIComponent(this.name);
+ this.success = true
+ var that = this;
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ that.contentPane.onClose()
+ that.controller.tabContainer.removeChild(that.contentPane);
+ that.contentPane.destroyRecursive();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!this.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+ }
+
+ return Exchange;
+ });
diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js
new file mode 100644
index 0000000000..8b332dbf92
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js
@@ -0,0 +1,485 @@
+/*
+ *
+ * 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()});
+ });
+
+ var deleteQueueButton = query(".deleteQueueButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(deleteQueueButton), "onClick",
+ function(evt){
+ event.stop(evt);
+ that.deleteQueue();
+ });
+ }});
+
+
+
+ };
+
+ 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 );
+ };
+
+ var queueTypeKeys = {
+ priority: "priorities",
+ lvq: "lvqKey",
+ sorted: "sortKey"
+ };
+
+ var queueTypeKeyNames = {
+ priority: "Number of priorities",
+ lvq: "LVQ key",
+ sorted: "Sort key"
+ };
+
+ 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",
+ "type",
+ "typeQualifier",
+ "alertRepeatGap",
+ "alertRepeatGapUnits",
+ "alertThresholdMessageAge",
+ "alertThresholdMessageAgeUnits",
+ "alertThresholdMessageSize",
+ "alertThresholdMessageSizeUnits",
+ "alertThresholdQueueDepthBytes",
+ "alertThresholdQueueDepthBytesUnits",
+ "alertThresholdQueueDepthMessages",
+ "alternateExchange",
+ "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.alternateExchange.innerHTML = this.queueData[ "alternateExchange" ] ? this.queueData[ "alternateExchange" ]: "" ;
+
+ 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 + ")";
+ this.type.innerHTML = this.queueData[ "type" ];
+ if (this.queueData.type == "standard")
+ {
+ this.typeQualifier.style.display = "none";
+ }
+ else
+ {
+ this.typeQualifier.innerHTML = "(" + queueTypeKeyNames[this.queueData.type] + ": " + this.queueData[queueTypeKeys[this.queueData.type]] + ")";
+ }
+
+ };
+
+ 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)
+
+ });
+ };
+
+ Queue.prototype.deleteQueue = function() {
+ if(confirm("Are you sure you want to delete queue '" +this.name+"'?")) {
+ var query = "rest/queue/"+ encodeURIComponent(this.getVirtualHostName()) + "/" + encodeURIComponent(this.name);
+ this.success = true
+ var that = this;
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ that.contentPane.onClose()
+ that.controller.tabContainer.removeChild(that.contentPane);
+ that.contentPane.destroyRecursive();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!this.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+ }
+
+ return Queue;
+ });
diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
new file mode 100644
index 0000000000..957f2381cf
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
@@ -0,0 +1,378 @@
+/*
+ *
+ * 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",
+ "dojox/grid/EnhancedGrid",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, registry, properties, updater, util, formatter, UpdatableStore, addQueue, addExchange, EnhancedGrid) {
+
+ 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 deleteQueueButton = query(".deleteQueueButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(deleteQueueButton), "onClick",
+ function(evt){
+ util.deleteGridSelections(
+ that.vhostUpdater,
+ "queuesGrid",
+ "rest/queue/"+ encodeURIComponent(that.name),
+ "Are you sure you want to delete queue");
+ }
+ );
+
+ var addExchangeButton = query(".addExchangeButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addExchangeButton), "onClick", function(evt){ addExchange.show(that.name) });
+
+ var deleteExchangeButton = query(".deleteExchangeButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(deleteExchangeButton), "onClick",
+ function(evt)
+ {
+ util.deleteGridSelections(
+ that.vhostUpdater,
+ "exchangesGrid",
+ "rest/exchange/"+ encodeURIComponent(that.name),
+ "Are you sure you want to delete exchange");
+ }
+ );
+ }});
+
+ };
+
+ 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 );
+
+ var gridProperties = {
+ keepSelection: true,
+ plugins: {
+ pagination: {
+ pageSizes: ["10", "25", "50", "100"],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ indirectSelection: true
+
+ }};
+
+ 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);
+ });
+ } , gridProperties, EnhancedGrid);
+
+ 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);
+ });
+ } , gridProperties, EnhancedGrid);
+
+
+ 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);
+
+ var exchangesGrid = thisObj.exchangesGrid.grid;
+ for(var i=0; i< thisObj.vhostData.exchanges.length; i++)
+ {
+ var data = exchangesGrid.getItem(i);
+ var isStandard = false;
+ if (data && data.name)
+ {
+ isStandard = util.isReservedExchangeName(data.name);
+ }
+ exchangesGrid.rowSelectCell.setDisabled(i, isStandard);
+ }
+
+ // update connections
+ thisObj.connectionsGrid.update(thisObj.vhostData.connections)
+
+
+ });
+ };
+
+
+ return VirtualHost;
+ }); \ No newline at end of file
diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js
new file mode 100644
index 0000000000..83e724d0e9
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js
new file mode 100644
index 0000000000..915092a9d1
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addExchange.js
@@ -0,0 +1,146 @@
+/*
+ *
+ * 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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js
new file mode 100644
index 0000000000..53f82aff48
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js
@@ -0,0 +1,191 @@
+/*
+ *
+ * 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 = {
+ priorities: "priority",
+ lvqKey: "lvq",
+ sortKey: "sorted"
+ };
+
+ var requiredFields = {
+ priority: "priorities",
+ sorted: "sortkey"
+ };
+
+ var fieldConverters = {
+ queueFlowControlSizeBytes: parseInt,
+ queueFlowResumeSizeBytes: parseInt,
+ alertThresholdMessageSize: parseInt,
+ alertThresholdQueueDepthMessages: parseInt,
+ maximumDeliveryAttempts: parseInt,
+ alertThresholdMessageAge: parseInt,
+ alertRepeatGap: parseInt
+ }
+
+ 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(propName === "dlqEnabled")
+ {
+ if (formValues.dlqEnabled[0] && formValues.dlqEnabled[0] == "dlqEnabled") {
+ newQueue["x-qpid-dlq-enabled"] = true;
+ }
+ }
+ else if (!typeSpecificFields.hasOwnProperty(propName) ||
+ formValues.type === typeSpecificFields[ propName ]) {
+ if(formValues[ propName ] !== "") {
+ if (fieldConverters.hasOwnProperty(propName))
+ {
+ newQueue[ propName ] = fieldConverters[propName](formValues[propName]);
+ }
+ else
+ {
+ 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 objId = widget.id + ":fields";
+ var obj = registry.byId(objId);
+ if(obj) {
+ if(isChecked) {
+ obj.domNode.style.display = "block";
+ } else {
+ obj.domNode.style.display = "none";
+ }
+ obj.resize();
+ var widgetValue = widget.value;
+ if (requiredFields.hasOwnProperty(widgetValue))
+ {
+ dijit.byId('formAddQueue.' + requiredFields[widgetValue]).required = isChecked;
+ }
+ }
+ })
+ }
+
+ });
+
+ 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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js
new file mode 100644
index 0000000000..8e5ac862bd
--- /dev/null
+++ b/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(that.success === true) {
+ registry.byId("addUser").hide();
+ } else {
+ alert("Error:" + that.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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
new file mode 100644
index 0000000000..1aa05a5a3c
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/moveCopyMessages.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/moveCopyMessages.js
new file mode 100644
index 0000000000..8cc488324f
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
new file mode 100644
index 0000000000..b1ccc0ca07
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
new file mode 100644
index 0000000000..b1d4abf8c1
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/management.html b/java/broker-plugins/management-http/src/main/java/resources/management.html
new file mode 100644
index 0000000000..a8345a8503
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/moveCopyMessages.html b/java/broker-plugins/management-http/src/main/java/resources/moveCopyMessages.html
new file mode 100644
index 0000000000..f188c3001c
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html b/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html
new file mode 100644
index 0000000000..c5d4e48a75
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/showBroker.html b/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
new file mode 100644
index 0000000000..a39e334c40
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
@@ -0,0 +1,25 @@
+<div class="broker">
+ <span>Name:</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/java/broker-plugins/management-http/src/main/java/resources/showConnection.html b/java/broker-plugins/management-http/src/main/java/resources/showConnection.html
new file mode 100644
index 0000000000..84854daf47
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/showExchange.html b/java/broker-plugins/management-http/src/main/java/resources/showExchange.html
new file mode 100644
index 0000000000..f33b029026
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/showExchange.html
@@ -0,0 +1,50 @@
+<!--
+ -
+ - 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="">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">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>
+ <button data-dojo-type="dijit.form.Button" class="deleteBindingButton">Delete Binding</button>
+ </div>
+ <br/>
+ <div class="dijitDialogPaneActionBar">
+ <button data-dojo-type="dijit.form.Button" class="deleteExchangeButton" type="button">Delete Exchange</button>
+ </div>
+</div>
diff --git a/java/broker-plugins/management-http/src/main/java/resources/showMessage.html b/java/broker-plugins/management-http/src/main/java/resources/showMessage.html
new file mode 100644
index 0000000000..0dea508c60
--- /dev/null
+++ b/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/java/broker-plugins/management-http/src/main/java/resources/showQueue.html b/java/broker-plugins/management-http/src/main/java/resources/showQueue.html
new file mode 100644
index 0000000000..929e1d1f23
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/showQueue.html
@@ -0,0 +1,103 @@
+<!--
+ -
+ - 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="">Name:</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/>
+ <span style="">AlternateExchange:</span><span class="alternateExchange" style="position:absolute; left:10em"></span>
+ <span style="position:absolute; left:26em">Type:</span><span style="position:absolute; left:29em" class="type"></span>
+ <span style="position:absolute; right:1em" class="typeQualifier"></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="">Queue Depth:</span>
+ <span class="alertThresholdQueueDepthMessages"
+ style="position:absolute; left:4em; width:8em; text-align:right"></span>
+ <span style="position:absolute; left:12.2em">msgs</span>
+
+ <span style="position:absolute; left:21em">Queue Depth:</span>
+ <span class="alertThresholdQueueDepthBytes"
+ style="position:absolute; left:22em; width:8em; text-align:right"></span>
+ <span class="alertThresholdQueueDepthBytesUnits" style="position:absolute; left:30.2em"></span>
+ <br>
+ <span style="">Message Age:</span>
+ <span class="alertThresholdMessageAge"
+ style="position:absolute; left:4em; width:8em; text-align:right"></span>
+ <span class="alertThresholdMessageAgeUnits" style="position:absolute; left:12.2em"></span>
+
+ <span style="position:absolute; left:21em">Message Size: </span>
+ <span class="alertThresholdMessageSize"
+ style="position:absolute; left:25em; width:5em; text-align:right"></span>
+ <span class="alertThresholdMessageSizeUnits" style="position:absolute; left:30.2em"></span>
+ <br/>
+ <br/>
+ <span style="">Alert frequency:</span>
+ <span class="alertRepeatGap"
+ style="position:absolute; left:4em; width:8em; text-align:right"></span>
+ <span class="alertRepeatGapUnits" style="position:absolute; left:12.2em"></span>
+ </div>
+
+ <div class="dijitDialogPaneActionBar">
+ <button data-dojo-type="dijit.form.Button" class="deleteQueueButton" type="button">Delete Queue</button>
+ </div>
+</div>
+
diff --git a/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html b/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html
new file mode 100644
index 0000000000..73c912e0d4
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/resources/showVirtualHost.html
@@ -0,0 +1,87 @@
+<!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>
+ <button data-dojo-type="dijit.form.Button" class="deleteExchangeButton">Delete 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>
+ <button data-dojo-type="dijit.form.Button" class="deleteQueueButton">Delete 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="">Queue Depth:</span>
+ <span class="alertThresholdQueueDepthMessages"
+ style="position:absolute; left:4em; width:8em; text-align:right"></span>
+ <span style="position:absolute; left:12.2em">msgs</span>
+
+ <span style="position:absolute; left:21em">Queue Depth:</span>
+ <span class="alertThresholdQueueDepthBytes"
+ style="position:absolute; left:22em; width:8em; text-align:right"></span>
+ <span class="alertThresholdQueueDepthBytesUnits" style="position:absolute; left:30.2em"></span>
+ <br>
+ <span style="">Message Age:</span>
+ <span class="alertThresholdMessageAge"
+ style="position:absolute; left:4em; width:8em; text-align:right"></span>
+ <span class="alertThresholdMessageAgeUnits" style="position:absolute; left:12.2em"></span>
+
+ <span style="position:absolute; left:21em">Message Size: </span>
+ <span class="alertThresholdMessageSize"
+ style="position:absolute; left:25em; width:5em; text-align:right"></span>
+ <span class="alertThresholdMessageSizeUnits" style="position:absolute; left:30.2em"></span>
+ <br/>
+ <br/>
+ <span style="">Alert frequency:</span>
+ <span class="alertRepeatGap"
+ style="position:absolute; left:4em; width:8em; text-align:right"></span>
+ <span class="alertRepeatGapUnits" style="position:absolute; left:12.2em"></span>
+ </div>
+</div>
+
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/Asserts.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/Asserts.java
new file mode 100644
index 0000000000..2595007574
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/Asserts.java
@@ -0,0 +1,249 @@
+/*
+ *
+ * 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 static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+
+public class Asserts
+{
+ public static final String STATISTICS_ATTRIBUTE = "statistics";
+
+ public static void assertVirtualHost(String virtualHostName, Map<String, Object> virtualHost)
+ {
+ assertNotNull("Virtualhost " + virtualHostName + " data are not found", virtualHost);
+ assertAttributesPresent(virtualHost, VirtualHost.AVAILABLE_ATTRIBUTES, VirtualHost.TIME_TO_LIVE,
+ VirtualHost.CREATED, VirtualHost.UPDATED, VirtualHost.SUPPORTED_QUEUE_TYPES, VirtualHost.STORE_CONFIGURATION);
+
+ assertEquals("Unexpected value of attribute " + VirtualHost.NAME, virtualHostName, virtualHost.get(VirtualHost.NAME));
+ assertNotNull("Unexpected value of attribute " + VirtualHost.ID, virtualHost.get(VirtualHost.ID));
+ assertEquals("Unexpected value of attribute " + VirtualHost.STATE, State.ACTIVE.name(),
+ virtualHost.get(VirtualHost.STATE));
+ assertEquals("Unexpected value of attribute " + VirtualHost.DURABLE, Boolean.TRUE,
+ virtualHost.get(VirtualHost.DURABLE));
+ assertEquals("Unexpected value of attribute " + VirtualHost.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ virtualHost.get(VirtualHost.LIFETIME_POLICY));
+ assertEquals("Unexpected value of attribute " + VirtualHost.DEAD_LETTER_QUEUE_ENABLED, Boolean.FALSE,
+ virtualHost.get(VirtualHost.DEAD_LETTER_QUEUE_ENABLED));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> exchangeTypes = (Collection<String>) virtualHost.get(VirtualHost.SUPPORTED_EXCHANGE_TYPES);
+ assertEquals("Unexpected value of attribute " + VirtualHost.SUPPORTED_EXCHANGE_TYPES,
+ new HashSet<String>(Arrays.asList("headers", "topic", "direct", "fanout", "management")),
+ new HashSet<String>(exchangeTypes));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) virtualHost.get(STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, VirtualHost.AVAILABLE_STATISTICS, VirtualHost.BYTES_RETAINED,
+ VirtualHost.LOCAL_TRANSACTION_BEGINS, VirtualHost.LOCAL_TRANSACTION_ROLLBACKS,
+ VirtualHost.MESSAGES_RETAINED, VirtualHost.STATE_CHANGED, VirtualHost.XA_TRANSACTION_BRANCH_ENDS,
+ VirtualHost.XA_TRANSACTION_BRANCH_STARTS, VirtualHost.XA_TRANSACTION_BRANCH_SUSPENDS);
+
+ }
+
+ public static void assertQueue(String queueName, String queueType, Map<String, Object> queueData)
+ {
+ assertQueue(queueName, queueType, queueData, null);
+ }
+
+ public static void assertQueue(String queueName, String queueType, Map<String, Object> queueData, Map<String, Object> expectedAttributes)
+ {
+ assertNotNull("Queue " + queueName + " is not found!", queueData);
+ Asserts.assertAttributesPresent(queueData, Queue.AVAILABLE_ATTRIBUTES, Queue.CREATED, Queue.UPDATED,
+ Queue.DESCRIPTION, Queue.TIME_TO_LIVE, Queue.ALTERNATE_EXCHANGE, Queue.OWNER, Queue.NO_LOCAL, Queue.LVQ_KEY,
+ Queue.SORT_KEY, Queue.MESSAGE_GROUP_KEY, Queue.MESSAGE_GROUP_DEFAULT_GROUP,
+ Queue.MESSAGE_GROUP_SHARED_GROUPS, Queue.PRIORITIES);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.NAME, queueName, queueData.get(Queue.NAME));
+ assertNotNull("Unexpected value of queue attribute " + Queue.ID, queueData.get(Queue.ID));
+ assertEquals("Unexpected value of queue attribute " + Queue.STATE, State.ACTIVE.name(), queueData.get(Queue.STATE));
+ assertEquals("Unexpected value of queue attribute " + Queue.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ queueData.get(Queue.LIFETIME_POLICY));
+ assertEquals("Unexpected value of queue attribute " + Queue.TYPE, queueType, queueData.get(Queue.TYPE));
+ if (expectedAttributes == null)
+ {
+ assertEquals("Unexpected value of queue attribute " + Queue.EXCLUSIVE, Boolean.FALSE, queueData.get(Queue.EXCLUSIVE));
+ assertEquals("Unexpected value of queue attribute " + Queue.MAXIMUM_DELIVERY_ATTEMPTS, 0,
+ queueData.get(Queue.MAXIMUM_DELIVERY_ATTEMPTS));
+ assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 0,
+ queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES));
+ assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 0,
+ queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES));
+ assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_STOPPED, Boolean.FALSE,
+ queueData.get(Queue.QUEUE_FLOW_STOPPED));
+ }
+ else
+ {
+ for (Map.Entry<String, Object> attribute : expectedAttributes.entrySet())
+ {
+ assertEquals("Unexpected value of " + queueName + " queue attribute " + attribute.getKey(),
+ attribute.getValue(), queueData.get(attribute.getKey()));
+ }
+ }
+
+ assertNotNull("Unexpected value of queue attribute statistics", queueData.get(Asserts.STATISTICS_ATTRIBUTE));
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) queueData.get(Asserts.STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, Queue.AVAILABLE_STATISTICS, Queue.DISCARDS_TTL_BYTES,
+ Queue.DISCARDS_TTL_MESSAGES, Queue.STATE_CHANGED);
+ }
+
+ public static void assertAttributesPresent(Map<String, Object> data, String[] attributes)
+ {
+ for (String name : attributes)
+ {
+ assertNotNull("Attribute " + name + " is not present", data.get(name));
+ }
+ }
+
+ public static void assertAttributesPresent(Map<String, Object> data, Collection<String> attributes,
+ String... unsupportedAttributes)
+ {
+ for (String name : attributes)
+ {
+ boolean unsupported = false;
+ for (String unsupportedAttribute : unsupportedAttributes)
+ {
+ if (unsupportedAttribute.equals(name))
+ {
+ unsupported = true;
+ break;
+ }
+ }
+ if (unsupported)
+ {
+ continue;
+ }
+ assertNotNull("Attribute " + name + " is not present", data.get(name));
+ }
+ }
+
+ public static void assertConnection(Map<String, Object> connectionData, AMQConnection connection) throws JMSException
+ {
+ assertNotNull("Unexpected connection data", connectionData);
+ assertAttributesPresent(connectionData, Connection.AVAILABLE_ATTRIBUTES, Connection.STATE, Connection.DURABLE,
+ Connection.LIFETIME_POLICY, Connection.TIME_TO_LIVE, Connection.CREATED, Connection.UPDATED,
+ Connection.INCOMING, Connection.REMOTE_PROCESS_NAME, Connection.REMOTE_PROCESS_PID,
+ Connection.LOCAL_ADDRESS, Connection.PROPERTIES);
+
+ assertEquals("Unexpected value of connection attribute " + Connection.SESSION_COUNT_LIMIT,
+ (int) connection.getMaximumChannelCount(), connectionData.get(Connection.SESSION_COUNT_LIMIT));
+ assertEquals("Unexpected value of connection attribute " + Connection.CLIENT_ID, "clientid",
+ connectionData.get(Connection.CLIENT_ID));
+ assertEquals("Unexpected value of connection attribute " + Connection.PRINCIPAL, "guest",
+ connectionData.get(Connection.PRINCIPAL));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) connectionData.get(STATISTICS_ATTRIBUTE);
+ assertAttributesPresent(statistics, Connection.AVAILABLE_STATISTICS, Connection.LOCAL_TRANSACTION_BEGINS,
+ Connection.LOCAL_TRANSACTION_ROLLBACKS, Connection.STATE_CHANGED, Connection.XA_TRANSACTION_BRANCH_ENDS,
+ Connection.XA_TRANSACTION_BRANCH_STARTS, Connection.XA_TRANSACTION_BRANCH_SUSPENDS);
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.SESSION_COUNT, 1,
+ statistics.get(Connection.SESSION_COUNT));
+ }
+
+ public static void assertPortAttributes(Map<String, Object> port)
+ {
+ assertAttributesPresent(port, Port.AVAILABLE_ATTRIBUTES, Port.CREATED, Port.UPDATED);
+
+ assertNotNull("Unexpected value of attribute " + Port.ID, port.get(Port.ID));
+ assertEquals("Unexpected value of attribute " + Port.DURABLE, Boolean.FALSE, port.get(Port.DURABLE));
+ assertEquals("Unexpected value of attribute " + Port.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ port.get(Broker.LIFETIME_POLICY));
+ assertEquals("Unexpected value of attribute " + Port.STATE, State.ACTIVE.name(), port.get(Port.STATE));
+ assertEquals("Unexpected value of attribute " + Port.TIME_TO_LIVE, 0, port.get(Port.TIME_TO_LIVE));
+ assertNotNull("Unexpected value of attribute " + Port.BINDING_ADDRESS, port.get(Port.BINDING_ADDRESS));
+ assertNotNull("Unexpected value of attribute " + Port.PROTOCOLS, port.get(Port.PROTOCOLS));
+ assertNotNull("Unexpected value of attribute " + Port.NAME, port.get(Port.NAME));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> transports = (Collection<String>) port.get(Port.TRANSPORTS);
+ assertEquals("Unexpected value of attribute " + Port.TRANSPORTS, new HashSet<String>(Arrays.asList("TCP")),
+ new HashSet<String>(transports));
+ }
+
+ public static void assertDurableExchange(String exchangeName, String type, Map<String, Object> exchangeData)
+ {
+ assertExchange(exchangeName, type, exchangeData);
+
+ assertEquals("Unexpected value of exchange attribute " + Exchange.DURABLE, Boolean.TRUE,
+ exchangeData.get(Exchange.DURABLE));
+ }
+
+ public static void assertExchange(String exchangeName, String type, Map<String, Object> exchangeData)
+ {
+ assertNotNull("Exchange " + exchangeName + " is not found!", exchangeData);
+ assertAttributesPresent(exchangeData, Exchange.AVAILABLE_ATTRIBUTES, Exchange.CREATED, Exchange.UPDATED,
+ Exchange.ALTERNATE_EXCHANGE, Exchange.TIME_TO_LIVE);
+
+ assertEquals("Unexpected value of exchange attribute " + Exchange.NAME, exchangeName,
+ exchangeData.get(Exchange.NAME));
+ assertNotNull("Unexpected value of exchange attribute " + Exchange.ID, exchangeData.get(VirtualHost.ID));
+ assertEquals("Unexpected value of exchange attribute " + Exchange.STATE, State.ACTIVE.name(),
+ exchangeData.get(Exchange.STATE));
+
+ assertEquals("Unexpected value of exchange attribute " + Exchange.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ exchangeData.get(Exchange.LIFETIME_POLICY));
+ assertEquals("Unexpected value of exchange attribute " + Exchange.TYPE, type, exchangeData.get(Exchange.TYPE));
+ assertNotNull("Unexpected value of exchange attribute statistics", exchangeData.get(STATISTICS_ATTRIBUTE));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) exchangeData.get(STATISTICS_ATTRIBUTE);
+ assertAttributesPresent(statistics, Exchange.AVAILABLE_STATISTICS, Exchange.STATE_CHANGED, Exchange.PRODUCER_COUNT);
+ }
+
+ public static void assertBinding(String bindingName, String queueName, String exchange, Map<String, Object> binding)
+ {
+ assertNotNull("Binding map should not be null", binding);
+ assertAttributesPresent(binding, Binding.AVAILABLE_ATTRIBUTES, Binding.STATE, Binding.TIME_TO_LIVE,
+ Binding.CREATED, Binding.UPDATED);
+
+ assertEquals("Unexpected binding attribute " + Binding.NAME, bindingName, binding.get(Binding.NAME));
+ assertEquals("Unexpected binding attribute " + Binding.QUEUE, queueName, binding.get(Binding.QUEUE));
+ assertEquals("Unexpected binding attribute " + Binding.EXCHANGE, exchange, binding.get(Binding.EXCHANGE));
+ assertEquals("Unexpected binding attribute " + Binding.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ binding.get(Binding.LIFETIME_POLICY));
+ }
+
+ public static void assertBinding(String queueName, String exchange, Map<String, Object> binding)
+ {
+ assertBinding(queueName, queueName, exchange, binding);
+ }
+
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
new file mode 100644
index 0000000000..37bc2733b0
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
@@ -0,0 +1,53 @@
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.User;
+
+public class AuthenticationProviderRestTest extends QpidRestTestCase
+{
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> providerDetails = getJsonAsList("/rest/authenticationprovider");
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ for (Map<String, Object> provider : providerDetails)
+ {
+ assertProvider("PrincipalDatabaseAuthenticationManager", provider);
+ Map<String, Object> data = getJsonAsSingletonList("/rest/authenticationprovider/"
+ + provider.get(AuthenticationProvider.NAME));
+ assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data);
+ assertProvider("PrincipalDatabaseAuthenticationManager", data);
+ }
+ }
+
+ private void assertProvider(String type, Map<String, Object> provider)
+ {
+ Asserts.assertAttributesPresent(provider, AuthenticationProvider.AVAILABLE_ATTRIBUTES,
+ AuthenticationProvider.CREATED, AuthenticationProvider.UPDATED, AuthenticationProvider.DESCRIPTION,
+ AuthenticationProvider.TIME_TO_LIVE);
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.STATE, State.ACTIVE.name(),
+ provider.get(AuthenticationProvider.STATE));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.LIFETIME_POLICY,
+ LifetimePolicy.PERMANENT.name(), provider.get(AuthenticationProvider.LIFETIME_POLICY));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.DURABLE, Boolean.TRUE,
+ provider.get(AuthenticationProvider.DURABLE));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.TYPE, type,
+ provider.get(AuthenticationProvider.TYPE));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> users = (List<Map<String, Object>>) provider.get("users");
+ assertNotNull("Users are not found", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ assertNotNull("Attribute " + User.NAME, user.get(User.NAME));
+ }
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
new file mode 100644
index 0000000000..527eb16927
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
@@ -0,0 +1,109 @@
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Binding;
+
+public class BindingRestTest extends QpidRestTestCase
+{
+
+ public void testGetAllBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getJsonAsList("/rest/binding");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertTrue("Unexpected number of bindings", bindings.size() >= EXPECTED_HOSTS.length * EXPECTED_QUEUES.length);
+ for (Map<String, Object> binding : bindings)
+ {
+ Asserts.assertBinding((String) binding.get(Binding.NAME), (String) binding.get(Binding.EXCHANGE), binding);
+ }
+ }
+
+ public void testGetVirtualHostBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", EXPECTED_QUEUES.length * 2, bindings.size());
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> searchAttributes = new HashMap<String, Object>();
+ searchAttributes.put(Binding.NAME, queueName);
+ searchAttributes.put(Binding.EXCHANGE, "amq.direct");
+
+ Map<String, Object> binding = find(searchAttributes, bindings);
+ Asserts.assertBinding(queueName, "amq.direct", binding);
+
+ searchAttributes.put(Binding.EXCHANGE, "<<default>>");
+
+ binding = find(searchAttributes, bindings);
+ Asserts.assertBinding(queueName, "<<default>>", binding);
+ }
+ }
+
+ public void testGetVirtualHostExchangeBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", EXPECTED_QUEUES.length, bindings.size());
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = find(Binding.NAME, queueName, bindings);
+ Asserts.assertBinding(queueName, "amq.direct", binding);
+ }
+ }
+
+ public void testGetVirtualHostExchangeQueueBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct/queue");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+ Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
+ }
+
+
+ public void testDeleteBinding() throws Exception
+ {
+ List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+ Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
+
+ HttpURLConnection connection = openManagementConection("/rest/binding/test/amq.direct/queue/queue", "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ bindings = getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
+ assertEquals("Binding should be deleted", 0, bindings.size());
+ }
+
+ public void testDeleteBindingById() throws Exception
+ {
+ Map<String, Object> binding = getJsonAsSingletonList("/rest/binding/test/amq.direct/queue");
+ HttpURLConnection connection = openManagementConection("/rest/binding/test/amq.direct?id=" + binding.get(Binding.ID), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct/queue");
+ assertEquals("Binding should be deleted", 0, bindings.size());
+ }
+
+ public void testCreateBinding() throws Exception
+ {
+ String bindingName = getTestName();
+ Map<String, Object> bindingData = new HashMap<String, Object>();
+ bindingData.put(Binding.NAME, bindingName);
+ bindingData.put(Binding.QUEUE, "queue");
+ bindingData.put(Binding.EXCHANGE, "amq.direct");
+
+ HttpURLConnection connection = openManagementConection("/rest/binding/test/amq.direct/queue/" + bindingName, "PUT");
+ connection.connect();
+ writeJsonRequest(connection, bindingData);
+ int responseCode = connection.getResponseCode();
+ connection.disconnect();
+ assertEquals("Unexpected response code", 201, responseCode);
+ Map<String, Object> binding = getJsonAsSingletonList("/rest/binding/test/amq.direct/queue/" + bindingName);
+
+ Asserts.assertBinding(bindingName, "queue", "amq.direct", binding);
+ }
+
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java
new file mode 100644
index 0000000000..4bbe9155cd
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.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.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Map;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.model.Broker;
+
+public class BrokerRestHttpsTest extends QpidRestTestCase
+{
+ private static final String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks";
+ private static final String TRUSTSTORE_PASSWORD = "password";
+
+ @Override
+ public void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+ }
+
+ @Override
+ protected void customizeConfiguration() throws ConfigurationException, IOException
+ {
+ setConfigurationProperty("management.enabled", "true");
+ setConfigurationProperty("management.http.enabled", "false");
+ setConfigurationProperty("management.https.enabled", "true");
+ setConfigurationProperty("management.https.port", Integer.toString(getHttpPort()));
+ }
+
+ @Override
+ protected String getHostName()
+ {
+ return "localhost";
+ }
+
+ @Override
+ protected String getProtocol()
+ {
+ return "https";
+ }
+
+ @Override
+ protected HttpURLConnection openManagementConection(String path) throws IOException
+ {
+ URL url = getManagementURL(path);
+ HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
+ ((HttpsURLConnection) httpCon).setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
+ httpCon.setDoOutput(true);
+ return httpCon;
+ }
+
+ public void testGetWithHttps() throws Exception
+ {
+ Map<String, Object> brokerDetails = getJsonAsSingletonList("/rest/broker");
+
+ Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES, Broker.BYTES_RETAINED,
+ Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES, Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED);
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java
new file mode 100644
index 0000000000..f2970e2ba9
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.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.rest;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+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.Port;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+
+public class BrokerRestTest extends QpidRestTestCase
+{
+
+ private static final String BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE = "authenticationproviders";
+ private static final String BROKER_PORTS_ATTRIBUTE = "ports";
+ private static final String BROKER_VIRTUALHOSTS_ATTRIBUTE = "virtualhosts";
+ private static final String BROKER_STATISTICS_ATTRIBUTE = "statistics";
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> brokerDetails = getJsonAsSingletonList("/rest/broker");
+
+ assertBrokerAttributes(brokerDetails);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, new String[]{ "bytesIn", "messagesOut", "bytesOut", "messagesIn" });
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> virtualhosts = (List<Map<String, Object>>) brokerDetails.get(BROKER_VIRTUALHOSTS_ATTRIBUTE);
+ assertEquals("Unexpected number of virtual hosts", 3, virtualhosts.size());
+
+ Asserts.assertVirtualHost("development", find(VirtualHost.NAME, "development", virtualhosts));
+ Asserts.assertVirtualHost("localhost", find(VirtualHost.NAME, "localhost", virtualhosts));
+ Asserts.assertVirtualHost("test", find(VirtualHost.NAME, "test", virtualhosts));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> ports = (List<Map<String, Object>>) brokerDetails.get(BROKER_PORTS_ATTRIBUTE);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+
+ for (Map<String, Object> port : ports)
+ {
+ Asserts.assertPortAttributes(port);
+ }
+
+ String bindingAddress = (String)ports.get(0).get(Port.BINDING_ADDRESS);
+
+ Map<String, Object> amqpPort = find(Port.NAME, bindingAddress + ":" + getPort(), ports);
+ Map<String, Object> httpPort = find(Port.NAME, bindingAddress + ":" + getHttpPort(), ports);
+
+ assertNotNull("Cannot find AMQP port", amqpPort);
+ assertNotNull("Cannot find HTTP port", httpPort);
+
+ @SuppressWarnings("unchecked")
+ Collection<String> port1Protocols = (Collection<String>) amqpPort.get(Port.PROTOCOLS);
+ assertFalse("AMQP protocol list cannot contain HTTP", port1Protocols.contains("HTTP"));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> port2Protocols = (Collection<String>) httpPort.get(Port.PROTOCOLS);
+ assertEquals("Unexpected value of attribute " + Port.PROTOCOLS, new HashSet<String>(Arrays.asList("HTTP")),
+ new HashSet<String>(port2Protocols));
+ }
+
+ protected void assertBrokerAttributes(Map<String, Object> brokerDetails)
+ {
+ Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES,
+ Broker.BYTES_RETAINED, Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES,
+ Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED);
+
+ assertEquals("Unexpected value of attribute " + Broker.BUILD_VERSION, QpidProperties.getBuildVersion(),
+ brokerDetails.get(Broker.BUILD_VERSION));
+ assertEquals("Unexpected value of attribute " + Broker.OPERATING_SYSTEM, System.getProperty("os.name") + " "
+ + System.getProperty("os.version") + " " + System.getProperty("os.arch"),
+ brokerDetails.get(Broker.OPERATING_SYSTEM));
+ assertEquals(
+ "Unexpected value of attribute " + Broker.PLATFORM,
+ System.getProperty("java.vendor") + " "
+ + System.getProperty("java.runtime.version", System.getProperty("java.version")),
+ brokerDetails.get(Broker.PLATFORM));
+ assertEquals("Unexpected value of attribute " + Broker.DURABLE, Boolean.TRUE, brokerDetails.get(Broker.DURABLE));
+ assertEquals("Unexpected value of attribute " + Broker.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ brokerDetails.get(Broker.LIFETIME_POLICY));
+ assertEquals("Unexpected value of attribute " + Broker.NAME, "Broker", brokerDetails.get(Broker.NAME));
+ assertEquals("Unexpected value of attribute " + Broker.STATE, State.ACTIVE.name(), brokerDetails.get(Broker.STATE));
+
+ assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID));
+ assertNotNull("Unexpected value of attribute statistics", brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute virtualhosts", brokerDetails.get(BROKER_VIRTUALHOSTS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute ports", brokerDetails.get(BROKER_PORTS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute authenticationproviders", brokerDetails.get(BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE));
+ }
+
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java
new file mode 100644
index 0000000000..3661b94a7c
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.Session;
+
+public class ConnectionRestTest extends QpidRestTestCase
+{
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 5;
+ private static final int MESSAGE_SIZE = 6;
+
+ private static final String SESSIONS_ATTRIBUTE = "sessions";
+
+ private javax.jms.Connection _connection;
+ private javax.jms.Session _session;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _connection = getConnection();
+ _session = _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = _session.createQueue(queueName);
+ MessageConsumer consumer = _session.createConsumer(queue);
+ MessageProducer producer = _session.createProducer(queue);
+ _connection.start();
+
+ // send messages
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ producer.send(_session.createTextMessage("Test-" + i));
+ }
+ _session.commit();
+
+ Message m = consumer.receive(1000l);
+ assertNotNull("Message was not received", m);
+ _session.commit();
+
+ // receive the rest of messages for rollback
+ for (int i = 0; i < MESSAGE_NUMBER - 1; i++)
+ {
+ m = consumer.receive(1000l);
+ assertNotNull("Message was not received", m);
+ }
+ _session.rollback();
+
+ // receive them again
+ for (int i = 0; i < MESSAGE_NUMBER - 1; i++)
+ {
+ m = consumer.receive(1000l);
+ assertNotNull("Message was not received", m);
+ }
+ }
+
+ public void testGetAllConnections() throws Exception
+ {
+ List<Map<String, Object>> connections = getJsonAsList("/rest/connection");
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
+ }
+
+ public void testGetVirtualHostConnections() throws Exception
+ {
+ List<Map<String, Object>> connections = getJsonAsList("/rest/connection/test");
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
+ }
+
+ public void testGetConnectionByName() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ Map<String, Object> connectionDetails = getJsonAsSingletonList("/rest/connection/test/"
+ + URLDecoder.decode(connectionName, "UTF-8"));
+ assertConnection(connectionDetails);
+ }
+
+ public void testGetAllSessions() throws Exception
+ {
+ List<Map<String, Object>> sessions = getJsonAsList("/rest/session");
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetVirtualHostSessions() throws Exception
+ {
+ List<Map<String, Object>> sessions = getJsonAsList("/rest/session/test");
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetConnectionSessions() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> sessions = getJsonAsList("/rest/session/test/"
+ + URLDecoder.decode(connectionName, "UTF-8"));
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetSessionByName() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> sessions = getJsonAsList("/rest/session/test/"
+ + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession<?, ?>) _session).getChannelId());
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ private void assertConnection(Map<String, Object> connectionDetails) throws JMSException
+ {
+ Asserts.assertConnection(connectionDetails, (AMQConnection) _connection);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) connectionDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.BYTES_IN, MESSAGE_NUMBER
+ * MESSAGE_SIZE, statistics.get(Connection.BYTES_IN));
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.BYTES_OUT, MESSAGE_SIZE
+ + ((MESSAGE_NUMBER - 1) * MESSAGE_SIZE) * 2, statistics.get(Connection.BYTES_OUT));
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.MESSAGES_IN, MESSAGE_NUMBER,
+ statistics.get(Connection.MESSAGES_IN));
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.MESSAGES_OUT,
+ MESSAGE_NUMBER * 2 - 1, statistics.get(Connection.MESSAGES_OUT));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> sessions = (List<Map<String, Object>>) connectionDetails.get(SESSIONS_ATTRIBUTE);
+ assertNotNull("Sessions cannot be found", sessions);
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ private void assertSession(Map<String, Object> sessionData, AMQSession<?, ?> session)
+ {
+ assertNotNull("Session map cannot be null", sessionData);
+ Asserts.assertAttributesPresent(sessionData, Session.AVAILABLE_ATTRIBUTES, Session.STATE, Session.DURABLE,
+ Session.LIFETIME_POLICY, Session.TIME_TO_LIVE, Session.CREATED, Session.UPDATED);
+ assertEquals("Unexpecte value of attribute " + Session.NAME, session.getChannelId() + "",
+ sessionData.get(Session.NAME));
+ assertEquals("Unexpecte value of attribute " + Session.PRODUCER_FLOW_BLOCKED, Boolean.FALSE,
+ sessionData.get(Session.PRODUCER_FLOW_BLOCKED));
+ assertEquals("Unexpecte value of attribute " + Session.CHANNEL_ID, session.getChannelId(),
+ sessionData.get(Session.CHANNEL_ID));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) sessionData.get(Asserts.STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, Session.AVAILABLE_STATISTICS, Session.BYTES_IN, Session.BYTES_OUT,
+ Session.STATE_CHANGED, Session.UNACKNOWLEDGED_BYTES, Session.LOCAL_TRANSACTION_OPEN,
+ Session.XA_TRANSACTION_BRANCH_ENDS, Session.XA_TRANSACTION_BRANCH_STARTS,
+ Session.XA_TRANSACTION_BRANCH_SUSPENDS);
+
+ assertEquals("Unexpecte value of statistic attribute " + Session.UNACKNOWLEDGED_MESSAGES, MESSAGE_NUMBER - 1,
+ statistics.get(Session.UNACKNOWLEDGED_MESSAGES));
+ assertEquals("Unexpecte value of statistic attribute " + Session.LOCAL_TRANSACTION_BEGINS, 4,
+ statistics.get(Session.LOCAL_TRANSACTION_BEGINS));
+ assertEquals("Unexpecte value of statistic attribute " + Session.LOCAL_TRANSACTION_ROLLBACKS, 1,
+ statistics.get(Session.LOCAL_TRANSACTION_ROLLBACKS));
+ assertEquals("Unexpecte value of statistic attribute " + Session.CONSUMER_COUNT, 1,
+ statistics.get(Session.CONSUMER_COUNT));
+ }
+
+ private String getConnectionName() throws IOException
+ {
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails
+ .get(VirtualHostRestTest.VIRTUALHOST_CONNECTIONS_ATTRIBUTE);
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Map<String, Object> connection = connections.get(0);
+ String connectionName = (String) connection.get(Connection.NAME);
+ return connectionName;
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
new file mode 100644
index 0000000000..59936427f9
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
@@ -0,0 +1,67 @@
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Exchange;
+
+public class ExchangeRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> exchanges = getJsonAsList("/rest/exchange");
+ assertNotNull("Exchanges cannot be null", exchanges);
+ assertTrue("Unexpected number of exchanges", exchanges.size() >= EXPECTED_HOSTS.length * EXPECTED_EXCHANGES.length);
+ for (Map<String, Object> exchange : exchanges)
+ {
+ Asserts.assertExchange((String) exchange.get(Exchange.NAME), (String) exchange.get(Exchange.TYPE), exchange);
+ }
+ }
+
+ public void testGetHostExchanges() throws Exception
+ {
+ List<Map<String, Object>> exchanges = getJsonAsList("/rest/exchange/test");
+ assertNotNull("Users cannot be null", exchanges);
+ assertEquals("Unexpected number of exchanges", 6, EXPECTED_EXCHANGES.length);
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = find(Exchange.NAME, exchangeName, exchanges);
+ assertExchange(exchangeName, exchange);
+ }
+ }
+
+ public void testGetHostExchangeByName() throws Exception
+ {
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = getJsonAsSingletonList("/rest/exchange/test/"
+ + URLDecoder.decode(exchangeName, "UTF-8"));
+ assertExchange(exchangeName, exchange);
+ }
+ }
+
+ private void assertExchange(String exchangeName, Map<String, Object> exchange)
+ {
+ assertNotNull("Exchange with name " + exchangeName + " is not found", exchange);
+ String type = (String) exchange.get(Exchange.TYPE);
+ Asserts.assertExchange(exchangeName, type, exchange);
+ if ("direct".equals(type))
+ {
+ assertBindings(exchange);
+ }
+ }
+
+ private void assertBindings(Map<String, Object> exchange)
+ {
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings");
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = find(Binding.NAME, queueName, bindings);
+ Asserts.assertBinding(queueName, (String) exchange.get(Exchange.NAME), binding);
+ }
+ }
+
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java
new file mode 100644
index 0000000000..c64fd6e1da
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.util.List;
+import java.util.Map;
+
+public class LogRecordsRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> logs = getJsonAsList("/rest/logrecords");
+ assertNotNull("Logs data cannot be null", logs);
+ assertTrue("Logs are not found", logs.size() > 0);
+ Map<String, Object> record = find("message", "[Broker] BRK-1004 : Qpid Broker Ready", logs);
+
+ assertNotNull("BRK-1004 message is not found", record);
+ assertNotNull("Message id cannot be null", record.get("id"));
+ assertNotNull("Message timestamp cannot be null", record.get("timestamp"));
+ assertEquals("Unexpected log level", "INFO", record.get("level"));
+ assertEquals("Unexpected thread", "main", record.get("thread"));
+ assertEquals("Unexpected logger", "qpid.message.broker.ready", record.get("logger"));
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java
new file mode 100644
index 0000000000..492df43957
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java
@@ -0,0 +1,354 @@
+/*
+ *
+ * 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.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class MessagesRestTest extends QpidRestTestCase
+{
+
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 12;
+
+ private Connection _connection;
+ private Session _session;
+ private MessageProducer _producer;
+ private long _startTime;
+ private long _ttl;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _startTime = System.currentTimeMillis();
+ _connection = getConnection();
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = _session.createQueue(queueName);
+ _session.createConsumer(queue);
+ _producer = _session.createProducer(queue);
+
+ _ttl = TimeUnit.DAYS.toMillis(1);
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ Message m = _session.createTextMessage("Test-" + i);
+ m.setIntProperty("index", i);
+ if (i % 2 == 0)
+ {
+ _producer.send(m);
+ }
+ else
+ {
+ _producer.send(m, DeliveryMode.NON_PERSISTENT, 5, _ttl);
+ }
+ }
+ _session.commit();
+ }
+
+ public void testGet() throws Exception
+ {
+ String queueName = getTestQueueName();
+ List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
+ int position = 0;
+ for (Map<String, Object> message : messages)
+ {
+ assertMessage(position, message);
+ position++;
+ }
+ }
+
+ public void testGetMessageContent() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ // add bytes message
+ BytesMessage byteMessage = _session.createBytesMessage();
+ byte[] messageBytes = "Test".getBytes();
+ byteMessage.writeBytes(messageBytes);
+ byteMessage.setStringProperty("test", "value");
+ _producer.send(byteMessage);
+ _session.commit();
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ Map<String, Object> message = getJsonAsMap("/rest/message/test/" + queueName + "/" + ids.get(0));
+ assertMessageAttributes(message);
+ assertMessageAttributeValues(message, true);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> headers = (Map<String, Object>) message.get("headers");
+ assertNotNull("Message headers are not found", headers);
+ assertEquals("Unexpected message header", 0, headers.get("index"));
+
+ Long lastMessageId = ids.get(ids.size() - 1);
+ message = getJsonAsMap("/rest/message/test/" + queueName + "/" + lastMessageId);
+ assertMessageAttributes(message);
+ assertEquals("Unexpected message attribute mimeType", "application/octet-stream", message.get("mimeType"));
+ assertEquals("Unexpected message attribute size", 4, message.get("size"));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> bytesMessageHeader = (Map<String, Object>) message.get("headers");
+ assertNotNull("Message headers are not found", bytesMessageHeader);
+ assertEquals("Unexpected message header", "value", bytesMessageHeader.get("test"));
+
+ // get content
+ HttpURLConnection connection = openManagementConection("/rest/message-content/test/" + queueName + "/"
+ + lastMessageId, "GET");
+ connection.connect();
+ byte[] data = readConnectionInputStream(connection);
+ assertTrue("Unexpected message", Arrays.equals(messageBytes, data));
+
+ }
+
+ public void testPostMoveMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String queueName2 = queueName + "_2";
+ Destination queue2 = _session.createQueue(queueName2);
+ _session.createConsumer(queue2);
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // move half of the messages
+ int movedNumber = ids.size() / 2;
+ List<Long> movedMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < movedNumber; i++)
+ {
+ movedMessageIds.add(ids.remove(i));
+ }
+
+ // move messages
+ HttpURLConnection connection = openManagementConection("/rest/message/test/" + queueName, "POST");
+
+ Map<String, Object> messagesData = new HashMap<String, Object>();
+ messagesData.put("messages", movedMessageIds);
+ messagesData.put("destinationQueue", queueName2);
+ messagesData.put("move", Boolean.TRUE);
+
+ writeJsonRequest(connection, messagesData);
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ // check messages on target queue
+ List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName2);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", movedMessageIds.size(), messages.size());
+ for (Long id : movedMessageIds)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+
+ // check messages on original queue
+ messages = getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", ids.size(), messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : movedMessageIds)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertNull("Moved message " + id + " is found on original queue", message);
+ }
+ }
+
+ public void testPostCopyMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String queueName2 = queueName + "_2";
+ Destination queue2 = _session.createQueue(queueName2);
+ _session.createConsumer(queue2);
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // copy half of the messages
+ int copyNumber = ids.size() / 2;
+ List<Long> copyMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < copyNumber; i++)
+ {
+ copyMessageIds.add(ids.remove(i));
+ }
+
+ // copy messages
+ HttpURLConnection connection = openManagementConection("/rest/message/test/" + queueName, "POST");
+
+ Map<String, Object> messagesData = new HashMap<String, Object>();
+ messagesData.put("messages", copyMessageIds);
+ messagesData.put("destinationQueue", queueName2);
+
+ writeJsonRequest(connection, messagesData);
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ // check messages on target queue
+ List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName2);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", copyMessageIds.size(), messages.size());
+ for (Long id : copyMessageIds)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+
+ // check messages on original queue
+ messages = getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : copyMessageIds)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ }
+
+ public void testDeleteMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // delete half of the messages
+ int deleteNumber = ids.size() / 2;
+ StringBuilder queryString = new StringBuilder();
+ List<Long> deleteMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < deleteNumber; i++)
+ {
+ Long id = ids.remove(i);
+ deleteMessageIds.add(id);
+ if (queryString.length() > 0)
+ {
+ queryString.append("&");
+ }
+ queryString.append("id=").append(id);
+ }
+
+ // delete messages
+ HttpURLConnection connection = openManagementConection(
+ "/rest/message/test/" + queueName + "?" + queryString.toString(), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ // check messages on queue
+ List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", ids.size(), messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : deleteMessageIds)
+ {
+ Map<String, Object> message = find("id", id.intValue(), messages);
+ assertNull("Message with id " + id + " was not deleted", message);
+ }
+ }
+
+ private List<Long> getMesssageIds(String queueName) throws IOException, JsonParseException, JsonMappingException
+ {
+ List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName);
+ List<Long> ids = new ArrayList<Long>();
+ for (Map<String, Object> message : messages)
+ {
+ ids.add(((Number) message.get("id")).longValue());
+ }
+ return ids;
+ }
+
+ private void assertMessage(int position, Map<String, Object> message)
+ {
+ assertMessageAttributes(message);
+
+ assertEquals("Unexpected message attribute position", position, message.get("position"));
+ assertEquals("Unexpected message attribute size", position < 10 ? 6 : 7, message.get("size"));
+ boolean even = position % 2 == 0;
+ assertMessageAttributeValues(message, even);
+ }
+
+ private void assertMessageAttributeValues(Map<String, Object> message, boolean even)
+ {
+ if (even)
+ {
+ assertEquals("Unexpected message attribute expirationTime", 0, message.get("expirationTime"));
+ assertEquals("Unexpected message attribute priority", 4, message.get("priority"));
+ assertEquals("Unexpected message attribute persistent", Boolean.TRUE, message.get("persistent"));
+ }
+ else
+ {
+ assertEquals("Unexpected message attribute expirationTime", ((Number) message.get("timestamp")).longValue()
+ + _ttl, message.get("expirationTime"));
+ assertEquals("Unexpected message attribute priority", 5, message.get("priority"));
+ assertEquals("Unexpected message attribute persistent", Boolean.FALSE, message.get("persistent"));
+ }
+ assertEquals("Unexpected message attribute mimeType", "text/plain", message.get("mimeType"));
+ assertEquals("Unexpected message attribute userId", "guest", message.get("userId"));
+ assertEquals("Unexpected message attribute deliveryCount", 0, message.get("deliveryCount"));
+ assertEquals("Unexpected message attribute state", "Available", message.get("state"));
+ }
+
+ private void assertMessageAttributes(Map<String, Object> message)
+ {
+ assertNotNull("Message map cannot be null", message);
+ assertNotNull("Unexpected message attribute deliveryCount", message.get("deliveryCount"));
+ assertNotNull("Unexpected message attribute state", message.get("state"));
+ assertNotNull("Unexpected message attribute id", message.get("id"));
+ assertNotNull("Message arrivalTime cannot be null", message.get("arrivalTime"));
+ assertNotNull("Message timestamp cannot be null", message.get("timestamp"));
+ assertTrue("Message arrivalTime cannot be null", ((Number) message.get("arrivalTime")).longValue() > _startTime);
+ assertNotNull("Message messageId cannot be null", message.get("messageId"));
+ assertNotNull("Unexpected message attribute mimeType", message.get("mimeType"));
+ assertNotNull("Unexpected message attribute userId", message.get("userId"));
+ assertNotNull("Message priority cannot be null", message.get("priority"));
+ assertNotNull("Message expirationTime cannot be null", message.get("expirationTime"));
+ assertNotNull("Message persistent cannot be null", message.get("persistent"));
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
new file mode 100644
index 0000000000..49f163baae
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
@@ -0,0 +1,41 @@
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Port;
+
+public class PortRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> ports = getJsonAsList("/rest/port/");
+ assertNotNull("Port data cannot be null", ports);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+ int[] expectedPorts = { getPort(), getHttpPort() };
+ for (int port : expectedPorts)
+ {
+ String portName = "0.0.0.0:" + port;
+ Map<String, Object> portData = find(Port.NAME, portName, ports);
+ assertNotNull("Port " + portName + " is not found", portData);
+ Asserts.assertPortAttributes(portData);
+ }
+ }
+
+ public void testGetPort() throws Exception
+ {
+ List<Map<String, Object>> ports = getJsonAsList("/rest/port/");
+ assertNotNull("Ports data cannot be null", ports);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+ for (Map<String, Object> portMap : ports)
+ {
+ String portName = (String) portMap.get(Port.NAME);
+ assertNotNull("Port name attribute is not found", portName);
+ Map<String, Object> portData = getJsonAsSingletonList("/rest/port/" + URLDecoder.decode(portName, "UTF-8"));
+ assertNotNull("Port " + portName + " is not found", portData);
+ Asserts.assertPortAttributes(portData);
+ }
+ }
+
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java
new file mode 100644
index 0000000000..e83341de80
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+
+public class QpidRestTestCase extends QpidBrokerTestCase
+{
+ private static final Logger LOGGER = Logger.getLogger(QpidRestTestCase.class);
+
+ public static final String[] EXPECTED_HOSTS = { "development", "test", "localhost" };
+ public static final String[] EXPECTED_QUEUES = { "queue", "ping" };
+ public static final String[] EXPECTED_EXCHANGES = { "amq.fanout", "amq.match", "amq.direct", "amq.topic",
+ "qpid.management", "<<default>>" };
+
+ private int _httpPort;
+ private String _hostName;
+ private List<HttpURLConnection> _httpConnections;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _httpConnections = new ArrayList<HttpURLConnection>();
+ _hostName = InetAddress.getLocalHost().getHostName();
+ _httpPort = findFreePort();
+ customizeConfiguration();
+ super.setUp();
+
+ }
+
+ protected void customizeConfiguration() throws ConfigurationException, IOException
+ {
+ setConfigurationProperty("management.enabled", "false");
+ setConfigurationProperty("management.http.enabled", "true");
+ setConfigurationProperty("management.https.enabled", "false");
+ setConfigurationProperty("management.http.port", Integer.toString(_httpPort));
+ }
+
+ public void teearDown() throws Exception
+ {
+ for (HttpURLConnection connection : _httpConnections)
+ {
+ try
+ {
+ connection.disconnect();
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ }
+ super.tearDown();
+ }
+
+ protected int getHttpPort()
+ {
+ return _httpPort;
+ }
+
+ protected String getHostName()
+ {
+ return _hostName;
+ }
+
+ protected String getProtocol()
+ {
+ return "http";
+ }
+
+ protected String getManagementURL()
+ {
+ return getProtocol() + "://" + getHostName() + ":" + getHttpPort();
+ }
+
+ protected URL getManagementURL(String path) throws MalformedURLException
+ {
+ return new URL(getManagementURL() + path);
+ }
+
+ protected HttpURLConnection openManagementConection(String path) throws IOException
+ {
+ URL url = getManagementURL(path);
+ HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
+ httpCon.setDoOutput(true);
+ return httpCon;
+ }
+
+ protected HttpURLConnection openManagementConection(String path, String method) throws IOException
+ {
+ HttpURLConnection httpCon = openManagementConection(path);
+ httpCon.setRequestMethod(method);
+ return httpCon;
+ }
+
+ protected List<Map<String, Object>> readJsonResponseAsList(HttpURLConnection connection) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ byte[] data = readConnectionInputStream(connection);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ TypeReference<List<LinkedHashMap<String, Object>>> typeReference = new TypeReference<List<LinkedHashMap<String, Object>>>()
+ {
+ };
+ List<Map<String, Object>> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
+ return providedObject;
+ }
+
+ protected Map<String, Object> readJsonResponseAsMap(HttpURLConnection connection) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ byte[] data = readConnectionInputStream(connection);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ TypeReference<LinkedHashMap<String, Object>> typeReference = new TypeReference<LinkedHashMap<String, Object>>()
+ {
+ };
+ Map<String, Object> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
+ return providedObject;
+ }
+
+ protected byte[] readConnectionInputStream(HttpURLConnection connection) throws IOException
+ {
+ InputStream is = connection.getInputStream();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int len = -1;
+ while ((len = is.read(buffer)) != -1)
+ {
+ baos.write(buffer, 0, len);
+ }
+ if (LOGGER.isTraceEnabled())
+ {
+ LOGGER.trace("RESPONSE:" + new String(baos.toByteArray()));
+ }
+ return baos.toByteArray();
+ }
+
+ protected void writeJsonRequest(HttpURLConnection connection, Map<String, Object> data) throws JsonGenerationException,
+ JsonMappingException, IOException
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.writeValue(connection.getOutputStream(), data);
+ }
+
+ protected Map<String, Object> find(String name, Object value, List<Map<String, Object>> data)
+ {
+ for (Map<String, Object> map : data)
+ {
+ Object mapValue = map.get(name);
+ if (value.equals(mapValue))
+ {
+ return map;
+ }
+ }
+ return null;
+ }
+
+ protected Map<String, Object> find(Map<String, Object> searchAttributes, List<Map<String, Object>> data)
+ {
+ for (Map<String, Object> map : data)
+ {
+ boolean equals = true;
+ for (Map.Entry<String, Object> entry : searchAttributes.entrySet())
+ {
+ Object mapValue = map.get(entry.getKey());
+ if (!entry.getValue().equals(mapValue))
+ {
+ equals = false;
+ break;
+ }
+ }
+ if (equals)
+ {
+ return map;
+ }
+ }
+ return null;
+ }
+
+ protected Map<String, Object> getJsonAsSingletonList(String path) throws IOException
+ {
+ List<Map<String, Object>> response = getJsonAsList(path);
+
+ assertNotNull("Response cannot be null", response);
+ assertEquals("Unexpected response", 1, response.size());
+ return response.get(0);
+ }
+
+ protected List<Map<String, Object>> getJsonAsList(String path) throws IOException, JsonParseException,
+ JsonMappingException
+ {
+ HttpURLConnection connection = openManagementConection(path, "GET");
+ connection.connect();
+ List<Map<String, Object>> response = readJsonResponseAsList(connection);
+ return response;
+ }
+
+ protected Map<String, Object> getJsonAsMap(String path) throws IOException
+ {
+ HttpURLConnection connection = openManagementConection(path, "GET");
+ connection.connect();
+ Map<String, Object> response = readJsonResponseAsMap(connection);
+ return response;
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java
new file mode 100644
index 0000000000..5f11b3fb1d
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java
@@ -0,0 +1,225 @@
+/*
+ *
+ * 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.HttpURLConnection;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Queue;
+
+public class QueueRestTest extends QpidRestTestCase
+{
+ private static final String QUEUE_ATTRIBUTE_CONSUMERS = "consumers";
+ private static final String QUEUE_ATTRIBUTE_BINDINGS = "bindings";
+
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 2;
+ private static final int MESSAGE_PAYLOAD_SIZE = 6;
+ private static final int ENQUEUED_MESSAGES = 1;
+ private static final int DEQUEUED_MESSAGES = 1;
+ private static final int ENQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE;
+ private static final int DEQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE;
+
+ private Connection _connection;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _connection = getConnection();
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = session.createQueue(queueName);
+ MessageConsumer consumer = session.createConsumer(queue);
+ MessageProducer producer = session.createProducer(queue);
+
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ producer.send(session.createTextMessage("Test-" + i));
+ }
+ session.commit();
+ _connection.start();
+ Message m = consumer.receive(1000l);
+ assertNotNull("Message is not received", m);
+ session.commit();
+ }
+
+ public void testGetVirtualHostQueues() throws Exception
+ {
+ String queueName = getTestQueueName();
+ List<Map<String, Object>> queues = getJsonAsList("/rest/queue/test");
+ assertEquals("Unexpected number of queues", EXPECTED_QUEUES.length + 1, queues.size());
+ String[] expectedQueues = new String[EXPECTED_QUEUES.length + 1];
+ System.arraycopy(EXPECTED_QUEUES, 0, expectedQueues, 0, EXPECTED_QUEUES.length);
+ expectedQueues[EXPECTED_QUEUES.length] = queueName;
+
+ for (String name : expectedQueues)
+ {
+ Map<String, Object> queueDetails = find(Queue.NAME, name, queues);
+ Asserts.assertQueue(name, "standard", queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", 2, bindings.size());
+
+ Map<String, Object> defaultExchangeBinding = find(Binding.EXCHANGE, "<<default>>", bindings);
+ Map<String, Object> directExchangeBinding = find(Binding.EXCHANGE, "amq.direct", bindings);
+ Asserts.assertBinding(name, "<<default>>", defaultExchangeBinding);
+ Asserts.assertBinding(name, "amq.direct", directExchangeBinding);
+ }
+ }
+
+ public void testGetByName() throws Exception
+ {
+ String queueName = getTestQueueName();
+ Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ Asserts.assertQueue(queueName, "standard", queueDetails);
+ assertStatistics(queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", 2, bindings.size());
+
+ Map<String, Object> defaultExchangeBinding = find(Binding.EXCHANGE, "<<default>>", bindings);
+ Map<String, Object> directExchangeBinding = find(Binding.EXCHANGE, "amq.direct", bindings);
+ Asserts.assertBinding(queueName, "<<default>>", defaultExchangeBinding);
+ Asserts.assertBinding(queueName, "amq.direct", directExchangeBinding);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> consumers = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_CONSUMERS);
+ assertNotNull("Queue consumers are not found", consumers);
+ assertEquals("Unexpected number of consumers", 1, consumers.size());
+ assertConsumer(consumers.get(0));
+ }
+
+ public void testPutCreateBinding() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String bindingName = queueName + 2;
+ String[] exchanges = { "amq.direct", "amq.fanout", "amq.topic", "amq.match", "qpid.management", "<<default>>" };
+
+ for (int i = 0; i < exchanges.length; i++)
+ {
+ createBinding(bindingName, exchanges[i], queueName);
+ }
+
+ Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ Asserts.assertQueue(queueName, "standard", queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", exchanges.length + 2, bindings.size());
+
+ Map<String, Object> searchAttributes = new HashMap<String, Object>();
+ searchAttributes.put(Binding.NAME, bindingName);
+
+ for (int i = 0; i < exchanges.length; i++)
+ {
+ searchAttributes.put(Binding.EXCHANGE, exchanges[i]);
+ Map<String, Object> binding = find(searchAttributes, bindings);
+ Asserts.assertBinding(bindingName, queueName, exchanges[i], binding);
+ }
+ }
+
+ private void createBinding(String bindingName, String exchangeName, String queueName) throws IOException
+ {
+ HttpURLConnection connection = openManagementConection(
+ "/rest/binding/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName,
+ "PUT");
+
+ Map<String, Object> bindingData = new HashMap<String, Object>();
+ bindingData.put(Binding.NAME, bindingName);
+ bindingData.put(Binding.EXCHANGE, exchangeName);
+ bindingData.put(Binding.QUEUE, queueName);
+
+ writeJsonRequest(connection, bindingData);
+ assertEquals("Unexpected response code", 201, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ private void assertConsumer(Map<String, Object> consumer)
+ {
+ assertNotNull("Consumer map should not be null", consumer);
+ Asserts.assertAttributesPresent(consumer, Consumer.AVAILABLE_ATTRIBUTES, Consumer.STATE, Consumer.TIME_TO_LIVE,
+ Consumer.CREATED, Consumer.UPDATED, Consumer.SETTLEMENT_MODE, Consumer.EXCLUSIVE, Consumer.SELECTOR,
+ Consumer.NO_LOCAL);
+
+ assertEquals("Unexpected binding attribute " + Consumer.NAME, "1", consumer.get(Consumer.NAME));
+ assertEquals("Unexpected binding attribute " + Consumer.DURABLE, Boolean.FALSE, consumer.get(Consumer.DURABLE));
+ assertEquals("Unexpected binding attribute " + Consumer.LIFETIME_POLICY, LifetimePolicy.AUTO_DELETE.name(),
+ consumer.get(Consumer.LIFETIME_POLICY));
+ assertEquals("Unexpected binding attribute " + Consumer.DISTRIBUTION_MODE, "MOVE",
+ consumer.get(Consumer.DISTRIBUTION_MODE));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) consumer.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertNotNull("Consumer statistics is not present", statistics);
+ Asserts.assertAttributesPresent(statistics, Consumer.AVAILABLE_STATISTICS, Consumer.STATE_CHANGED);
+ }
+
+ private void assertStatistics(Map<String, Object> queueDetails)
+ {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES,
+ statistics.get(Queue.PERSISTENT_DEQUEUED_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.QUEUE_DEPTH_MESSAGES, ENQUEUED_MESSAGES,
+ statistics.get(Queue.QUEUE_DEPTH_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.CONSUMER_COUNT, 1,
+ statistics.get(Queue.CONSUMER_COUNT));
+ assertEquals("Unexpected queue statistics attribute " + Queue.CONSUMER_COUNT_WITH_CREDIT, 1,
+ statistics.get(Queue.CONSUMER_COUNT_WITH_CREDIT));
+ assertEquals("Unexpected queue statistics attribute " + Queue.BINDING_COUNT, 2, statistics.get(Queue.BINDING_COUNT));
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES,
+ statistics.get(Queue.PERSISTENT_DEQUEUED_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES,
+ statistics.get(Queue.TOTAL_DEQUEUED_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_DEQUEUED_BYTES, DEQUEUED_BYTES,
+ statistics.get(Queue.TOTAL_DEQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_BYTES, DEQUEUED_BYTES,
+ statistics.get(Queue.TOTAL_DEQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_ENQUEUED_BYTES, ENQUEUED_BYTES
+ + DEQUEUED_BYTES, statistics.get(Queue.PERSISTENT_ENQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_ENQUEUED_BYTES, ENQUEUED_BYTES + DEQUEUED_BYTES,
+ statistics.get(Queue.TOTAL_ENQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.QUEUE_DEPTH_BYTES, ENQUEUED_BYTES,
+ statistics.get(Queue.QUEUE_DEPTH_BYTES));
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
new file mode 100644
index 0000000000..943466eda7
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
@@ -0,0 +1,22 @@
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.util.List;
+import java.util.Map;
+
+public class SaslRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ Map<String, Object> saslData = getJsonAsMap("/rest/sasl");
+ assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms"));
+
+ @SuppressWarnings("unchecked")
+ List<String> mechanisms = (List<String>) saslData.get("mechanisms");
+ String[] expectedMechanisms = { "AMQPLAIN", "PLAIN", "CRAM-MD5" };
+ for (String mechanism : expectedMechanisms)
+ {
+ assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism));
+ }
+ }
+
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java
new file mode 100644
index 0000000000..b01e1d44b8
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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.List;
+import java.util.Map;
+
+public class StructureRestTest extends QpidRestTestCase
+{
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> structure = getJsonAsMap("/rest/structure");
+ assertNotNull("Structure data cannot be null", structure);
+ assertNode(structure, "Broker");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> virtualhosts = (List<Map<String, Object>>) structure.get("virtualhosts");
+ assertEquals("Unexpected number of virtual hosts", 3, virtualhosts.size());
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> ports = (List<Map<String, Object>>) structure.get("ports");
+ assertEquals("Unexpected number of ports", 2, ports.size());
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> providers = (List<Map<String, Object>>) structure.get("authenticationproviders");
+ assertEquals("Unexpected number of authentication providers", 1, providers.size());
+
+ for (String hostName : EXPECTED_HOSTS)
+ {
+ Map<String, Object> host = find("name", hostName, virtualhosts);
+ assertNotNull("Host " + hostName + " is not found ", host);
+ assertNode(host, hostName);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) host.get("queues");
+ assertNotNull("Host " + hostName + " queues are not found ", queues);
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> queue = find("name", queueName, queues);
+ assertNotNull(hostName + " queue " + queueName + " is not found ", queue);
+ assertNode(queue, queueName);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queue.get("bindings");
+ assertNotNull(hostName + " queue " + queueName + " bindings are not found ", queues);
+ for (Map<String, Object> binding : bindings)
+ {
+ assertNode(binding, queueName);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) host.get("exchanges");
+ assertNotNull("Host " + hostName + " exchanges are not found ", exchanges);
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = find("name", exchangeName, exchanges);
+ assertNotNull("Exchange " + exchangeName + " is not found ", exchange);
+ assertNode(exchange, exchangeName);
+ if ("amq.direct".equalsIgnoreCase(exchangeName) || "<<default>>".equalsIgnoreCase(exchangeName))
+ {
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings");
+ assertNotNull(hostName + " exchange " + exchangeName + " bindings are not found ", bindings);
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = find("name", queueName, bindings);
+ assertNotNull(hostName + " exchange " + exchangeName + " binding " + queueName + " is not found", binding);
+ assertNode(binding, queueName);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> aliases = (List<Map<String, Object>>) host.get("virtualhostaliases");
+ assertNotNull("Host " + hostName + " aliaces are not found ", aliases);
+ assertEquals("Unexpected aliaces size", 1, aliases.size());
+ assertNode(aliases.get(0), hostName);
+ }
+
+ int[] expectedPorts = { getPort(), getHttpPort() };
+ for (int port : expectedPorts)
+ {
+ String portName = "0.0.0.0:" + port;
+ Map<String, Object> portData = find("name", portName, ports);
+ assertNotNull("Port " + portName + " is not found ", portData);
+ assertNode(portData, portName);
+ }
+ }
+
+ private void assertNode(Map<String, Object> node, String name)
+ {
+ assertEquals("Unexpected name", name, node.get("name"));
+ assertNotNull("Unexpected id", node.get("id"));
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
new file mode 100644
index 0000000000..378b349a99
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
@@ -0,0 +1,92 @@
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.User;
+
+public class UserRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> users = getJsonAsList("/rest/user");
+ assertNotNull("Users cannot be null", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertUser(user);
+ }
+ }
+
+ public void testGetUserByName() throws Exception
+ {
+ List<Map<String, Object>> users = getJsonAsList("/rest/user");
+ assertNotNull("Users cannot be null", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ String userName = (String) user.get(User.NAME);
+ assertNotNull("Attribute " + User.NAME, userName);
+ Map<String, Object> userDetails = getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName);
+ assertUser(userDetails);
+ assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
+ }
+ }
+
+ public void testPut() throws Exception
+ {
+ String userName = getTestName();
+ HttpURLConnection connection = openManagementConection("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName, "PUT");
+
+ Map<String, Object> userData = new HashMap<String, Object>();
+ userData.put(User.NAME, userName);
+ userData.put(User.PASSWORD, userName);
+
+ writeJsonRequest(connection, userData);
+ assertEquals("Unexpected response code", 201, connection.getResponseCode());
+
+ connection.disconnect();
+
+ Map<String, Object> userDetails = getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName);
+ assertUser(userDetails);
+ assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
+ }
+
+ public void testDelete() throws Exception
+ {
+ // add user
+ String userName = getTestName();
+ HttpURLConnection connection = openManagementConection("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName, "PUT");
+
+ Map<String, Object> userData = new HashMap<String, Object>();
+ userData.put(User.NAME, userName);
+ userData.put(User.PASSWORD, userName);
+
+ writeJsonRequest(connection, userData);
+ assertEquals("Unexpected response code", 201, connection.getResponseCode());
+ connection.disconnect();
+
+ Map<String, Object> userDetails = getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName);
+ String id = (String) userDetails.get(User.ID);
+
+ connection = openManagementConection("/rest/user/PrincipalDatabaseAuthenticationManager?id=" + id, "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> users = getJsonAsList("/rest/user/PrincipalDatabaseAuthenticationManager/" + userName);
+ assertEquals("User should be deleted", 0, users.size());
+ }
+
+ private void assertUser(Map<String, Object> user)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ assertNotNull("Attribute " + User.NAME, user.get(User.NAME));
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java
new file mode 100644
index 0000000000..17f1aaaf7b
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java
@@ -0,0 +1,434 @@
+/*
+ *
+ * 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.HttpURLConnection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class VirtualHostRestTest extends QpidRestTestCase
+{
+ private static final String VIRTUALHOST_EXCHANGES_ATTRIBUTE = "exchanges";
+ public static final String VIRTUALHOST_QUEUES_ATTRIBUTE = "queues";
+ public static final String VIRTUALHOST_CONNECTIONS_ATTRIBUTE = "connections";
+
+ private AMQConnection _connection;
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> hosts = getJsonAsList("/rest/virtualhost/");
+ assertNotNull("Hosts data cannot be null", hosts);
+ assertEquals("Unexpected number of hosts", 3, hosts.size());
+ for (String hostName : EXPECTED_HOSTS)
+ {
+ Map<String, Object> host = find("name", hostName, hosts);
+ Asserts.assertVirtualHost(hostName, host);
+ }
+ }
+
+ public void testGetHost() throws Exception
+ {
+ // create AMQP connection to get connection JSON details
+ _connection = (AMQConnection) getConnection();
+ _connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Asserts.assertVirtualHost("test", hostDetails);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected number of exchanges in statistics", 6, statistics.get(VirtualHost.EXCHANGE_COUNT));
+ assertEquals("Unexpected number of queues in statistics", 2, statistics.get(VirtualHost.QUEUE_COUNT));
+ assertEquals("Unexpected number of connections in statistics", 1, statistics.get(VirtualHost.CONNECTION_COUNT));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+ assertEquals("Unexpected number of exchanges", 6, exchanges.size());
+ Asserts.assertDurableExchange("amq.fanout", "fanout", find(Exchange.NAME, "amq.fanout", exchanges));
+ Asserts.assertDurableExchange("qpid.management", "management", find(Exchange.NAME, "qpid.management", exchanges));
+ Asserts.assertDurableExchange("amq.topic", "topic", find(Exchange.NAME, "amq.topic", exchanges));
+ Asserts.assertDurableExchange("amq.direct", "direct", find(Exchange.NAME, "amq.direct", exchanges));
+ Asserts.assertDurableExchange("amq.match", "headers", find(Exchange.NAME, "amq.match", exchanges));
+ Asserts.assertDurableExchange("<<default>>", "direct", find(Exchange.NAME, "<<default>>", exchanges));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE);
+ assertEquals("Unexpected number of queues", 2, queues.size());
+ Map<String, Object> queue = find(Queue.NAME, "queue", queues);
+ Map<String, Object> ping = find(Queue.NAME, "ping", queues);
+ Asserts.assertQueue("queue", "standard", queue);
+ Asserts.assertQueue("ping", "standard", ping);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.FALSE, queue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.FALSE, ping.get(Queue.DURABLE));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails
+ .get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE);
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), _connection);
+ }
+
+ public void testPutCreateQueue() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ createQueue(queueName + "-standard", "standard", null);
+
+ Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>();
+ sortedQueueAttributes.put(Queue.SORT_KEY, "sortme");
+ createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes);
+
+ Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>();
+ priorityQueueAttributes.put(Queue.PRIORITIES, 10);
+ createQueue(queueName + "-priority", "priority", priorityQueueAttributes);
+
+ Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>();
+ lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ");
+ createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> standardQueue = find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = find(Queue.NAME, queueName + "-lvq" , queues);
+
+ Asserts.assertQueue(queueName + "-standard", "standard", standardQueue);
+ Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue);
+ Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue);
+ Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, standardQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, sortedQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE));
+
+ assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(Queue.SORT_KEY));
+ assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(Queue.LVQ_KEY));
+ assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(Queue.PRIORITIES));
+ }
+
+ public void testPutCreateExchange() throws Exception
+ {
+ String exchangeName = getTestName();
+
+ createExchange(exchangeName + "-direct", "direct");
+ createExchange(exchangeName + "-topic", "topic");
+ createExchange(exchangeName + "-headers", "headers");
+ createExchange(exchangeName + "-fanout", "fanout");
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+ Map<String, Object> directExchange = find(Queue.NAME, exchangeName + "-direct" , exchanges);
+ Map<String, Object> topicExchange = find(Queue.NAME, exchangeName + "-topic" , exchanges);
+ Map<String, Object> headersExchange = find(Queue.NAME, exchangeName + "-headers" , exchanges);
+ Map<String, Object> fanoutExchange = find(Queue.NAME, exchangeName + "-fanout" , exchanges);
+
+ Asserts.assertDurableExchange(exchangeName + "-direct", "direct", directExchange);
+ Asserts.assertDurableExchange(exchangeName + "-topic", "topic", topicExchange);
+ Asserts.assertDurableExchange(exchangeName + "-headers", "headers", headersExchange);
+ Asserts.assertDurableExchange(exchangeName + "-fanout", "fanout", fanoutExchange);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, directExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, topicExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, headersExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, fanoutExchange.get(Queue.DURABLE));
+
+ }
+
+ public void testPutCreateLVQWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName()+ "-lvq";
+ createQueue(queueName, "lvq", null);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> lvqQueue = find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "lvq", lvqQueue);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected lvq key attribute", AMQQueueFactory.QPID_LVQ_KEY, lvqQueue.get(Queue.LVQ_KEY));
+ }
+
+ public void testPutCreateSortedQueueWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName() + "-sorted";
+ int responseCode = tryCreateQueue(queueName, "sorted", null);
+ assertEquals("Unexpected response code", 409, responseCode);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> testQueue = find(Queue.NAME, queueName , queues);
+
+ assertNull("Sorted queue without a key was created ", testQueue);
+ }
+
+ public void testPutCreatePriorityQueueWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName()+ "-priority";
+ createQueue(queueName, "priority", null);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> priorityQueue = find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "priority", priorityQueue);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected number of priorities", 10, priorityQueue.get(Queue.PRIORITIES));
+ }
+
+ public void testPutCreateStandardQueueWithoutType() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> queue = find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "standard", queue);
+ }
+
+ public void testPutCreateQueueOfUnsupportedType() throws Exception
+ {
+ String queueName = getTestQueueName();
+ int responseCode = tryCreateQueue(queueName, "unsupported", null);
+ assertEquals("Unexpected response code", 409, responseCode);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> queue = find(Queue.NAME, queueName , queues);
+
+ assertNull("Queue of unsupported type was created", queue);
+ }
+
+ public void testDeleteQueue() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+
+ HttpURLConnection connection = openManagementConection("/rest/queue/test/" + queueName, "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getJsonAsList("/rest/queue/test/" + queueName);
+ assertEquals("Queue should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteQueueById() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+ Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName);
+
+ HttpURLConnection connection = openManagementConection("/rest/queue/test?id=" + queueDetails.get(Queue.ID), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getJsonAsList("/rest/queue/test/" + queueName);
+ assertEquals("Queue should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteExchange() throws Exception
+ {
+ String exchangeName = getTestName();
+ createExchange(exchangeName, "direct");
+
+ HttpURLConnection connection = openManagementConection("/rest/exchange/test/" + exchangeName, "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getJsonAsList("/rest/exchange/test/" + exchangeName);
+ assertEquals("Exchange should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteExchangeById() throws Exception
+ {
+ String exchangeName = getTestName();
+ createExchange(exchangeName, "direct");
+ Map<String, Object> echangeDetails = getJsonAsSingletonList("/rest/exchange/test/" + exchangeName);
+
+ HttpURLConnection connection = openManagementConection("/rest/exchange/test?id=" + echangeDetails.get(Exchange.ID), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getJsonAsList("/rest/exchange/test/" + exchangeName);
+ assertEquals("Exchange should be deleted", 0, queues.size());
+ }
+
+ public void testPutCreateQueueWithAttributes() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.ALERT_REPEAT_GAP, 1000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 3600000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 1000000000);
+ attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 800);
+ attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 15);
+ attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 2000000000);
+ attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 1500000000);
+
+ createQueue(queueName + "-standard", "standard", attributes);
+
+ Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>();
+ sortedQueueAttributes.putAll(attributes);
+ sortedQueueAttributes.put(Queue.SORT_KEY, "sortme");
+ createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes);
+
+ Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>();
+ priorityQueueAttributes.putAll(attributes);
+ priorityQueueAttributes.put(Queue.PRIORITIES, 10);
+ createQueue(queueName + "-priority", "priority", priorityQueueAttributes);
+
+ Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>();
+ lvqQueueAttributes.putAll(attributes);
+ lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ");
+ createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
+
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> standardQueue = find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = find(Queue.NAME, queueName + "-lvq" , queues);
+
+ attributes.put(Queue.DURABLE, Boolean.TRUE);
+ Asserts.assertQueue(queueName + "-standard", "standard", standardQueue, attributes);
+ Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue, attributes);
+ Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue, attributes);
+ Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue, attributes);
+
+ assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(Queue.SORT_KEY));
+ assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(Queue.LVQ_KEY));
+ assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(Queue.PRIORITIES));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testCreateQueueWithDLQEnabled() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AMQQueueFactory.X_QPID_DLQ_ENABLED, true);
+
+ //verify the starting state
+ Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+
+ assertNull("queue should not have already been present", find(Queue.NAME, queueName , queues));
+ assertNull("queue should not have already been present", find(Queue.NAME, queueName + "_DLQ" , queues));
+ assertNull("exchange should not have already been present", find(Exchange.NAME, queueName + "_DLE" , exchanges));
+
+ //create the queue
+ createQueue(queueName, "standard", attributes);
+
+ //verify the new queue, as well as the DLQueue and DLExchange have been created
+ hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+
+ Map<String, Object> queue = find(Queue.NAME, queueName , queues);
+ Map<String, Object> dlqQueue = find(Queue.NAME, queueName + "_DLQ" , queues);
+ Map<String, Object> dlExchange = find(Exchange.NAME, queueName + "_DLE" , exchanges);
+ assertNotNull("queue should not have been present", queue);
+ assertNotNull("queue should not have been present", dlqQueue);
+ assertNotNull("exchange should not have been present", dlExchange);
+
+ //verify that the alternate exchange is set as expected on the new queue
+ Map<String, Object> queueAttributes = new HashMap<String, Object>();
+ queueAttributes.put(Queue.ALTERNATE_EXCHANGE, queueName + "_DLE");
+
+ Asserts.assertQueue(queueName, "standard", queue, queueAttributes);
+ Asserts.assertQueue(queueName, "standard", queue, null);
+ }
+
+ private void createExchange(String exchangeName, String exchangeType) throws IOException
+ {
+ HttpURLConnection connection = openManagementConection("/rest/exchange/test/" + exchangeName, "PUT");
+
+ Map<String, Object> queueData = new HashMap<String, Object>();
+ queueData.put(Exchange.NAME, exchangeName);
+ queueData.put(Exchange.DURABLE, Boolean.TRUE);
+ queueData.put(Exchange.TYPE, exchangeType);
+
+ writeJsonRequest(connection, queueData);
+ assertEquals("Unexpected response code", 201, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ private void createQueue(String queueName, String queueType, Map<String, Object> attributes) throws IOException,
+ JsonGenerationException, JsonMappingException
+ {
+ int responseCode = tryCreateQueue(queueName, queueType, attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private int tryCreateQueue(String queueName, String queueType, Map<String, Object> attributes) throws IOException,
+ JsonGenerationException, JsonMappingException
+ {
+ HttpURLConnection connection = openManagementConection("/rest/queue/test/" + queueName, "PUT");
+
+ Map<String, Object> queueData = new HashMap<String, Object>();
+ queueData.put(Queue.NAME, queueName);
+ queueData.put(Queue.DURABLE, Boolean.TRUE);
+ if (queueType != null)
+ {
+ queueData.put(Queue.TYPE, queueType);
+ }
+ if (attributes != null)
+ {
+ queueData.putAll(attributes);
+ }
+
+ writeJsonRequest(connection, queueData);
+ int responseCode = connection.getResponseCode();
+ connection.disconnect();
+ return responseCode;
+ }
+
+}