summaryrefslogtreecommitdiff
path: root/qpid/java/broker-plugins/management-http
diff options
context:
space:
mode:
authorKim van der Riet <kpvdr@apache.org>2013-09-20 18:59:30 +0000
committerKim van der Riet <kpvdr@apache.org>2013-09-20 18:59:30 +0000
commitc70bf3ea28cdf6bafd8571690d3e5c466a0658a2 (patch)
tree68b24940e433f3f9c278b054d9ea1622389bd332 /qpid/java/broker-plugins/management-http
parentfcdf1723c7b5cdf0772054a93edb6e7d97c4bb1e (diff)
downloadqpid-python-c70bf3ea28cdf6bafd8571690d3e5c466a0658a2.tar.gz
QPID-4984: WIP - Merge from trunk r.1525056
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/linearstore@1525101 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/broker-plugins/management-http')
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java41
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java4
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileDetails.java78
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileHelper.java228
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/LogFileServlet.java105
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java30
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java4
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java68
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java25
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java17
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/PreferencesServlet.java137
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java4
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java215
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addPreferencesProvider.html47
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/add.html29
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/show.html21
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/common/TimeZoneSelector.html55
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css70
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showColumnDefDialog.html32
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showRowNumberLimitDialog.html33
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/auto-refresh.pngbin0 -> 535 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/download.pngbin0 -> 803 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/gear.pngbin0 -> 3512 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/help.pngbin0 -> 932 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/log-viewer.pngbin0 -> 719 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.pngbin6600 -> 6798 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/images/refresh.pngbin0 -> 468 bytes
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/index.html47
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/TimeZoneSelector.js176
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js73
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js140
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilter.js229
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilterTools.js270
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/FilterSummary.js173
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/GridUpdater.js258
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js96
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/UpdatableGrid.js56
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js32
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js115
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js52
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js204
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js179
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js7
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js198
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js49
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/preferences/filesystempreferences/add.js (renamed from qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/store/memory/add.js)35
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/preferences/filesystempreferences/show.js46
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js6
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js175
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js199
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js21
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogFileDownloadDialog.html33
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogViewer.html29
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html7
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html6
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferences.html83
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferencesProvider.html40
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/memory/add.html0
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/pool/none/add.html0
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementTest.java11
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/log/LogFileHelperTest.java339
66 files changed, 4452 insertions, 185 deletions
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index d87a1755da..c6623aefcf 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -20,9 +20,9 @@
*/
package org.apache.qpid.server.management.plugin;
-import java.io.File;
import java.lang.reflect.Type;
import java.net.SocketAddress;
+import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
@@ -31,6 +31,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
+import javax.net.ssl.SSLContext;
import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.logging.actors.CurrentActor;
@@ -39,11 +40,15 @@ import org.apache.qpid.server.management.plugin.filter.ForbiddingAuthorisationFi
import org.apache.qpid.server.management.plugin.filter.RedirectingAuthorisationFilter;
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.LogFileServlet;
import org.apache.qpid.server.management.plugin.servlet.rest.HelperServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.LogFileListingServlet;
import org.apache.qpid.server.management.plugin.servlet.rest.LogRecordsServlet;
import org.apache.qpid.server.management.plugin.servlet.rest.LogoutServlet;
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.PreferencesServlet;
+import org.apache.qpid.server.management.plugin.servlet.rest.UserPreferencesServlet;
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;
@@ -60,6 +65,7 @@ import org.apache.qpid.server.model.GroupProvider;
import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.Plugin;
import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.PreferencesProvider;
import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.model.Queue;
import org.apache.qpid.server.model.Session;
@@ -70,7 +76,6 @@ import org.apache.qpid.server.model.User;
import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
import org.apache.qpid.server.plugin.PluginFactory;
-import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.util.MapValueConverter;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.DispatcherType;
@@ -238,13 +243,17 @@ public class HttpManagement extends AbstractPluginAdapter implements HttpManagem
{
throw new IllegalConfigurationException("Key store is not configured. Cannot start management on HTTPS port without keystore");
}
- String keyStorePath = (String)keyStore.getAttribute(KeyStore.PATH);
- String keyStorePassword = keyStore.getPassword();
-
SslContextFactory factory = new SslContextFactory();
- factory.setKeyStorePath(keyStorePath);
- factory.setKeyStorePassword(keyStorePassword);
-
+ try
+ {
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(keyStore.getKeyManagers(), null, null);
+ factory.setSslContext(sslContext);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new RuntimeException("Cannot configure port " + port.getName() + " for transport " + Transport.SSL, e);
+ }
connector = new SslSocketConnector(factory);
}
else
@@ -288,7 +297,10 @@ public class HttpManagement extends AbstractPluginAdapter implements HttpManagem
addRestServlet(root, "keystore", KeyStore.class);
addRestServlet(root, "truststore", TrustStore.class);
addRestServlet(root, "plugin", Plugin.class);
+ addRestServlet(root, "preferencesprovider", AuthenticationProvider.class, PreferencesProvider.class);
+ root.addServlet(new ServletHolder(new UserPreferencesServlet()), "/rest/userpreferences/*");
+ root.addServlet(new ServletHolder(new PreferencesServlet()), "/rest/preferences");
root.addServlet(new ServletHolder(new StructureServlet()), "/rest/structure");
root.addServlet(new ServletHolder(new MessageServlet()), "/rest/message/*");
root.addServlet(new ServletHolder(new MessageContentServlet()), "/rest/message-content/*");
@@ -312,6 +324,15 @@ public class HttpManagement extends AbstractPluginAdapter implements HttpManagem
root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.txt");
root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.xsl");
root.addServlet(new ServletHolder(new HelperServlet()), "/rest/helper");
+ root.addServlet(new ServletHolder(new LogFileListingServlet()), "/rest/logfiles");
+ root.addServlet(new ServletHolder(new LogFileServlet()), "/rest/logfile");
+
+ String[] timeZoneFiles = {"africa", "antarctica", "asia", "australasia", "backward",
+ "etcetera", "europe", "northamerica", "pacificnew", "southamerica"};
+ for (String timeZoneFile : timeZoneFiles)
+ {
+ root.addServlet(new ServletHolder(FileServlet.INSTANCE), "/dojo/dojox/date/zoneinfo/" + timeZoneFile);
+ }
final SessionManager sessionManager = root.getSessionHandler().getSessionManager();
sessionManager.setSessionCookie(JSESSIONID_COOKIE_PREFIX + lastPort);
@@ -407,9 +428,9 @@ public class HttpManagement extends AbstractPluginAdapter implements HttpManagem
}
@Override
- public SubjectCreator getSubjectCreator(SocketAddress localAddress)
+ public AuthenticationProvider getAuthenticationProvider(SocketAddress localAddress)
{
- return getBroker().getSubjectCreator(localAddress);
+ return getBroker().getAuthenticationProvider(localAddress);
}
@Override
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
index 56919e2e6b..7d89daa427 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
@@ -22,7 +22,7 @@ package org.apache.qpid.server.management.plugin;
import java.net.SocketAddress;
-import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.model.AuthenticationProvider;
public interface HttpManagementConfiguration
{
@@ -34,5 +34,5 @@ public interface HttpManagementConfiguration
boolean isHttpBasicAuthenticationEnabled();
- SubjectCreator getSubjectCreator(SocketAddress localAddress);
+ AuthenticationProvider getAuthenticationProvider(SocketAddress localAddress);
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java
index 4c6e5bf63e..990ff1c53b 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java
@@ -168,7 +168,7 @@ public class HttpManagementUtil
{
Subject subject = null;
SocketAddress localAddress = getSocketAddress(request);
- SubjectCreator subjectCreator = managementConfig.getSubjectCreator(localAddress);
+ SubjectCreator subjectCreator = managementConfig.getAuthenticationProvider(localAddress).getSubjectCreator();
String remoteUser = request.getRemoteUser();
if (remoteUser != null || subjectCreator.isAnonymousAuthenticationAllowed())
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileDetails.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileDetails.java
new file mode 100644
index 0000000000..09dabd0e73
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileDetails.java
@@ -0,0 +1,78 @@
+/*
+ * 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.log;
+
+import java.io.File;
+
+public class LogFileDetails
+{
+ private String _name;
+ private File _location;
+ private String _mimeType;
+ private long _size;
+ private long _lastModified;
+ private String _appenderName;
+
+ public LogFileDetails(String name, String appenderName, File location, String mimeType, long fileSize, long lastUpdateTime)
+ {
+ super();
+ _name = name;
+ _location = location;
+ _mimeType = mimeType;
+ _size = fileSize;
+ _lastModified = lastUpdateTime;
+ _appenderName = appenderName;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public File getLocation()
+ {
+ return _location;
+ }
+
+ public String getMimeType()
+ {
+ return _mimeType;
+ }
+
+ public long getSize()
+ {
+ return _size;
+ }
+
+ public long getLastModified()
+ {
+ return _lastModified;
+ }
+
+ public String getAppenderName()
+ {
+ return _appenderName;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "LogFileDetails [name=" + _name + "]";
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileHelper.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileHelper.java
new file mode 100644
index 0000000000..03d98d020b
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/log/LogFileHelper.java
@@ -0,0 +1,228 @@
+/*
+ * 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.log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.QpidCompositeRollingAppender;
+
+public class LogFileHelper
+{
+ public static final String GZIP_MIME_TYPE = "application/x-gzip";
+ public static final String TEXT_MIME_TYPE = "text/plain";
+ public static final String ZIP_MIME_TYPE = "application/zip";
+ public static final String GZIP_EXTENSION = ".gz";
+ private static final int BUFFER_LENGTH = 1024 * 4;
+ private Collection<Appender> _appenders;
+
+ public LogFileHelper(Collection<Appender> appenders)
+ {
+ super();
+ _appenders = appenders;
+ }
+
+ public List<LogFileDetails> findLogFileDetails(String[] requestedFiles)
+ {
+ List<LogFileDetails> logFiles = new ArrayList<LogFileDetails>();
+ Map<String, List<LogFileDetails>> cache = new HashMap<String, List<LogFileDetails>>();
+ for (int i = 0; i < requestedFiles.length; i++)
+ {
+ String[] paths = requestedFiles[i].split("/");
+ if (paths.length != 2)
+ {
+ throw new IllegalArgumentException("Log file name '" + requestedFiles[i] + "' does not include an appender name");
+ }
+
+ String appenderName = paths[0];
+ String fileName = paths[1];
+
+ List<LogFileDetails> appenderFiles = cache.get(appenderName);
+ if (appenderFiles == null)
+ {
+ Appender fileAppender = null;
+ for (Appender appender : _appenders)
+ {
+ if (appenderName.equals(appender.getName()))
+ {
+ fileAppender = appender;
+ break;
+ }
+ }
+ if (fileAppender == null)
+ {
+ continue;
+ }
+ appenderFiles = getAppenderFiles(fileAppender, true);
+ if (appenderFiles == null)
+ {
+ continue;
+ }
+ cache.put(appenderName, appenderFiles);
+ }
+ for (LogFileDetails logFileDetails : appenderFiles)
+ {
+ if (logFileDetails.getName().equals(fileName))
+ {
+ logFiles.add(logFileDetails);
+ }
+ }
+ }
+ return logFiles;
+ }
+
+ public List<LogFileDetails> getLogFileDetails(boolean includeLogFileLocation)
+ {
+ List<LogFileDetails> results = new ArrayList<LogFileDetails>();
+ for (Appender appender : _appenders)
+ {
+ List<LogFileDetails> appenderFiles = getAppenderFiles(appender, includeLogFileLocation);
+ if (appenderFiles != null)
+ {
+ results.addAll(appenderFiles);
+ }
+ }
+ return results;
+ }
+
+ public void writeLogFiles(List<LogFileDetails> logFiles, OutputStream os) throws IOException
+ {
+ ZipOutputStream out = new ZipOutputStream(os);
+ try
+ {
+ addLogFileEntries(logFiles, out);
+ }
+ finally
+ {
+ out.close();
+ }
+ }
+
+ public void writeLogFile(File file, OutputStream os) throws IOException
+ {
+ FileInputStream fis = new FileInputStream(file);
+ try
+ {
+ byte[] bytes = new byte[BUFFER_LENGTH];
+ int length = 1;
+ while ((length = fis.read(bytes)) != -1)
+ {
+ os.write(bytes, 0, length);
+ }
+ }
+ finally
+ {
+ fis.close();
+ }
+ }
+
+ private List<LogFileDetails> getAppenderFiles(Appender appender, boolean includeLogFileLocation)
+ {
+ if (appender instanceof QpidCompositeRollingAppender)
+ {
+ return listAppenderFiles((QpidCompositeRollingAppender) appender, includeLogFileLocation);
+ }
+ else if (appender instanceof FileAppender)
+ {
+ return listAppenderFiles((FileAppender) appender, includeLogFileLocation);
+ }
+ return null;
+ }
+
+ private List<LogFileDetails> listAppenderFiles(FileAppender appender, boolean includeLogFileLocation)
+ {
+ String appenderFilePath = appender.getFile();
+ File appenderFile = new File(appenderFilePath);
+ if (appenderFile.exists())
+ {
+ return listLogFiles(appenderFile.getParentFile(), appenderFile.getName(), appender.getName(), "", includeLogFileLocation);
+ }
+ return Collections.emptyList();
+ }
+
+ private List<LogFileDetails> listAppenderFiles(QpidCompositeRollingAppender appender, boolean includeLogFileLocation)
+ {
+ List<LogFileDetails> files = listAppenderFiles((FileAppender) appender, includeLogFileLocation);
+ String appenderFilePath = appender.getFile();
+ File appenderFile = new File(appenderFilePath);
+ File backupFolder = new File(appender.getBackupFilesToPath());
+ if (backupFolder.exists())
+ {
+ String backFolderName = backupFolder.getName() + "/";
+ List<LogFileDetails> backedUpFiles = listLogFiles(backupFolder, appenderFile.getName(), appender.getName(),
+ backFolderName, includeLogFileLocation);
+ files.addAll(backedUpFiles);
+ }
+ return files;
+ }
+
+ private List<LogFileDetails> listLogFiles(File parent, String baseFileName, String appenderName, String relativePath,
+ boolean includeLogFileLocation)
+ {
+ List<LogFileDetails> files = new ArrayList<LogFileDetails>();
+ for (File file : parent.listFiles())
+ {
+ String name = file.getName();
+ if (name.startsWith(baseFileName))
+ {
+ files.add(new LogFileDetails(name, appenderName, includeLogFileLocation ? file : null, getMimeType(name), file.length(),
+ file.lastModified()));
+ }
+ }
+ return files;
+ }
+
+ private String getMimeType(String fileName)
+ {
+ if (fileName.endsWith(GZIP_EXTENSION))
+ {
+ return GZIP_MIME_TYPE;
+ }
+ return TEXT_MIME_TYPE;
+ }
+
+ private void addLogFileEntries(List<LogFileDetails> files, ZipOutputStream out) throws IOException
+ {
+ for (LogFileDetails logFileDetails : files)
+ {
+ File file = logFileDetails.getLocation();
+ if (file.exists())
+ {
+ ZipEntry entry = new ZipEntry(logFileDetails.getAppenderName() + "/" + logFileDetails.getName());
+ entry.setSize(file.length());
+ out.putNextEntry(entry);
+ writeLogFile(file, out);
+ out.closeEntry();
+ }
+ out.flush();
+ }
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/LogFileServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/LogFileServlet.java
new file mode 100644
index 0000000000..1fa03dc3dc
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/LogFileServlet.java
@@ -0,0 +1,105 @@
+/*
+ * 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.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.LogManager;
+import org.apache.qpid.server.management.plugin.log.LogFileDetails;
+import org.apache.qpid.server.management.plugin.log.LogFileHelper;
+import org.apache.qpid.server.management.plugin.servlet.rest.AbstractServlet;
+
+public class LogFileServlet extends AbstractServlet
+{
+ private static final long serialVersionUID = 1L;
+
+ public static final String LOGS_FILE_NAME = "qpid-logs-%s.zip";
+ public static final String DATE_FORMAT = "yyyy-MM-dd-mmHHss";
+
+ @SuppressWarnings("unchecked")
+ private LogFileHelper _helper = new LogFileHelper(Collections.list(LogManager.getRootLogger().getAllAppenders()));
+
+ @Override
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException,
+ ServletException
+ {
+ response.setHeader("Cache-Control", "no-cache");
+ response.setHeader("Pragma", "no-cache");
+ response.setDateHeader("Expires", 0);
+
+ if (!getBroker().getSecurityManager().authoriseLogsAccess())
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "Log files download is denied");
+ return;
+ }
+
+ String[] requestedFiles = request.getParameterValues("l");
+
+ if (requestedFiles == null || requestedFiles.length == 0)
+ {
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ List<LogFileDetails> logFiles = null;
+
+ try
+ {
+ logFiles = _helper.findLogFileDetails(requestedFiles);
+ }
+ catch(IllegalArgumentException e)
+ {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ if (logFiles.size() == 0)
+ {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ String fileName = String.format(LOGS_FILE_NAME, new SimpleDateFormat(DATE_FORMAT).format(new Date()));
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
+ response.setContentType(LogFileHelper.ZIP_MIME_TYPE);
+
+ OutputStream os = response.getOutputStream();
+ try
+ {
+ _helper.writeLogFiles(logFiles, os);
+ }
+ finally
+ {
+ if (os != null)
+ {
+ os.close();
+ }
+ }
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
index 9614ded3d8..c0f4b55f64 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
@@ -21,6 +21,7 @@
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.io.IOException;
+import java.io.PrintWriter;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@@ -40,6 +41,10 @@ import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
import org.apache.qpid.server.management.plugin.HttpManagementUtil;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.security.SecurityManager;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
public abstract class AbstractServlet extends HttpServlet
{
@@ -219,14 +224,7 @@ public abstract class AbstractServlet extends HttpServlet
}
finally
{
- try
- {
- SecurityManager.setThreadSubject(null);
- }
- finally
- {
- AMQShortString.clearLocalCache();
- }
+ SecurityManager.setThreadSubject(null);
}
}
@@ -261,4 +259,20 @@ public abstract class AbstractServlet extends HttpServlet
throw new RuntimeException("Failed to send error response code " + errorCode, e);
}
}
+
+ protected void sendJsonResponse(Object object, HttpServletResponse response) throws IOException,
+ JsonGenerationException, JsonMappingException
+ {
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+ response.setContentType("application/json");
+
+ final PrintWriter writer = response.getWriter();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, object);
+ }
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java
index 75e5bd9842..9ba36bb5c2 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java
@@ -41,6 +41,8 @@ import org.codehaus.jackson.map.SerializationConfig;
public class HelperServlet extends AbstractServlet
{
+ private static final long serialVersionUID = 1L;
+
private static final String PARAM_ACTION = "action";
private Map<String, Action> _actions;
@@ -55,6 +57,8 @@ public class HelperServlet extends AbstractServlet
new ListAuthenticationProviderAttributes(),
new ListBrokerAttribute(Broker.SUPPORTED_VIRTUALHOST_STORE_TYPES, "ListMessageStoreTypes"),
new ListBrokerAttribute(Broker.SUPPORTED_VIRTUALHOST_TYPES, "ListVirtualHostTypes"),
+ new ListBrokerAttribute(Broker.SUPPORTED_PREFERENCES_PROVIDERS_TYPES, "ListPreferencesProvidersTypes"),
+ new ListBrokerAttribute(Broker.PRODUCT_VERSION, "version"),
new ListGroupProviderAttributes(),
new ListAccessControlProviderAttributes(),
new PluginClassProviderAction()
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java
new file mode 100644
index 0000000000..b6face18e3
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java
@@ -0,0 +1,68 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.LogManager;
+import org.apache.qpid.server.management.plugin.log.LogFileDetails;
+import org.apache.qpid.server.management.plugin.log.LogFileHelper;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+
+public class LogFileListingServlet extends AbstractServlet
+{
+ private static final long serialVersionUID = 1L;
+
+ @SuppressWarnings("unchecked")
+ private LogFileHelper _helper = new LogFileHelper(Collections.list(LogManager.getRootLogger().getAllAppenders()));
+
+ @Override
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException,
+ ServletException
+ {
+ response.setHeader("Cache-Control", "no-cache");
+ response.setHeader("Pragma", "no-cache");
+ response.setDateHeader("Expires", 0);
+
+ if (!getBroker().getSecurityManager().authoriseLogsAccess())
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "Log files download is denied");
+ return;
+ }
+
+ List<LogFileDetails> logFiles = _helper.getLogFileDetails(false);
+ response.setContentType("application/json");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ final PrintWriter writer = response.getWriter();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ mapper.writeValue(writer, logFiles);
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
index f2cf5d7734..35523ddf0f 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
@@ -31,6 +31,10 @@ import org.codehaus.jackson.map.SerializationConfig;
public class LogRecordsServlet extends AbstractServlet
{
+ private static final long serialVersionUID = 2L;
+
+ public static final String PARAM_LAST_LOG_ID = "lastLogId";
+
public LogRecordsServlet()
{
super();
@@ -46,12 +50,31 @@ public class LogRecordsServlet extends AbstractServlet
response.setHeader("Pragma","no-cache");
response.setDateHeader ("Expires", 0);
+ if (!getBroker().getSecurityManager().authoriseLogsAccess())
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "Broker logs access is denied");
+ return;
+ }
+
+ long lastLogId = 0;
+ try
+ {
+ lastLogId = Long.parseLong(request.getParameter(PARAM_LAST_LOG_ID));
+ }
+ catch(Exception e)
+ {
+ // ignore null and incorrect parameter values
+ }
+
List<Map<String,Object>> logRecords = new ArrayList<Map<String, Object>>();
LogRecorder logRecorder = getBroker().getLogRecorder();
for(LogRecorder.Record record : logRecorder)
{
- logRecords.add(logRecordToObject(record));
+ if (record.getId() > lastLogId)
+ {
+ logRecords.add(logRecordToObject(record));
+ }
}
final PrintWriter writer = response.getWriter();
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
index 49e0c2b1bf..83208516c7 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
@@ -80,6 +80,7 @@ public class MessageServlet extends AbstractServlet
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
response.setDateHeader ("Expires", 0);
+ response.setContentType("application/json");
final PrintWriter writer = response.getWriter();
ObjectMapper mapper = new ObjectMapper();
@@ -352,20 +353,32 @@ public class MessageServlet extends AbstractServlet
if(messageHeader != null)
{
addIfPresent(object, "messageId", messageHeader.getMessageId());
- addIfPresent(object, "expirationTime", messageHeader.getExpiration());
+ addIfPresentAndNotZero(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());
+ addIfPresentAndNotZero(object, "timestamp", messageHeader.getTimestamp());
addIfPresent(object, "type", messageHeader.getType());
addIfPresent(object, "userId", messageHeader.getUserId());
}
}
+ private void addIfPresentAndNotZero(Map<String, Object> object, String name, Object property)
+ {
+ if(property instanceof Number)
+ {
+ Number value = (Number)property;
+ if (value.longValue() != 0)
+ {
+ object.put(name, property);
+ }
+ }
+ }
+
private void addIfPresent(Map<String, Object> object, String name, Object property)
{
if(property != null)
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/PreferencesServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/PreferencesServlet.java
new file mode 100644
index 0000000000..bf2a88a2c1
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/PreferencesServlet.java
@@ -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.
+ *
+ */
+
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.HttpManagementUtil;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.PreferencesProvider;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.codehaus.jackson.map.ObjectMapper;
+
+public class PreferencesServlet extends AbstractServlet
+{
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException,
+ ServletException
+ {
+ PreferencesProvider preferencesProvider = getPreferencesProvider(request);
+ if (preferencesProvider == null)
+ {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "Preferences provider is not configured");
+ return;
+ }
+ String userName = getAuthenticatedUserName(request);
+ Map<String, Object> preferences = preferencesProvider.getPreferences(userName);
+ if (preferences == null)
+ {
+ preferences = Collections.<String, Object>emptyMap();
+ }
+ sendJsonResponse(preferences, response);
+ }
+
+ /*
+ * replace preferences
+ */
+ @Override
+ protected void doPutWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ PreferencesProvider preferencesProvider = getPreferencesProvider(request);
+ if (preferencesProvider == null)
+ {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "Preferences provider is not configured");
+ return;
+ }
+ String userName = getAuthenticatedUserName(request);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> newPreferences = mapper.readValue(request.getInputStream(), LinkedHashMap.class);
+
+ preferencesProvider.deletePreferences(userName);
+ Map<String, Object> preferences = preferencesProvider.setPreferences(userName, newPreferences);
+ if (preferences == null)
+ {
+ preferences = Collections.<String, Object>emptyMap();
+ }
+ sendJsonResponse(preferences, response);
+ }
+
+ /*
+ * update preferences
+ */
+ @Override
+ protected void doPostWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ PreferencesProvider preferencesProvider = getPreferencesProvider(request);
+ if (preferencesProvider == null)
+ {
+ throw new IllegalStateException("Preferences provider is not configured");
+ }
+ String userName = getAuthenticatedUserName(request);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> newPreferences = mapper.readValue(request.getInputStream(), LinkedHashMap.class);
+ Map<String, Object> preferences = preferencesProvider.setPreferences(userName, newPreferences);
+ if (preferences == null)
+ {
+ preferences = Collections.<String, Object>emptyMap();
+ }
+ sendJsonResponse(preferences, response);
+ }
+
+ private String getAuthenticatedUserName(HttpServletRequest request)
+ {
+ Subject subject = getAuthorisedSubject(request);
+ Principal principal = AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
+ return principal.getName();
+ }
+
+ private PreferencesProvider getPreferencesProvider(HttpServletRequest request)
+ {
+ SocketAddress localAddress = HttpManagementUtil.getSocketAddress(request);
+ AuthenticationProvider authenticationProvider = getManagementConfiguration().getAuthenticationProvider(localAddress);
+ if (authenticationProvider == null)
+ {
+ throw new IllegalStateException("Authentication provider is not found");
+ }
+ return authenticationProvider.getPreferencesProvider();
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
index 1cebe3ec19..8ea0aa538a 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
@@ -123,7 +123,7 @@ public class RestServlet extends AbstractServlet
if(names.size() > _hierarchy.length)
{
- throw new IllegalArgumentException("Too many entries in path");
+ throw new IllegalArgumentException("Too many entries in path. Expected " + _hierarchy.length + "; path: " + names);
}
}
@@ -337,7 +337,7 @@ public class RestServlet extends AbstractServlet
if(names.size() != _hierarchy.length)
{
throw new IllegalArgumentException("Path to object to create must be fully specified. "
- + "Found " + names.size() + " expecting " + _hierarchy.length);
+ + "Found " + names + " of size " + names.size() + " expecting " + _hierarchy.length);
}
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
index b67c83dc7a..2b035fed8f 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
@@ -278,7 +278,7 @@ public class SaslServlet extends AbstractServlet
private SubjectCreator getSubjectCreator(HttpServletRequest request)
{
SocketAddress localAddress = HttpManagementUtil.getSocketAddress(request);
- return HttpManagementUtil.getManagementConfiguration(getServletContext()).getSubjectCreator(localAddress);
+ return HttpManagementUtil.getManagementConfiguration(getServletContext()).getAuthenticationProvider(localAddress).getSubjectCreator();
}
@Override
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java
new file mode 100644
index 0000000000..808e3210dd
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java
@@ -0,0 +1,215 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.PreferencesProvider;
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.server.security.access.Operation;
+
+public class UserPreferencesServlet extends AbstractServlet
+{
+ private static final Logger LOGGER = Logger.getLogger(UserPreferencesServlet.class);
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException,
+ ServletException
+ {
+ String[] pathElements = null;
+ if (request.getPathInfo() != null && request.getPathInfo().length() > 0)
+ {
+ pathElements = request.getPathInfo().substring(1).split("/");
+ }
+ if (pathElements != null && pathElements.length > 1)
+ {
+ getUserPreferences(pathElements[0], pathElements[1], response);
+ }
+ else
+ {
+ getUserList(pathElements, response);
+ }
+ }
+
+ private void getUserPreferences(String authenticationProviderName, String userId, HttpServletResponse response)
+ throws IOException
+ {
+ if (!userPreferencesOperationAuthorized(userId))
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "Vieweing of preferences is not allowed");
+ return;
+ }
+ Map<String, Object> preferences = null;
+ PreferencesProvider preferencesProvider = getPreferencesProvider(authenticationProviderName);
+ if (preferencesProvider == null)
+ {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "Preferences provider is not configured");
+ return;
+ }
+ preferences = preferencesProvider.getPreferences(userId);
+
+ sendJsonResponse(preferences, response);
+ }
+
+ private void getUserList(String[] pathElements, HttpServletResponse response) throws IOException
+ {
+ List<Map<String, Object>> users = null;
+ try
+ {
+ users = getUsers(pathElements);
+ }
+ catch (Exception e)
+ {
+ LOGGER.debug("Bad preferences request", e);
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
+ }
+ sendJsonResponse(users, response);
+ }
+
+ private PreferencesProvider getPreferencesProvider(String authenticationProviderName)
+ {
+ AuthenticationProvider authenticationProvider = getAuthenticationProvider(authenticationProviderName);
+ if (authenticationProvider == null)
+ {
+ throw new IllegalArgumentException(String.format("Authentication provider '%s' is not found",
+ authenticationProviderName));
+ }
+ PreferencesProvider preferencesProvider = authenticationProvider.getPreferencesProvider();
+ return preferencesProvider;
+ }
+
+ private AuthenticationProvider getAuthenticationProvider(String authenticationProviderName)
+ {
+ Broker broker = getBroker();
+ Collection<AuthenticationProvider> authenticationProviders = broker.getAuthenticationProviders();
+ for (AuthenticationProvider authenticationProvider : authenticationProviders)
+ {
+ if (authenticationProviderName.equals(authenticationProvider.getName()))
+ {
+ return authenticationProvider;
+ }
+ }
+ return null;
+ }
+
+ private List<Map<String, Object>> getUsers(String[] pathElements)
+ {
+ List<Map<String, Object>> users = new ArrayList<Map<String, Object>>();
+ String authenticationProviderName = pathElements != null && pathElements.length > 0 ? pathElements[0] : null;
+
+ Broker broker = getBroker();
+ Collection<AuthenticationProvider> authenticationProviders = broker.getAuthenticationProviders();
+ for (AuthenticationProvider authenticationProvider : authenticationProviders)
+ {
+ if (authenticationProviderName != null && !authenticationProvider.getName().equals(authenticationProviderName))
+ {
+ continue;
+ }
+ PreferencesProvider preferencesProvider = authenticationProvider.getPreferencesProvider();
+ if (preferencesProvider != null)
+ {
+ Set<String> usernames = preferencesProvider.listUserIDs();
+ for (String name : usernames)
+ {
+ Map<String, Object> userMap = new HashMap<String, Object>();
+ userMap.put(User.NAME, name);
+ userMap.put("authenticationProvider", authenticationProvider.getName());
+ users.add(userMap);
+ }
+ }
+ }
+ return users;
+ }
+
+ /*
+ * removes preferences
+ */
+ @Override
+ protected void doDeleteWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ final List<String[]> userData = new ArrayList<String[]>();
+ for (String name : request.getParameterValues("user"))
+ {
+ String[] elements = name.split("/");
+ if (elements.length != 2)
+ {
+ throw new IllegalArgumentException("Illegal parameter");
+ }
+ userData.add(elements);
+ }
+
+ if (!userData.isEmpty())
+ {
+ Broker broker = getBroker();
+ Collection<AuthenticationProvider> authenticationProviders = broker.getAuthenticationProviders();
+ for (Iterator<String[]> it = userData.iterator(); it.hasNext();)
+ {
+ String[] data = (String[]) it.next();
+ String authenticationProviderName = data[0];
+ String userId = data[1];
+
+ for (AuthenticationProvider authenticationProvider : authenticationProviders)
+ {
+ if (authenticationProviderName.equals(authenticationProvider.getName()))
+ {
+ PreferencesProvider preferencesProvider = authenticationProvider.getPreferencesProvider();
+ if (preferencesProvider != null)
+ {
+ Set<String> usernames = preferencesProvider.listUserIDs();
+ if (usernames.contains(userId))
+ {
+ if (!userPreferencesOperationAuthorized(userId))
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "Deletion of preferences is not allowed");
+ return;
+ }
+ preferencesProvider.deletePreferences(userId);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ private boolean userPreferencesOperationAuthorized(String userId)
+ {
+ return getBroker().getSecurityManager().authoriseUserOperation(Operation.UPDATE, userId);
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addPreferencesProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPreferencesProvider.html
new file mode 100644
index 0000000000..ac5dd32119
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPreferencesProvider.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="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Preferences Provider'" id="addPreferencesProvider">
+ <form id="formAddPreferencesProvider" method="post" data-dojo-type="dijit.form.Form">
+ <input type="hidden" id="preferencesProvider.id" name="id"/>
+ <div style="height:100px; width:420px; overflow: auto">
+ <table class="tableContainer-table tableContainer-table-horiz" width="100%" cellspacing="1">
+ <tr>
+ <td class="tableContainer-labelCell" style="width: 200px;"><strong>Type*:</strong></td>
+ <td class="tableContainer-valueCell"><div id="addPreferencesProvider.selectPreferencesProviderDiv"></div></td>
+ </tr>
+ <tr>
+ <td class="tableContainer-labelCell" style="width: 200px;"><strong>Name*:</strong></td>
+ <td class="tableContainer-valueCell"><input type="text" name="name"
+ id="preferencesProvider.name" data-dojo-type="dijit.form.ValidationTextBox"
+ data-dojo-props="placeHolder: 'Name',
+ required: true,
+ missingMessage: 'A name must be supplied',
+ title: 'Enter name',
+ pattern: '^[\x20-\x2e\x30-\x7F]{1,255}$'" /></td>
+ </tr>
+ </table>
+ <div id="preferencesProvider.fieldsContainer"></div>
+ </div>
+ <div class="dijitDialogPaneActionBar">
+ <!-- submit buttons -->
+ <input type="submit" value="Save Preferences Provider" data-dojo-props="label: 'Save Preferences Provider'" data-dojo-type="dijit.form.Button" />
+ <input type="button" value="Cancel" data-dojo-props="label: 'Cancel'" data-dojo-type="dijit.form.Button" id="addPreferencesProvider.cancelButton"/>
+ </div>
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/add.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/add.html
new file mode 100644
index 0000000000..f46da4b017
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/add.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.
+ -->
+<table class="tableContainer-table tableContainer-table-horiz" style="margin:0; width:100%" cellspacing="1">
+ <tr>
+ <td class="tableContainer-labelCell" style="width: 200px;"><strong>Path*: </strong></td>
+ <td class="tableContainer-valueCell" >
+ <input type="text" name="path"
+ id="preferencesProvider.path"
+ data-dojo-type="dijit.form.ValidationTextBox"
+ data-dojo-props="placeHolder: 'Path/to/file',
+ required: true,
+ missingMessage: 'A path must be supplied',
+ title: 'Enter path'"/></td>
+ </tr>
+</table>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/show.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/show.html
new file mode 100644
index 0000000000..bc302d1e65
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/preferences/filesystempreferences/show.html
@@ -0,0 +1,21 @@
+<!--
+ ~ 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 style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 100px;">Path:</div>
+ <div class="fileSystemPreferencesProviderPath" style="float:left;"></div>
+</div> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/common/TimeZoneSelector.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/common/TimeZoneSelector.html
new file mode 100644
index 0000000000..7027a4555c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/common/TimeZoneSelector.html
@@ -0,0 +1,55 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<table cellpadding="0" cellspacing="2">
+ <tr>
+ <td>Region</td>
+ <td>
+ <select class='timezoneRegion' name="region" data-dojo-type="dijit/form/FilteringSelect" data-dojo-props="
+ placeholder: 'Select region',
+ required: true,
+ missingMessage: 'A region must be supplied',
+ title: 'Select region',
+ autoComplete: true,
+ value:'undefined'">
+ <option value="undefined">Undefined</option>
+ <option value="Africa">Africa</option>
+ <option value="America">America</option>
+ <option value="Antarctica">Antarctica</option>
+ <option value="Arctic">Arctic</option>
+ <option value="Asia">Asia</option>
+ <option value="Atlantic">Atlantic</option>
+ <option value="Australia">Australia</option>
+ <option value="Europe">Europe</option>
+ <option value="Indian">Indian</option>
+ <option value="Pacific">Pacific</option>
+ </select>
+ </td>
+ <td>City</td>
+ <td>
+ <select class='timezoneCity' name="city" data-dojo-type="dijit/form/FilteringSelect" data-dojo-props="
+ placeholder: 'Select city',
+ required: true,
+ missingMessage: 'A city must be supplied',
+ title: 'Select city'">
+ </select>
+ </td>
+ </tr>
+</table> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css b/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css
index 4c8b79ab82..d9064f40c9 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css
@@ -92,4 +92,74 @@ div .messages {
.formLabel-labelCell {
font-weight: bold;
+}
+
+.columnDefDialogButtonIcon {
+ background: url("../dojo/dojox/grid/enhanced/resources/images/sprite_icons.png") no-repeat;
+ background-position: -260px 2px;
+ width: 14px;
+ height: 14px;
+}
+
+.logViewerIcon {
+ background: url("../images/log-viewer.png") no-repeat;
+ width: 14px;
+ height: 16px;
+}
+
+.downloadLogsIcon {
+ background: url("../images/download.png") no-repeat;
+ width: 14px;
+ height: 14px;
+}
+
+.dojoxGridFBarClearFilterButtontnIcon
+{
+ background: url("../dojo/dojox/grid/enhanced/resources/images/sprite_icons.png") no-repeat;
+ background-position: -120px -18px;
+ width: 14px;
+ height: 14px;
+}
+
+.rowNumberLimitIcon
+{
+ background: url("../dojo/dojox/grid/enhanced/resources/images/sprite_icons.png") no-repeat;
+ background-position: -240px -18px;
+ width: 14px;
+ height: 14px;
+}
+
+.gridRefreshIcon
+{
+ background: url("../images/refresh.png") no-repeat;
+ width: 16px;
+ height: 16px;
+}
+
+.gridAutoRefreshIcon
+{
+ background: url("../images/auto-refresh.png") no-repeat;
+ width: 16px;
+ height: 16px;
+}
+
+.redBackground tr{ background-color:#ffdcd7 !important; background-image: none !important;}
+.yellowBackground tr{background-color:#fbfddf !important; background-image: none !important;}
+.grayBackground tr{background-color:#eeeeee !important; background-image: none !important;}
+.dojoxGridRowOdd.grayBackground tr{ background-color:#e9e9e9 !important; background-image: none !important;}
+.dojoxGridRowOdd.yellowBackground tr{background-color:#fafdd5 !important; background-image: none !important;}
+.dojoxGridRowOdd.redBackground tr{background-color:#f4c1c1 !important; background-image: none !important;}
+
+.preferencesIcon
+{
+ background: url("../images/gear.png") no-repeat;
+ width: 16px;
+ height: 16px;
+}
+
+.helpIcon
+{
+ background: url("../images/help.png") no-repeat;
+ width: 16px;
+ height: 16px;
} \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showColumnDefDialog.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showColumnDefDialog.html
new file mode 100644
index 0000000000..5b6b8ad774
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showColumnDefDialog.html
@@ -0,0 +1,32 @@
+<!--
+ -
+ - 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>
+ <div>
+ <div>Select columns to display:</div>
+ <div class="columnList"></div>
+ </div>
+ <div class="dijitDialogPaneActionBar">
+ <button value="Display" data-dojo-type="dijit.form.Button"
+ class="displayButton" data-dojo-props="label: 'Display' "></button>
+ <button value="Cancel" data-dojo-type="dijit.form.Button" data-dojo-props="label: 'Cancel'"
+ class="cancelButton"></button>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showRowNumberLimitDialog.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showRowNumberLimitDialog.html
new file mode 100644
index 0000000000..087d54c0f9
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/grid/showRowNumberLimitDialog.html
@@ -0,0 +1,33 @@
+<!--
+ -
+ - 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>
+ <div>
+ <div>Set the maximum number of rows to cache and display:</div>
+ <input class="rowNumberLimit" data-dojo-type="dijit.form.NumberSpinner"
+ data-dojo-props="invalidMessage: 'Invalid value', required: true, smallDelta: 1,mconstraints: {min:1,max:65535,places:0, pattern: '#####'}, label: 'Maximum number of rows:', name: 'rowNumberLimit'"></input>
+ </div>
+ <div class="dijitDialogPaneActionBar">
+ <button value="Submit" data-dojo-type="dijit.form.Button"
+ class="submitButton" data-dojo-props="label: 'Submit' "></button>
+ <button value="Cancel" data-dojo-type="dijit.form.Button" data-dojo-props="label: 'Cancel'"
+ class="cancelButton"></button>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/auto-refresh.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/auto-refresh.png
new file mode 100644
index 0000000000..493636f467
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/auto-refresh.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/download.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/download.png
new file mode 100644
index 0000000000..b64b41d476
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/download.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/gear.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/gear.png
new file mode 100644
index 0000000000..0bb4394b46
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/gear.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/help.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/help.png
new file mode 100644
index 0000000000..f7d3698d25
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/help.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/log-viewer.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/log-viewer.png
new file mode 100644
index 0000000000..858fd48beb
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/log-viewer.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png
index 95d49ea469..ae0fbb462f 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/qpid-logo.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/images/refresh.png b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/refresh.png
new file mode 100644
index 0000000000..083044979b
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/images/refresh.png
Binary files differ
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
index 4b97c464ec..4fc961ec12 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
@@ -42,7 +42,6 @@
var dojoConfig = {
tlmSiblingOfDojo:false,
- parseOnLoad:true,
async:true,
baseUrl: getContextPath(),
packages:[
@@ -58,7 +57,14 @@
</script>
<script>
- require(["dijit/layout/BorderContainer",
+ var qpidHelpLocation = "http://qpid.apache.org/releases/qpid-";
+ var qpidHelpURL = null;
+ var qpidPreferences = null;
+ require([
+ "dojo/_base/xhr",
+ "dojo/parser",
+ "qpid/management/Preferences",
+ "dijit/layout/BorderContainer",
"dijit/layout/TabContainer",
"dijit/layout/ContentPane",
"dijit/TitlePane",
@@ -66,7 +72,18 @@
"qpid/management/treeView",
"qpid/management/controller",
"qpid/common/footer",
- "qpid/authorization/checkUser"]);
+ "qpid/authorization/checkUser"], function(xhr, parser, Preferences){
+ parser.parse();
+ qpidPreferences = new Preferences();
+ xhr.get({
+ sync: true,
+ url: "rest/helper?action=version",
+ handleAs: "json"
+ }).then(function(qpidVersion) {
+ qpidHelpURL = qpidHelpLocation + qpidVersion + "/java-broker/book/index.html";
+ });
+
+ });
</script>
</head>
@@ -75,7 +92,27 @@
<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" style="float: left; width: 300px"></div>
- <div id="login" style="float: right; display:none"><strong>User: </strong> <span id="authenticatedUser"></span><a href="logout">[logout]</a></div>
+ <div style="float: right;">
+ <div id="login" style="display:none"><strong>User: </strong> <span id="authenticatedUser"></span><a href="logout">[logout]</a></div>
+ <div id="preferencesButton" style="float: right; margin-top: 0px;" data-dojo-type="dijit.form.DropDownButton" data-dojo-props="iconClass: 'preferencesIcon', title: 'Preferences', showLabel:false">
+ <div data-dojo-type="dijit.Menu">
+ <div data-dojo-type="dijit.MenuItem" data-dojo-props="
+ iconClass: 'dijitIconFunction',
+ onClick: function(){ qpidPreferences.showDialog(); } ">
+ Preferences
+ </div>
+ <!--
+ <div data-dojo-type="dijit.MenuItem" data-dojo-props="iconClass: 'dijitIconMail', onClick: function(){ console.log('TODO'); }">
+ Contacts
+ </div>
+ -->
+ <div data-dojo-type="dijit.MenuItem" data-dojo-props="iconClass: 'helpIcon', onClick: function(){
+ var newWindow = window.open(qpidHelpURL,'QpidHelp','height=600,width=600,scrollbars=1,location=1,resizable=1,status=0,toolbar=0,titlebar=1,menubar=0',true); newWindow.focus(); } ">
+ Help
+ </div>
+ </div>
+ </div>
+ </div>
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'leading', splitter: true" style="width:20%">
<div qpid-type="treeView" qpid-props="query: 'rest/structure'" ></div>
@@ -104,4 +141,4 @@
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js
index 159c7458ed..d65e6c6e07 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js
@@ -29,7 +29,7 @@ var updateUI = function updateUI(data)
if(data.user)
{
dom.byId("authenticatedUser").innerHTML = entities.encode(String(data.user));
- dom.byId("login").style.display = "block";
+ dom.byId("login").style.display = "inline";
}
};
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/TimeZoneSelector.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/TimeZoneSelector.js
new file mode 100644
index 0000000000..287fbc9619
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/TimeZoneSelector.js
@@ -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.
+ *
+ */
+define([
+ "dojo/_base/declare",
+ "dojo/_base/array",
+ "dojo/dom-construct",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/store/Memory",
+ "dijit/_WidgetBase",
+ "dijit/registry",
+ "dojo/text!common/TimeZoneSelector.html",
+ "dijit/form/ComboBox",
+ "dijit/form/FilteringSelect",
+ "dojox/date/timezone",
+ "dojox/validate/us",
+ "dojox/validate/web",
+ "dojo/domReady!"],
+function (declare, array, domConstruct, parser, query, Memory, _WidgetBase, registry, template) {
+
+ var preferencesRegions = ["Africa","America","Antarctica","Arctic","Asia","Atlantic","Australia","Europe","Indian","Pacific"];
+
+ function initSupportedTimeZones()
+ {
+ var supportedTimeZones = [];
+ var allTimeZones = dojox.date.timezone.getAllZones();
+ for(var i = 0; i < allTimeZones.length; i++)
+ {
+ var timeZone = allTimeZones[i];
+ var elements = timeZone.split("/");
+ if (elements.length > 1)
+ {
+ for(var j = 0; j<preferencesRegions.length; j++)
+ {
+ if (elements[0] == preferencesRegions[j])
+ {
+ supportedTimeZones.push({id: timeZone, region: elements[0], city: elements.slice(1).join("/").replace("_", " ") })
+ break;
+ }
+ }
+ }
+ }
+ return supportedTimeZones;
+ }
+
+ function initSupportedRegions()
+ {
+ var supportedRegions = [{"id": "undefined", "name": "Undefined"}];
+ for(var j = 0; j<preferencesRegions.length; j++)
+ {
+ supportedRegions.push({id: preferencesRegions[j], name: preferencesRegions[j] });
+ }
+ return supportedRegions;
+ }
+
+ return declare("qpid.common.TimeZoneSelector", [_WidgetBase], {
+
+ value: null,
+ domNode: null,
+ _regionSelector: null,
+ _citySelector: null,
+
+ constructor: function(args)
+ {
+ this._args = args;
+ },
+
+ buildRendering: function(){
+ this.domNode = domConstruct.create("div", {innerHTML: template});
+ parser.parse(this.domNode);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ var supportedTimeZones = initSupportedTimeZones();
+
+ this._citySelector = registry.byNode(query(".timezoneCity", this.domNode)[0]);
+ this._citySelector.set("searchAttr", "city");
+ this._citySelector.set("query", {region: /.*/});
+ this._citySelector.set("labelAttr", "city");
+ this._citySelector.set("store", new Memory({ data: supportedTimeZones }));
+ if (this._args.name)
+ {
+ this._citySelector.set("name", this._args.name);
+ }
+ this._regionSelector = registry.byNode(query(".timezoneRegion", this.domNode)[0]);
+ var supportedRegions = initSupportedRegions();
+ this._regionSelector.set("store", new Memory({ data: supportedRegions }));
+ var self = this;
+
+ this._regionSelector.on("change", function(value){
+ if (value=="undefined")
+ {
+ self._citySelector.set("disabled", true);
+ self._citySelector.query.region = /.*/;
+ self.value = null;
+ self._citySelector.set("value", null);
+ }
+ else
+ {
+ self._citySelector.set("disabled", false);
+ self._citySelector.query.region = value || /.*/;
+ if (this.timeZone)
+ {
+ self._citySelector.set("value", this.timeZone);
+ this.timeZone = null;
+ }
+ else
+ {
+ self._citySelector.set("value", null);
+ }
+ }
+ });
+
+ this._citySelector.on("change", function(value){
+ self.value = value;
+ });
+
+ this._setValueAttr(this._args.value);
+ },
+
+ _setValueAttr: function(value)
+ {
+ if (value)
+ {
+ var elements = value.split("/");
+ if (elements.length > 1)
+ {
+ this._regionSelector.timeZone = value;
+ this._regionSelector.set("value", elements[0]);
+ this._citySelector.set("value", value);
+ }
+ else
+ {
+ this._regionSelector.set("value", "undefined");
+ }
+ }
+ else
+ {
+ this._regionSelector.set("value", "undefined");
+ }
+ this.value = value;
+ },
+
+ destroy: function()
+ {
+ if (this.domNode)
+ {
+ this.domNode.destroy();
+ this.domNode = null;
+ }
+ _regionSelector: null;
+ _citySelector: null;
+ }
+
+ });
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js
index f7ede1a7f7..ea3ba78372 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/UpdatableStore.js
@@ -23,12 +23,13 @@ define(["dojo/store/Memory",
"dojo/data/ObjectStore",
"dojo/store/Observable"], function (Memory, DataGrid, ObjectStore, Observable) {
- function UpdatableStore( data, divName, structure, func, props, Grid ) {
+ function UpdatableStore( data, divName, structure, func, props, Grid, notObservable ) {
var that = this;
var GridType = DataGrid;
- that.store = Observable(Memory({data: data, idProperty: "id"}));
+ that.memoryStore = new Memory({data: data, idProperty: "id"});
+ that.store = notObservable? that.memoryStore : new Observable(that.memoryStore);
that.dataStore = ObjectStore({objectStore: that.store});
var gridProperties = { store: that.dataStore,
@@ -63,7 +64,7 @@ define(["dojo/store/Memory",
UpdatableStore.prototype.update = function(data)
{
-
+ var changed = false;
var store = this.store;
var theItem;
@@ -78,7 +79,7 @@ define(["dojo/store/Memory",
}
}
store.remove(object.id);
-
+ changed = true;
});
// iterate over data...
@@ -91,20 +92,84 @@ define(["dojo/store/Memory",
if(theItem[ propName ] != data[i][ propName ]) {
theItem[ propName ] = data[i][ propName ];
modified = true;
+ changed = true;
}
}
}
if(modified) {
// ... check attributes for updates
store.notify(theItem, data[i].id);
+ changed = true;
}
} else {
// ,,, if not in the store then add
store.put(data[i]);
+ changed = true;
}
}
}
+ return changed;
+ };
+
+ function removeItemsFromArray(items, numberToRemove)
+ {
+ if (items)
+ {
+ if (numberToRemove > 0 && items.length > 0)
+ {
+ if (numberToRemove >= items.length)
+ {
+ numberToRemove = numberToRemove - items.length;
+ items.length = 0
+ }
+ else
+ {
+ items.splice(0, numberToRemove);
+ numberToRemove = 0;
+ }
+ }
+ }
+ return numberToRemove;
+ };
+
+ UpdatableStore.prototype.append = function(data, limit)
+ {
+ var changed = false;
+ var items = this.memoryStore.data;
+
+ if (limit)
+ {
+ var totalSize = items.length + (data ? data.length : 0);
+ var numberToRemove = totalSize - limit;
+
+ if (numberToRemove > 0)
+ {
+ changed = true;
+ numberToRemove = removeItemsFromArray(items, numberToRemove);
+ if (numberToRemove > 0)
+ {
+ removeItemsFromArray(data, numberToRemove);
+ }
+ }
+ }
+
+ if (data && data.length > 0)
+ {
+ changed = true;
+ items.push.apply(items, data);
+ }
+
+ this.memoryStore.setData(items);
+ return changed;
+ };
+
+ UpdatableStore.prototype.close = function()
+ {
+ this.dataStore.close();
+ this.dataStore = null;
+ this.store = null;
+ this.memoryStore = null;
};
return UpdatableStore;
});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js
new file mode 100644
index 0000000000..d285dfaad6
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js
@@ -0,0 +1,140 @@
+/*
+ *
+ * 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/declare",
+ "dojo/_base/event",
+ "dojo/_base/array",
+ "dojo/_base/lang",
+ "dojo/parser",
+ "dojo/dom-construct",
+ "dojo/query",
+ "dijit/registry",
+ "dijit/form/Button",
+ "dijit/form/CheckBox",
+ "dojox/grid/enhanced/plugins/Dialog",
+ "dojo/text!../../../grid/showColumnDefDialog.html",
+ "dojo/domReady!"
+], function(declare, event, array, lang, parser, dom, query, registry, Button, CheckBox, Dialog, template ){
+
+
+return declare("qpid.common.grid.ColumnDefDialog", null, {
+
+ grid: null,
+ containerNode: null,
+ _columns: [],
+ _dialog: null,
+
+ constructor: function(args){
+ var grid = this.grid = args.grid;
+
+ this.containerNode = dom.create("div", {innerHTML: template});
+ parser.parse(this.containerNode);
+
+ var submitButton = registry.byNode(query(".displayButton", this.containerNode)[0]);
+ this.closeButton = registry.byNode(query(".cancelButton", this.containerNode)[0]);
+ var columnsContainer = query(".columnList", this.containerNode)[0];
+
+ this._buildColumnWidgets(columnsContainer);
+
+ this._dialog = new Dialog({
+ "refNode": this.grid.domNode,
+ "title": "Grid Columns",
+ "content": this.containerNode
+ });
+
+ var self = this;
+ submitButton.on("click", function(e){self._onColumnsSelect(e); });
+ this.closeButton.on("click", function(e){self._dialog.hide(); });
+
+ this._dialog.startup();
+ },
+
+ destroy: function(){
+ this._dialog.destroyRecursive();
+ this._dialog = null;
+ this.grid = null;
+ this.containerNode = null;
+ this._columns = null;
+ },
+
+ showDialog: function(){
+ this._initColumnWidgets();
+ this._dialog.show();
+ },
+
+ _initColumnWidgets: function()
+ {
+ var cells = this.grid.layout.cells;
+ for(var i in cells)
+ {
+ var cell = cells[i];
+ this._columns[cell.name].checked = !cell.hidden;
+ }
+ },
+
+ _onColumnsSelect: function(evt){
+ event.stop(evt);
+ var grid = this.grid;
+ grid.beginUpdate();
+ var cells = grid.layout.cells;
+ try
+ {
+ for(var i in cells)
+ {
+ var cell = cells[i];
+ var widget = this._columns[cell.name];
+ grid.layout.setColumnVisibility(i, widget.checked);
+ }
+ }
+ finally
+ {
+ grid.endUpdate();
+ this._dialog.hide();
+ }
+ },
+
+ _buildColumnWidgets: function(columnsContainer)
+ {
+ var cells = this.grid.layout.cells;
+ for(var i in cells)
+ {
+ var cell = cells[i];
+ var widget = new dijit.form.CheckBox({
+ required: false,
+ checked: !cell.hidden,
+ label: cell.name,
+ name: this.grid.id + "_cchb_ " + i
+ });
+
+ this._columns[cell.name] = widget;
+
+ var div = dom.create("div");
+ div.appendChild(widget.domNode);
+ div.appendChild(dom.create("span", {innerHTML: cell.name}));
+
+ columnsContainer.appendChild(div);
+ }
+ }
+
+ });
+
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilter.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilter.js
new file mode 100644
index 0000000000..9c0baf3111
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilter.js
@@ -0,0 +1,229 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+define([
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dijit/Toolbar",
+ "dojox/grid/enhanced/_Plugin",
+ "dojox/grid/enhanced/plugins/Dialog",
+ "dojox/grid/enhanced/plugins/filter/FilterLayer",
+ "dojox/grid/enhanced/plugins/filter/FilterDefDialog",
+ "dojox/grid/enhanced/plugins/filter/FilterStatusTip",
+ "dojox/grid/enhanced/plugins/filter/ClearFilterConfirm",
+ "dojox/grid/EnhancedGrid",
+ "dojo/i18n!dojox/grid/enhanced/nls/Filter",
+ "qpid/common/grid/EnhancedFilterTools"
+], function(declare, lang, array, Toolbar, _Plugin,
+ Dialog, FilterLayer, FilterDefDialog, FilterStatusTip, ClearFilterConfirm, EnhancedGrid, nls, EnhancedFilterTools){
+
+ // override CriteriaBox#_getColumnOptions to show criteria for hidden columns with EnhancedFilter
+ dojo.extend(dojox.grid.enhanced.plugins.filter.CriteriaBox, {
+ _getColumnOptions: function(){
+ var colIdx = this.dlg.curColIdx >= 0 ? String(this.dlg.curColIdx) : "anycolumn";
+ var filterHidden = this.plugin.filterHidden;
+ return array.map(array.filter(this.plugin.grid.layout.cells, function(cell){
+ return !(cell.filterable === false || (!filterHidden && cell.hidden));
+ }), function(cell){
+ return {
+ label: cell.name || cell.field,
+ value: String(cell.index),
+ selected: colIdx == String(cell.index)
+ };
+ });
+ }
+ });
+
+ // Enhanced filter has extra functionality for refreshing, limiting rows, displaying/hiding columns in the grid
+ var EnhancedFilter = declare("qpid.common.grid.EnhancedFilter", _Plugin, {
+ // summary:
+ // Accept the same plugin parameters as dojox.grid.enhanced.plugins.Filter and the following:
+ //
+ // filterHidden: boolean:
+ // Whether to display filtering criteria for hidden columns. Default to true.
+ //
+ // defaulGridRowLimit: int:
+ // Default limit for numbers of items to cache in the gris dtore
+ //
+ // disableFiltering: boolean:
+ // Whether to disable a filtering including filter button, clear filter button and filter summary.
+ //
+ // toolbar: dijit.Toolbar:
+ // An instance of toolbar to add the enhanced filter widgets.
+
+
+ // name: String
+ // plugin name
+ name: "enhancedFilter",
+
+ // filterHidden: Boolean
+ // whether to filter hidden columns
+ filterHidden: true,
+
+ constructor: function(grid, args){
+ // summary:
+ // See constructor of dojox.grid.enhanced._Plugin.
+ this.grid = grid;
+ this.nls = nls;
+
+ args = this.args = lang.isObject(args) ? args : {};
+ if(typeof args.ruleCount != 'number' || args.ruleCount < 0){
+ args.ruleCount = 0;
+ }
+ var rc = this.ruleCountToConfirmClearFilter = args.ruleCountToConfirmClearFilter;
+ if(rc === undefined){
+ this.ruleCountToConfirmClearFilter = 5;
+ }
+
+ if (args.filterHidden){
+ this.filterHidden = args.filterHidden;
+ }
+ this.defaulGridRowLimit = args.defaulGridRowLimit;
+ this.disableFiltering = args.disableFiltering;
+
+ //Install UI components
+ var obj = { "plugin": this };
+
+ this.filterBar = ( args.toolbar && args.toolbar instanceof dijit.Toolbar) ? args.toolbar: new Toolbar();
+
+ if (!this.disableFiltering)
+ {
+ //Install filter layer
+ this._wrapStore();
+
+ this.clearFilterDialog = new Dialog({
+ refNode: this.grid.domNode,
+ title: this.nls["clearFilterDialogTitle"],
+ content: new ClearFilterConfirm(obj)
+ });
+
+ this.filterDefDialog = new FilterDefDialog(obj);
+
+ nls["statusTipTitleNoFilter"] = "Filter is not set";
+ nls["statusTipMsg"] = "Click on 'Set Filter' button to specify filtering conditions";
+ this.filterStatusTip = new FilterStatusTip(obj);
+
+ var self = this;
+ var toggleClearFilterBtn = function (arg){ self.enhancedFilterTools.toggleClearFilterBtn(arg); };
+
+ this.filterBar.toggleClearFilterBtn = toggleClearFilterBtn;
+
+ this.grid.isFilterBarShown = function (){return true};
+
+ this.connect(this.grid.layer("filter"), "onFilterDefined", function(filter){
+ toggleClearFilterBtn(true);
+ });
+
+ //Expose the layer event to grid.
+ grid.onFilterDefined = function(){};
+ this.connect(grid.layer("filter"), "onFilterDefined", function(filter){
+ grid.onFilterDefined(grid.getFilter(), grid.getFilterRelation());
+ });
+ }
+
+ // add extra buttons into toolbar
+ this.enhancedFilterTools = new EnhancedFilterTools({
+ grid: grid,
+ toolbar: this.filterBar,
+ filterStatusTip: this.filterStatusTip,
+ clearFilterDialog: this.clearFilterDialog,
+ filterDefDialog: this.filterDefDialog,
+ defaulGridRowLimit: this.defaulGridRowLimit,
+ disableFiltering: this.disableFiltering,
+ nls: nls
+ });
+
+ this.filterBar.placeAt(this.grid.viewsHeaderNode, "before");
+ this.filterBar.startup();
+
+ },
+
+ destroy: function(){
+ this.inherited(arguments);
+ try
+ {
+ if (this.filterDefDialog)
+ {
+ this.filterDefDialog.destroy();
+ this.filterDefDialog = null;
+ }
+ if (this.grid)
+ {
+ this.grid.unwrap("filter");
+ this.grid = null;
+ }
+ if (this.filterBar)
+ {
+ this.filterBar.destroyRecursive();
+ this.filterBar = null;
+ }
+ if (this.enhancedFilterTools)
+ {
+ this.enhancedFilterTools.destroy();
+ this.enhancedFilterTools = null;
+ }
+ if (this.clearFilterDialog)
+ {
+ this.clearFilterDialog.destroyRecursive();
+ this.clearFilterDialog = null;
+ }
+ if (this.filterStatusTip)
+ {
+ this.filterStatusTip.destroy();
+ this.filterStatusTip = null;
+ }
+ this.args = null;
+
+ }catch(e){
+ console.warn("Filter.destroy() error:",e);
+ }
+ },
+
+ _wrapStore: function(){
+ var g = this.grid;
+ var args = this.args;
+ var filterLayer = args.isServerSide ? new FilterLayer.ServerSideFilterLayer(args) :
+ new FilterLayer.ClientSideFilterLayer({
+ cacheSize: args.filterCacheSize,
+ fetchAll: args.fetchAllOnFirstFilter,
+ getter: this._clientFilterGetter
+ });
+ FilterLayer.wrap(g, "_storeLayerFetch", filterLayer);
+
+ this.connect(g, "_onDelete", lang.hitch(filterLayer, "invalidate"));
+ },
+
+ onSetStore: function(store){
+ this.filterDefDialog.clearFilter(true);
+ },
+
+ _clientFilterGetter: function(/* data item */ datarow,/* cell */cell, /* int */rowIndex){
+ return cell.get(rowIndex, datarow);
+ }
+
+ });
+
+ EnhancedGrid.registerPlugin(EnhancedFilter);
+
+ return EnhancedFilter;
+
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilterTools.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilterTools.js
new file mode 100644
index 0000000000..b1645b4905
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/EnhancedFilterTools.js
@@ -0,0 +1,270 @@
+/*
+ *
+ * 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/declare",
+ "dojo/_base/event",
+ "dijit/form/Button",
+ "dijit/form/ToggleButton",
+ "qpid/common/grid/RowNumberLimitDialog",
+ "qpid/common/grid/ColumnDefDialog",
+ "qpid/common/grid/FilterSummary"
+], function(declare, event, Button, ToggleButton, RowNumberLimitDialog, ColumnDefDialog, FilterSummary){
+
+ var _stopEvent = function (evt){
+ try{
+ if(evt && evt.preventDefault){
+ event.stop(evt);
+ }
+ }catch(e){}
+ };
+
+ return declare("qpid.common.grid.EnhancedFilterTools", null, {
+
+ grid: null,
+ filterBar: null,
+ filterStatusTip: null,
+ clearFilterDialog: null,
+ filterDefDialog: null,
+
+ columnDefDialog: null,
+ columnDefButton: null,
+ filterDefButton: null,
+ clearFilterButton: null,
+ filterSummary: null,
+ setRowNumberLimitButton: null,
+ setRowNumberLimitDialog: null,
+ refreshButton: null,
+ autoRefreshButton: null,
+
+ constructor: function(params)
+ {
+ this.inherited(arguments);
+
+ this.filterBar = params.toolbar;
+ this.grid = params.grid;
+ this.filterStatusTip= params.filterStatusTip;
+ this.clearFilterDialog = params.clearFilterDialog;
+ this.filterDefDialog = params.filterDefDialog;
+
+ this._addRefreshButtons();
+ this._addRowLimitButton(params.defaulGridRowLimit);
+ this._addColumnsButton();
+
+ if (!params.disableFiltering)
+ {
+ this._addFilteringTools(params.nls);
+ }
+ },
+
+ toggleClearFilterBtn: function(clearFlag)
+ {
+ var filterLayer = this.grid.layer("filter");
+ var filterSet = filterLayer && filterLayer.filterDef && filterLayer.filterDef();
+ this.clearFilterButton.set("disabled", !filterSet);
+ },
+
+ destroy: function()
+ {
+ this.inherited(arguments);
+
+ if (this.columnDefDialog)
+ {
+ this.columnDefDialog.destroy();
+ this.columnDefDialog = null;
+ }
+ if (this.columnDefButton)
+ {
+ this.columnDefButton.destroy();
+ this.columnDefButton = null;
+ }
+ if (this.filterDefButton)
+ {
+ this.filterDefButton.destroy();
+ this.filterDefButton = null;
+ }
+ if (this.clearFilterButton)
+ {
+ this.clearFilterButton.destroy();
+ this.clearFilterButton = null;
+ }
+ if (this.filterSummary)
+ {
+ this.filterSummary.destroy();
+ this.filterSummary = null;
+ }
+ if (this.setRowNumberLimitButton)
+ {
+ this.setRowNumberLimitButton.destroy();
+ this.setRowNumberLimitButton = null;
+ }
+ if (this.setRowNumberLimitDialog)
+ {
+ this.setRowNumberLimitDialog.destroy();
+ this.setRowNumberLimitDialog = null;
+ }
+ if (this.refreshButton)
+ {
+ this.refreshButton.destroy();
+ this.refreshButton = null;
+ }
+ if (this.autoRefreshButton)
+ {
+ this.autoRefreshButton.destroy();
+ this.autoRefreshButton = null;
+ }
+
+ this.grid = null;
+ this.filterBar = null;
+ this.filterStatusTip = null;
+ this.clearFilterDialog = null;
+ this.filterDefDialog = null;
+ },
+
+ _addRefreshButtons: function()
+ {
+ var self = this;
+ this.refreshButton = new dijit.form.Button({
+ label: "Refresh",
+ type: "button",
+ iconClass: "gridRefreshIcon",
+ title: "Manual Refresh"
+ });
+
+ this.autoRefreshButton = new dijit.form.ToggleButton({
+ label: "Auto Refresh",
+ type: "button",
+ iconClass: "gridAutoRefreshIcon",
+ title: "Auto Refresh"
+ });
+
+ this.autoRefreshButton.on("change", function(value){
+ self.grid.updater.updatable=value;
+ self.refreshButton.set("disabled", value);
+ });
+
+ this.refreshButton.on("click", function(value){
+ self.grid.updater.performUpdate();
+ });
+
+ this.filterBar.addChild(this.autoRefreshButton);
+ this.filterBar.addChild(this.refreshButton);
+ },
+
+ _addRowLimitButton: function(defaulGridRowLimit)
+ {
+ var self = this;
+ this.setRowNumberLimitButton = new dijit.form.Button({
+ label: "Set Row Limit",
+ type: "button",
+ iconClass: "rowNumberLimitIcon",
+ title: "Set Row Number Limit"
+ });
+ this.setRowNumberLimitButton.set("title", "Set Row Number Limit (Current: " + defaulGridRowLimit +")");
+
+ this.setRowNumberLimitDialog = new RowNumberLimitDialog(this.grid.domNode, function(newLimit){
+ if (newLimit > 0 && self.grid.updater.appendLimit != newLimit )
+ {
+ self.grid.updater.appendLimit = newLimit;
+ self.grid.updater.performRefresh([]);
+ self.setRowNumberLimitButton.set("title", "Set Row Number Limit (Current: " + newLimit +")");
+ }
+ });
+
+ this.setRowNumberLimitButton.on("click", function(evt){
+ self.setRowNumberLimitDialog.showDialog(self.grid.updater.appendLimit);
+ });
+
+ this.filterBar.addChild(this.setRowNumberLimitButton);
+ },
+
+ _addColumnsButton: function()
+ {
+ var self = this;
+ this.columnDefDialog = new ColumnDefDialog({grid: this.grid});
+
+ this.columnDefButton = new dijit.form.Button({
+ label: "Display Columns",
+ type: "button",
+ iconClass: "columnDefDialogButtonIcon",
+ title: "Show/Hide Columns"
+ });
+
+ this.columnDefButton.on("click", function(e){
+ _stopEvent(e);
+ self.columnDefDialog.showDialog();
+ });
+
+ this.filterBar.addChild(this.columnDefButton);
+ },
+
+ _addFilteringTools: function(nls)
+ {
+ var self = this;
+
+ this.filterDefButton = new dijit.form.Button({
+ "class": "dojoxGridFBarBtn",
+ label: "Set Filter",
+ iconClass: "dojoxGridFBarDefFilterBtnIcon",
+ showLabel: "true",
+ title: "Define filter"
+ });
+
+ this.clearFilterButton = new dijit.form.Button({
+ "class": "dojoxGridFBarBtn",
+ label: "Clear filter",
+ iconClass: "dojoxGridFBarClearFilterButtontnIcon",
+ showLabel: "true",
+ title: "Clear filter",
+ disabled: true
+ });
+
+
+ this.filterDefButton.on("click", function(e){
+ _stopEvent(e);
+ self.filterDefDialog.showDialog();
+ });
+
+ this.clearFilterButton.on("click", function(e){
+ _stopEvent(e);
+ if (self.ruleCountToConfirmClearFilter && self.filterDefDialog.getCriteria() >= self.ruleCountToConfirmClearFilter)
+ {
+ self.clearFilterDialog.show();
+ }
+ else
+ {
+ self.grid.layer("filter").filterDef(null);
+ self.toggleClearFilterBtn(true)
+ }
+ });
+
+ this.filterSummary = new FilterSummary({grid: this.grid, filterStatusTip: this.filterStatusTip, nls: nls});
+
+ this.filterBar.addChild(this.filterDefButton);
+ this.filterBar.addChild(this.clearFilterButton);
+
+ this.filterBar.addChild(new dijit.ToolbarSeparator());
+ this.filterBar.addChild(this.filterSummary, "last");
+ this.filterBar.getColumnIdx = function(coordX){return self.filterSummary._getColumnIdx(coordX);};
+
+ }
+ });
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/FilterSummary.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/FilterSummary.js
new file mode 100644
index 0000000000..2b1d960fa5
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/FilterSummary.js
@@ -0,0 +1,173 @@
+/*
+ *
+ * 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/declare",
+ "dojo/_base/lang",
+ "dojo/_base/html",
+ "dojo/query",
+ "dojo/dom-construct",
+ "dojo/string",
+ "dojo/on",
+ "dijit/_WidgetBase"
+], function(declare, lang, html, query, domConstruct, string, on, _WidgetBase){
+
+return declare("qpid.common.grid.FilterSummary", [_WidgetBase], {
+
+ domNode: null,
+ itemName: null,
+ filterStatusTip: null,
+ grid: null,
+ _handle_statusTooltip: null,
+ _timeout_statusTooltip: 300,
+ _nls: null,
+
+ constructor: function(params)
+ {
+ this.inherited(arguments);
+ this.itemName = params.itemsName;
+ this.initialize(params.filterStatusTip, params.grid);
+ this._nls = params.nls;
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ var itemsName = this.itemName || this._nls["defaultItemsName"];
+ var message = string.substitute(this._nls["filterBarMsgNoFilterTemplate"], [0, itemsName ]);
+ this.domNode = domConstruct.create("span", {innerHTML: message, "class": "dijit dijitReset dijitInline dijitButtonInline", role: "presentation" });
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ on(this.domNode, "mouseenter", lang.hitch(this, this._onMouseEnter));
+ on(this.domNode, "mouseleave", lang.hitch(this, this._onMouseLeave));
+ on(this.domNode, "mousemove", lang.hitch(this, this._onMouseMove));
+ },
+
+ destroy: function()
+ {
+ this.inherited(arguments);
+ this.itemName = null;
+ this.filterStatusTip = null;
+ this.grid = null;
+ this._handle_statusTooltip = null;
+ this._filteredClass = null;
+ this._nls = null;
+ },
+
+ initialize: function(filterStatusTip, grid)
+ {
+ this.filterStatusTip = filterStatusTip;
+ this.grid = grid;
+ if (this.grid)
+ {
+ var filterLayer = grid.layer("filter");
+ this.connect(filterLayer, "onFiltered", this.onFiltered);
+ }
+ },
+
+ onFiltered: function(filteredSize, originSize)
+ {
+ try
+ {
+ var itemsName = this.itemName || this._nls["defaultItemsName"],
+ msg = "", g = this.grid,
+ filterLayer = g.layer("filter");
+ if(filterLayer.filterDef()){
+ msg = string.substitute(this._nls["filterBarMsgHasFilterTemplate"], [filteredSize, originSize, itemsName]);
+ }else{
+ msg = string.substitute(this._nls["filterBarMsgNoFilterTemplate"], [originSize, itemsName]);
+ }
+ this.domNode.innerHTML = msg;
+ }
+ catch(e)
+ {
+ // swallow and log exception
+ // otherwise grid rendering is screwed
+ console.error(e);
+ }
+ },
+
+ _getColumnIdx: function(coordX){
+ var headers = query("[role='columnheader']", this.grid.viewsHeaderNode);
+ var idx = -1;
+ for(var i = headers.length - 1; i >= 0; --i){
+ var coord = html.position(headers[i]);
+ if(coordX >= coord.x && coordX < coord.x + coord.w){
+ idx = i;
+ break;
+ }
+ }
+ if(idx >= 0 && this.grid.layout.cells[idx].filterable !== false){
+ return idx;
+ }else{
+ return -1;
+ }
+ },
+
+ _setStatusTipTimeout: function(){
+ this._clearStatusTipTimeout();
+ this._handle_statusTooltip = setTimeout(lang.hitch(this,this._showStatusTooltip),this._timeout_statusTooltip);
+ },
+
+ _clearStatusTipTimeout: function(){
+ if (this._handle_statusTooltip){
+ clearTimeout(this._handle_statusTooltip);
+ }
+ this._handle_statusTooltip = null;
+ },
+
+ _showStatusTooltip: function(){
+ this._handle_statusTooltip = null;
+ if(this.filterStatusTip){
+ this.filterStatusTip.showDialog(this._tippos.x, this._tippos.y, this._getColumnIdx(this._tippos.x));
+ }
+ },
+
+ _updateTipPosition: function(evt){
+ this._tippos = {
+ x: evt.pageX,
+ y: evt.pageY
+ };
+ },
+
+ _onMouseEnter: function(e){
+ this._updateTipPosition(e);
+ if(this.filterStatusTip){
+ this._setStatusTipTimeout();
+ }
+ },
+
+ _onMouseMove: function(e){
+ if(this.filterStatusTip){
+ this._setStatusTipTimeout();
+ if(this._handle_statusTooltip){
+ this._updateTipPosition(e);
+ }
+ }
+ },
+
+ _onMouseLeave: function(e){
+ this._clearStatusTipTimeout();
+ },
+ });
+
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/GridUpdater.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/GridUpdater.js
new file mode 100644
index 0000000000..7016e4eb5b
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/GridUpdater.js
@@ -0,0 +1,258 @@
+/*
+ *
+ * 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/_base/array",
+ "dojo/_base/lang",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/UpdatableStore",
+ "qpid/common/util",
+ "dojo/store/Memory",
+ "dojo/data/ObjectStore",
+ "qpid/common/grid/EnhancedFilter",
+ "dojox/grid/enhanced/plugins/NestedSorting",
+ "dojo/domReady!"],
+ function (xhr, parser, array, lang, properties, updater, UpdatableStore, util, Memory, ObjectStore) {
+
+ function GridUpdater(args, store) {
+ this.updatable = args.hasOwnProperty("updatable") ? args.updatable : true ;
+ this.serviceUrl = args.serviceUrl;
+
+ this.onUpdate = args.onUpdate;
+
+ this.appendData = args.append;
+ this.appendLimit = args.appendLimit;
+ this.initialData = args.data;
+ this.initializeStore(store);
+ };
+
+ GridUpdater.prototype.buildUpdatableGridArguments = function(args)
+ {
+ var filterPluginFound = args && args.hasOwnProperty("plugins") && args.plugins.filter ? true: false;
+
+ var gridProperties = {
+ autoHeight: true,
+ plugins: {
+ pagination: {
+ defaultPageSize: 25,
+ pageSizes: [10, 25, 50, 100],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ enhancedFilter: {
+ disableFiltering: filterPluginFound
+ }
+ }
+ };
+
+ if(args)
+ {
+ for(var argProperty in args)
+ {
+ if(args.hasOwnProperty(argProperty))
+ {
+ if (argProperty == "plugins")
+ {
+ var argPlugins = args[ argProperty ];
+ for(var argPlugin in argPlugins)
+ {
+ if(argPlugins.hasOwnProperty(argPlugin))
+ {
+ var argPluginProperties = argPlugins[ argPlugin ];
+ if (argPluginProperties && gridProperties.plugins.hasOwnProperty(argPlugin))
+ {
+ var gridPlugin = gridProperties.plugins[ argPlugin ];
+ for(var pluginProperty in argPluginProperties)
+ {
+ if(argPluginProperties.hasOwnProperty(pluginProperty))
+ {
+ gridPlugin[pluginProperty] = argPluginProperties[pluginProperty];
+ }
+ }
+ }
+ else
+ {
+ gridProperties.plugins[ argPlugin ] = argPlugins[ argPlugin ];
+ }
+ }
+ }
+ }
+ else
+ {
+ gridProperties[ argProperty ] = args[ argProperty ];
+ }
+ }
+ }
+ }
+
+ gridProperties.updater = this;
+ gridProperties.store = this.dataStore;
+
+ return gridProperties;
+ };
+
+ GridUpdater.prototype.initializeStore = function(store)
+ {
+ var self = this;
+
+ function processData(data)
+ {
+ var dataSet = false;
+ if (!store)
+ {
+ store = new ObjectStore({objectStore: new Memory({data: data, idProperty: "id"})});
+ dataSet = true;
+ }
+ self.dataStore = store
+ self.store = store;
+ if (store instanceof ObjectStore)
+ {
+ if( store.objectStore instanceof Memory)
+ {
+ self.memoryStore = store.objectStore;
+ }
+ self.store = store.objectStore
+ }
+
+ if (data)
+ {
+ try
+ {
+ if ((dataSet || self.updateOrAppend(data)) && self.onUpdate)
+ {
+ self.onUpdate(data);
+ }
+ }
+ catch(e)
+ {
+ console.error(e);
+ }
+ }
+ };
+
+ if (this.serviceUrl)
+ {
+ var requestUrl = lang.isFunction(this.serviceUrl) ? this.serviceUrl() : this.serviceUrl;
+ xhr.get({url: requestUrl, sync: true, handleAs: "json"}).then(processData, util.errorHandler);
+ }
+ else
+ {
+ processData(this.initialData);
+ }
+ };
+
+ GridUpdater.prototype.start = function(grid)
+ {
+ this.grid = grid;
+ if (this.serviceUrl)
+ {
+ updater.add(this);
+ }
+ };
+
+ GridUpdater.prototype.destroy = function()
+ {
+ updater.remove(this);
+ if (this.dataStore)
+ {
+ this.dataStore.close();
+ this.dataStore = null;
+ }
+ this.store = null;
+ this.memoryStore = null;
+ this.grid = null;
+ };
+
+ GridUpdater.prototype.updateOrAppend = function(data)
+ {
+ return this.appendData ?
+ UpdatableStore.prototype.append.call(this, data, this.appendLimit):
+ UpdatableStore.prototype.update.call(this, data);
+ };
+
+ GridUpdater.prototype.refresh = function(data)
+ {
+ this.updating = true;
+ try
+ {
+ if (this.updateOrAppend(data))
+ {
+ // EnhancedGrid with Filter plugin has "filter" layer.
+ // The filter expression needs to be re-applied after the data update
+ var filterLayer = this.grid.layer("filter");
+ if ( filterLayer && filterLayer.filterDef)
+ {
+ var currentFilter = filterLayer.filterDef();
+
+ if (currentFilter)
+ {
+ // re-apply filter in the filter layer
+ filterLayer.filterDef(currentFilter);
+ }
+ }
+
+ // refresh grid to render updates
+ this.grid._refresh();
+ }
+ }
+ finally
+ {
+ this.updating = false;
+ if (this.onUpdate)
+ {
+ this.onUpdate(data);
+ }
+ }
+ }
+
+ GridUpdater.prototype.update = function()
+ {
+ if (this.updatable)
+ {
+ this.performUpdate();
+ }
+ };
+
+ GridUpdater.prototype.performUpdate = function()
+ {
+ var self = this;
+ var requestUrl = lang.isFunction(this.serviceUrl) ? this.serviceUrl() : this.serviceUrl;
+ var requestArguments = {url: requestUrl, sync: properties.useSyncGet, handleAs: "json"};
+ xhr.get(requestArguments).then(function(data){self.refresh(data);});
+ };
+
+ GridUpdater.prototype.performRefresh = function(data)
+ {
+ if (!this.updating)
+ {
+ this.refresh(data);
+ }
+ };
+
+ return GridUpdater;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js
new file mode 100644
index 0000000000..db3ae5a2ea
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js
@@ -0,0 +1,96 @@
+/*
+ *
+ * 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/declare",
+ "dojo/_base/event",
+ "dojo/_base/array",
+ "dojo/_base/lang",
+ "dojo/parser",
+ "dojo/dom-construct",
+ "dojo/query",
+ "dijit/registry",
+ "dijit/form/Button",
+ "dijit/form/CheckBox",
+ "dojox/grid/enhanced/plugins/Dialog",
+ "dojo/text!../../../grid/showRowNumberLimitDialog.html",
+ "dojo/domReady!"
+], function(declare, event, array, lang, parser, dom, query, registry, Button, CheckBox, Dialog, template ){
+
+
+return declare("qpid.management.logs.RowNumberLimitDialog", null, {
+
+ grid: null,
+ dialog: null,
+
+ constructor: function(domNode, limitChangedCallback){
+
+ this.containerNode = dom.create("div", {innerHTML: template});
+ parser.parse(this.containerNode);
+
+ this.rowNumberLimit = registry.byNode(query(".rowNumberLimit", this.containerNode)[0])
+ this.submitButton = registry.byNode(query(".submitButton", this.containerNode)[0]);
+ this.closeButton = registry.byNode(query(".cancelButton", this.containerNode)[0]);
+
+ this.dialog = new Dialog({
+ "refNode": domNode,
+ "title": "Grid Rows Number",
+ "content": this.containerNode
+ });
+
+ var self = this;
+ this.submitButton.on("click", function(e){
+ if (self.rowNumberLimit.value > 0)
+ {
+ try
+ {
+ limitChangedCallback(self.rowNumberLimit.value);
+ }
+ catch(e)
+ {
+ console.error(e);
+ }
+ finally
+ {
+ self.dialog.hide();
+ }
+ }
+ });
+
+ this.closeButton.on("click", function(e){self.dialog.hide(); });
+ this.dialog.startup();
+ },
+
+ destroy: function(){
+ this.submitButton.destroy();
+ this.closeButton.destroy();
+ this.dialog.destroy();
+ this.dialog = null;
+ },
+
+ showDialog: function(currentLimit){
+ this.rowNumberLimit.set("value", currentLimit);
+ this.dialog.show();
+ }
+
+ });
+
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/UpdatableGrid.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/UpdatableGrid.js
new file mode 100644
index 0000000000..04041388bd
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/UpdatableGrid.js
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+define([
+ "dojo/_base/declare",
+ "dojox/grid/EnhancedGrid",
+ "dojo/domReady!"], function(declare, EnhancedGrid){
+
+ return declare("qpid.common.grid.UpdatableGrid", [EnhancedGrid], {
+
+ updater: null,
+
+ postCreate: function(){
+ this.inherited(arguments);
+ if (this.updater)
+ {
+ this.updater.start(this);
+ }
+ },
+
+ destroy: function(){
+ if (this.updater)
+ {
+ try
+ {
+ this.updater.destroy();
+ }
+ catch(e)
+ {
+ console.error(e)
+ }
+ this.updater = null;
+ }
+ this.inherited(arguments);
+ }
+ });
+
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
index 2c2096d390..3d349830ac 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
@@ -77,10 +77,10 @@ define(["dojo/_base/xhr",
return exchangeName == null || exchangeName == "" || "<<default>>" == exchangeName || exchangeName.indexOf("amq.") == 0 || exchangeName.indexOf("qpid.") == 0;
};
- util.deleteGridSelections = function(updater, grid, url, confirmationMessageStart)
+ util.deleteGridSelections = function(updater, grid, url, confirmationMessageStart, idParam)
{
var data = grid.selection.getSelected();
-
+ var success = false;
if(data.length)
{
var confirmationMessage = null;
@@ -114,18 +114,19 @@ define(["dojo/_base/xhr",
{
queryParam = "?";
}
- queryParam += "id=" + data[i].id;
+ queryParam += ( idParam || "id" ) + "=" + encodeURIComponent(data[i].id);
}
var query = url + queryParam;
- var success = true
var failureReason = "";
xhr.del({url: query, sync: true, handleAs: "json"}).then(
function(data)
{
- // TODO why query *??
- //grid.setQuery({id: "*"});
+ success = true;
grid.selection.deselectAll();
- updater.update();
+ if (updater)
+ {
+ updater.update();
+ }
},
function(error) {success = false; failureReason = error;});
if(!success )
@@ -134,6 +135,7 @@ define(["dojo/_base/xhr",
}
}
}
+ return success;
}
util.isProviderManagingUsers = function(type)
@@ -353,5 +355,21 @@ define(["dojo/_base/xhr",
}
};
+ util.errorHandler = function errorHandler(error)
+ {
+ if(error.status == 401)
+ {
+ alert("Authentication Failed");
+ }
+ else if(error.status == 403)
+ {
+ alert("Access Denied");
+ }
+ else
+ {
+ alert(error);
+ }
+ }
+
return util;
}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js
index 978ac4b45f..b5b4380a0d 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js
@@ -32,10 +32,13 @@ define(["dojo/_base/xhr",
"dijit/registry",
"dojo/dom-style",
"dojox/html/entities",
- "dojox/grid/enhanced/plugins/Pagination",
- "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojo/dom",
+ "qpid/management/addPreferencesProvider",
+ "qpid/management/PreferencesProvider",
+ "qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager",
"dojo/domReady!"],
- function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid, addAuthenticationProvider, event, registry, domStyle, entities) {
+ function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid,
+ addAuthenticationProvider, event, registry, domStyle, entities, dom, addPreferencesProvider, PreferencesProvider, PrincipalDatabaseAuthenticationManager) {
function AuthenticationProvider(name, parent, controller) {
this.name = name;
@@ -48,7 +51,7 @@ define(["dojo/_base/xhr",
}
AuthenticationProvider.prototype.getTitle = function() {
- return "AuthenticationProvider";
+ return "AuthenticationProvider:" + this.name;
};
AuthenticationProvider.prototype.open = function(contentPane) {
@@ -62,8 +65,6 @@ define(["dojo/_base/xhr",
that.authProviderUpdater = new AuthProviderUpdater(contentPane.containerNode, that.modelObj, that.controller, that);
- updater.add( that.authProviderUpdater );
-
that.authProviderUpdater.update();
var editButton = query(".editAuthenticationProviderButton", contentPane.containerNode)[0];
@@ -81,6 +82,15 @@ define(["dojo/_base/xhr",
event.stop(evt);
that.deleteAuthenticationProvider();
});
+
+ var addPreferencesProviderButton = query(".addPreferencesProviderButton", contentPane.containerNode)[0];
+ var addPreferencesProviderWidget = registry.byNode(addPreferencesProviderButton);
+ connect.connect(addPreferencesProviderWidget, "onClick",
+ function(evt){
+ event.stop(evt);
+ that.addPreferencesProvider();
+ });
+ updater.add( that.authProviderUpdater );
}});
};
@@ -111,6 +121,14 @@ define(["dojo/_base/xhr",
}
};
+ AuthenticationProvider.prototype.addPreferencesProvider = function() {
+ if (this.authProviderUpdater && this.authProviderUpdater.authProviderData
+ && (!this.authProviderUpdater.authProviderData.preferencesproviders
+ || !this.authProviderUpdater.authProviderData.preferencesproviders[0])){
+ addPreferencesProvider.show(this.name);
+ }
+ };
+
function AuthProviderUpdater(node, authProviderObj, controller, authenticationProvider)
{
this.controller = controller;
@@ -118,6 +136,13 @@ define(["dojo/_base/xhr",
this.type = query(".type", node)[0];
this.state = query(".state", node)[0];
this.authenticationProvider = authenticationProvider;
+ this.preferencesProviderType=dom.byId("preferencesProviderType");
+ this.preferencesProviderName=dom.byId("preferencesProviderName");
+ this.preferencesProviderState=dom.byId("preferencesProviderState");
+ this.addPreferencesProviderButton = query(".addPreferencesProviderButton", node)[0];
+ this.editPreferencesProviderButton = query(".editPreferencesProviderButton", node)[0];
+ this.deletePreferencesProviderButton = query(".deletePreferencesProviderButton", node)[0];
+ this.preferencesProviderAttributes = dom.byId("preferencesProviderAttributes")
this.query = "rest/authenticationprovider/" + encodeURIComponent(authProviderObj.name);
@@ -139,16 +164,46 @@ define(["dojo/_base/xhr",
if (util.isProviderManagingUsers(that.authProviderData.type))
{
- require(["qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager"],
- function(PrincipalDatabaseAuthenticationManager) {
- that.details = new PrincipalDatabaseAuthenticationManager(node, data[0], controller, that);
- that.details.update();
- });
+ that.details = new PrincipalDatabaseAuthenticationManager(node, that.authProviderData, controller);
+ that.details.update(that.authProviderData);
+ }
+ if (that.authProviderData.type == "Anonymous")
+ {
+ var authenticationProviderPanel = registry.byNode( query(".preferencesPanel", node)[0]);
+ domStyle.set(authenticationProviderPanel.domNode, "display","none");
+ }
+ else
+ {
+ var preferencesProviderData = that.authProviderData.preferencesproviders? that.authProviderData.preferencesproviders[0]: null;
+ that.preferencesNode = query(".preferencesProviderDetails", node)[0];
+ that.updatePreferencesProvider(preferencesProviderData);
}
});
}
+ AuthProviderUpdater.prototype.updatePreferencesProvider = function(preferencesProviderData)
+ {
+ if (preferencesProviderData)
+ {
+ this.addPreferencesProviderButton.style.display = 'none';
+ if (!this.preferencesProvider)
+ {
+ this.preferencesProvider=new PreferencesProvider(preferencesProviderData.name, this.authProviderData);
+ this.preferencesProvider.init(this.preferencesNode);
+ }
+ this.preferencesProvider.update(preferencesProviderData);
+ }
+ else
+ {
+ if (this.preferencesProvider)
+ {
+ this.preferencesProvider.update(null);
+ }
+ this.addPreferencesProviderButton.style.display = 'inline';
+ }
+ };
+
AuthProviderUpdater.prototype.updateHeader = function()
{
this.authenticationProvider.name = this.authProviderData[ "name" ]
@@ -159,8 +214,44 @@ define(["dojo/_base/xhr",
AuthProviderUpdater.prototype.update = function()
{
+ var that = this;
- var that = this;
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ that.authProviderData = data[0];
+ that.name = data[0].name
+ util.flattenStatistics( that.authProviderData );
+ that.updateHeader();
+ if (that.details)
+ {
+ try
+ {
+ that.details.update(that.authProviderData);
+ }
+ catch(e)
+ {
+ if (console)
+ {
+ console.error(e);
+ }
+ }
+ }
+ var preferencesProviderData = that.authProviderData.preferencesproviders? that.authProviderData.preferencesproviders[0]: null;
+ if (preferencesProviderData)
+ {
+ try
+ {
+ that.updatePreferencesProvider(preferencesProviderData);
+ }
+ catch(e)
+ {
+ if (console)
+ {
+ console.error(e);
+ }
+ }
+ }
+ });
};
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
index f721ad6fa5..1bb0ca0afa 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
@@ -352,6 +352,12 @@ define(["dojo/_base/xhr",
that.brokerUpdater.update();
+ var logViewerButton = query(".logViewer", contentPane.containerNode)[0];
+ registry.byNode(logViewerButton).on("click", function(evt){
+ that.controller.show("logViewer", null, null);
+ });
+
+
var addProviderButton = query(".addAuthenticationProvider", contentPane.containerNode)[0];
connect.connect(registry.byNode(addProviderButton), "onClick", function(evt){ addAuthenticationProvider.show(); });
@@ -664,43 +670,6 @@ define(["dojo/_base/xhr",
}, gridProperties, EnhancedGrid);
that.displayACLWarnMessage(aclData);
});
-
- 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()
@@ -805,15 +774,6 @@ define(["dojo/_base/xhr",
that.displayACLWarnMessage(data);
}
});
-
-
- xhr.get({url: "rest/logrecords", sync: properties.useSyncGet, handleAs: "json"})
- .then(function(data)
- {
- that.logData = data;
- that.logfileGrid.update(that.logData);
- });
-
};
BrokerUpdater.prototype.showReadOnlyAttributes = function()
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js
new file mode 100644
index 0000000000..735a657c61
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js
@@ -0,0 +1,204 @@
+/*
+ *
+ * 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/declare",
+ "dojo/_base/xhr",
+ "dojo/_base/event",
+ "dojo/_base/connect",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dojo/parser",
+ "dojo/json",
+ "dojo/store/Memory",
+ "dojo/data/ObjectStore",
+ "dojox/html/entities",
+ "dijit/registry",
+ "qpid/common/TimeZoneSelector",
+ "dojo/text!../../showPreferences.html",
+ "qpid/common/util",
+ "dijit/Dialog",
+ "dijit/form/NumberSpinner",
+ "dijit/form/CheckBox",
+ "dijit/form/Textarea",
+ "dijit/form/FilteringSelect",
+ "dijit/form/TextBox",
+ "dijit/form/DropDownButton",
+ "dijit/form/Button",
+ "dijit/form/Form",
+ "dijit/layout/TabContainer",
+ "dijit/layout/ContentPane",
+ "dojox/grid/EnhancedGrid",
+ "dojox/validate/us",
+ "dojox/validate/web",
+ "dojo/domReady!"],
+function (declare, xhr, event, connect, dom, domConstruct, parser, json, Memory, ObjectStore, entities, registry, TimeZoneSelector, markup, util) {
+
+ var preferenceNames = ["timeZone", "updatePeriod", "saveTabs"];
+
+ return declare("qpid.management.Preferences", null, {
+
+ preferencesDialog: null,
+ saveButton: null,
+ cancelButton: null,
+
+ constructor: function()
+ {
+ var that = this;
+
+ this.domNode = domConstruct.create("div", {innerHTML: markup});
+ this.preferencesDialog = parser.parse(this.domNode)[0];
+
+ for(var i=0; i<preferenceNames.length; i++)
+ {
+ var name = preferenceNames[i];
+ this[name] = registry.byId("preferences." + name);
+ }
+
+ this.saveButton = registry.byId("preferences.saveButton");
+ this.cancelButton = registry.byId("preferences.cancelButton");
+ this.theForm = registry.byId("preferences.preferencesForm");
+ this.users = registry.byId("preferences.users");
+ this.users.set("structure", [ { name: "User", field: "name", width: "50%"},
+ { name: "Authentication Provider", field: "authenticationProvider", width: "50%"}]);
+ this.cancelButton.on("click", function(){that.preferencesDialog.hide();});
+ this.deletePreferencesButton = registry.byId("preferences.deletePreeferencesButton");
+ this.deletePreferencesButton.on("click", function(){
+ if (util.deleteGridSelections(
+ null,
+ that.users,
+ "rest/userpreferences",
+ "Are you sure you want to delete preferences for user",
+ "user"))
+ {
+ that._updateUsersWithPreferences();
+ }
+ });
+ var deletePreferencesButtonToggler = function(rowIndex){
+ var data = that.users.selection.getSelected();
+ that.deletePreferencesButton.set("disabled",!data.length );
+ };
+ connect.connect(this.users.selection, 'onSelected', deletePreferencesButtonToggler);
+ connect.connect(this.users.selection, 'onDeselected', deletePreferencesButtonToggler);
+ this.theForm.on("submit", function(e){
+ event.stop(e);
+ if(that.theForm.validate()){
+ var preferences = {};
+ for(var i=0; i<preferenceNames.length; i++)
+ {
+ var name = preferenceNames[i];
+ var preferenceWidget = that[name];
+ if (preferenceWidget)
+ {
+ preferences[name] = preferenceWidget.get("value");
+ }
+ }
+ xhr.post({
+ url: "rest/preferences",
+ sync: true,
+ handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ postData: json.stringify(preferences),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}
+ });
+ if(that.success === true)
+ {
+ that.preferencesDialog.hide();
+ }
+ else
+ {
+ alert("Error:" + that.failureReason);
+ }
+ }
+ return false;
+ });
+ this.preferencesDialog.startup();
+ },
+
+ showDialog: function(){
+ var that = this;
+ xhr.get({
+ url: "rest/preferences",
+ sync: true,
+ handleAs: "json",
+ load: function(data) {
+ that._updatePreferencesWidgets(data);
+ that._updateUsersWithPreferences();
+ that.preferencesDialog.show();
+ },
+ error: function(error){
+ alert("Cannot load user preferences : " + error);
+ }
+ });
+ },
+
+ destroy: function()
+ {
+ if (this.preferencesDialog)
+ {
+ this.preferencesDialog.destroyRecursevly();
+ this.preferencesDialog = null;
+ }
+ },
+
+ _updatePreferencesWidgets: function(data)
+ {
+ for(var i=0; i<preferenceNames.length; i++)
+ {
+ var preference = preferenceNames[i];
+ if (this.hasOwnProperty(preference))
+ {
+ var value = data ? data[preference] : null;
+ if (typeof value == "string")
+ {
+ value = entities.encode(String(value))
+ }
+ this[preference].set("value", value);
+ }
+ }
+ },
+
+ _updateUsersWithPreferences: function()
+ {
+ var that = this;
+ xhr.get({
+ url: "rest/userpreferences",
+ sync: false,
+ handleAs: "json"
+ }).then(
+ function(users) {
+ for(var i=0; i<users.length; i++)
+ {
+ users[i].id = users[i].authenticationProvider + "/" + users[i].name;
+ }
+ var usersStore = new Memory({data: users, idProperty: "id"});
+ var usersDataStore = new ObjectStore({objectStore: usersStore});
+ if (that.users.store)
+ {
+ that.users.store.close();
+ }
+ that.users.set("store", usersDataStore);
+ that.users._refresh();
+ });
+ }
+
+ });
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js
new file mode 100644
index 0000000000..c8e6f9845c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js
@@ -0,0 +1,179 @@
+/*
+ *
+ * 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",
+ "dojo/_base/event",
+ "dijit/registry",
+ "dojo/dom-style",
+ "dojox/html/entities",
+ "qpid/management/addPreferencesProvider",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, properties, updater, util, event, registry, domStyle, entities, addPreferencesProvider) {
+
+ function PreferencesProvider(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "preferencesprovider", name: name };
+ this.authenticationProviderName = parent.name;
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[parent.type] = parent;
+ }
+ }
+
+ PreferencesProvider.prototype.getTitle = function() {
+ return "PreferencesProvider:" + this.authenticationProviderName + "/" + this.name ;
+ };
+
+ PreferencesProvider.prototype.init = function(node) {
+ var that = this;
+ xhr.get({url: "showPreferencesProvider.html",
+ sync: true,
+ load: function(data) {
+ node.innerHTML = data;
+ parser.parse(node);
+
+ that.preferencesProviderType=query(".preferencesProviderType", node)[0];
+ that.preferencesProviderName=query(".preferencesProviderName", node)[0];
+ that.preferencesProviderState=query(".preferencesProviderState", node)[0];
+ that.editPreferencesProviderButton = query(".editPreferencesProviderButton", node)[0];
+ that.deletePreferencesProviderButton = query(".deletePreferencesProviderButton", node)[0];
+ that.preferencesProviderAttributes = query(".preferencesProviderAttributes", node)[0];
+ that.preferencesDetailsDiv = query(".preferencesDetails", node)[0];
+ var editPreferencesProviderWidget = registry.byNode(that.editPreferencesProviderButton);
+ editPreferencesProviderWidget.on("click", function(evt){ event.stop(evt); that.editPreferencesProvider();});
+ var deletePreferencesProviderWidget = registry.byNode(that.deletePreferencesProviderButton);
+ deletePreferencesProviderWidget.on("click", function(evt){ event.stop(evt); that.deletePreferencesProvider();});
+ }});
+ this.reload();
+ };
+
+ PreferencesProvider.prototype.open = function(contentPane) {
+ this.contentPane = contentPane;
+ this.init(contentPane.containerNode);
+ this.updater = new PreferencesProviderUpdater(this);
+ updater.add(this.updater);
+ };
+
+ PreferencesProvider.prototype.close = function() {
+ if (this.updater)
+ {
+ updater.remove( this.updater);
+ }
+ };
+
+ PreferencesProvider.prototype.deletePreferencesProvider = function() {
+ if (this.preferencesProviderData){
+ var preferencesProviderData = this.preferencesProviderData;
+ if(confirm("Are you sure you want to delete preferences provider '" + preferencesProviderData.name + "'?")) {
+ var query = "rest/preferencesprovider/" + encodeURIComponent(this.authenticationProviderName) + "/" + encodeURIComponent(preferencesProviderData.name);
+ this.success = true
+ var that = this;
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ that.update(null);
+
+ // if opened in tab
+ if (that.contentPane)
+ {
+ that.close();
+ 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);
+ }
+ }
+ }
+ };
+
+ PreferencesProvider.prototype.editPreferencesProvider = function() {
+ if (this.preferencesProviderData){
+ addPreferencesProvider.show(this.authenticationProviderName, this.name);
+ }
+ };
+
+ PreferencesProvider.prototype.update = function(data) {
+ this.preferencesProviderData = data;
+ if (data)
+ {
+ this.name = data.name;
+ this.preferencesProviderAttributes.style.display = 'block';
+ this.editPreferencesProviderButton.style.display = 'inline';
+ this.deletePreferencesProviderButton.style.display = 'inline';
+ this.preferencesProviderType.innerHTML = entities.encode(String(data.type));
+ this.preferencesProviderName.innerHTML = entities.encode(String(data.name));
+ this.preferencesProviderState.innerHTML = entities.encode(String(data.state));
+ if (!this.details)
+ {
+ var that = this;
+ require(["qpid/management/authenticationprovider/preferences/" + data.type.toLowerCase() + "/show"],
+ function(PreferencesProviderDetails) {
+ that.details = new PreferencesProviderDetails(that.preferencesDetailsDiv);
+ that.details.update(data);
+ });
+ }
+ else
+ {
+ this.details.update(data);
+ }
+ }
+ else
+ {
+ this.editPreferencesProviderButton.style.display = 'none';
+ this.deletePreferencesProviderButton.style.display = 'none';
+ this.preferencesProviderAttributes.style.display = 'none';
+ this.details = null;
+ }
+ };
+
+ PreferencesProvider.prototype.reload = function()
+ {
+ var query = "rest/preferencesprovider/" + encodeURIComponent(this.authenticationProviderName) + "/" + encodeURIComponent(this.name);
+ var that = this;
+ xhr.get({url: query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ var preferencesProviderData = data[0];
+ util.flattenStatistics( preferencesProviderData );
+ that.update(preferencesProviderData);
+ });
+ };
+
+ function PreferencesProviderUpdater(preferencesProvider)
+ {
+ this.preferencesProvider = preferencesProvider;
+ };
+
+ PreferencesProviderUpdater.prototype.update = function()
+ {
+ this.preferencesProvider.reload();
+ };
+
+ return PreferencesProvider;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js
index d2891c7d3b..3737e41da4 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js
@@ -31,6 +31,7 @@ define(["dojo/_base/xhr",
"dijit/form/FilteringSelect",
"dojo/_base/connect",
"dojo/dom-style",
+ "qpid/management/addPreferencesProvider",
/* dojox/ validate resources */
"dojox/validate/us", "dojox/validate/web",
/* basic dijit classes */
@@ -44,7 +45,7 @@ define(["dojo/_base/xhr",
"dojox/form/BusyButton", "dojox/form/CheckedMultiSelect",
"dojox/layout/TableContainer",
"dojo/domReady!"],
- function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, FilteringSelect, connect, domStyle) {
+ function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, FilteringSelect, connect, domStyle, addPreferencesProvider) {
var addAuthenticationProvider = {};
@@ -163,6 +164,10 @@ define(["dojo/_base/xhr",
if(this.success === true)
{
registry.byId("addAuthenticationProvider").hide();
+ if (newAuthenticationManager.type != "Anonymous" && dojo.byId("formAddAuthenticationProvider.id").value == "")
+ {
+ addPreferencesProvider.show(newAuthenticationManager.name);
+ }
}
else
{
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js
new file mode 100644
index 0000000000..818dc32366
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js
@@ -0,0 +1,198 @@
+/*
+ *
+ * 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/query",
+ "dojo/_base/window",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "dojo/store/Memory",
+ "dijit/form/FilteringSelect",
+ "dojo/_base/connect",
+ "dojo/dom-style",
+ "dojo/string",
+ "dojox/html/entities",
+ "dojox/validate/us",
+ "dojox/validate/web",
+ "dijit/Dialog",
+ "dijit/form/CheckBox",
+ "dijit/form/Textarea",
+ "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox",
+ "dijit/form/Button",
+ "dijit/form/Form",
+ "dojox/form/BusyButton",
+ "dojox/form/CheckedMultiSelect",
+ "dojox/layout/TableContainer",
+ "dojo/domReady!"],
+ function (xhr, dom, construct, query, win, registry, parser, array, event, json, Memory, FilteringSelect, connect, domStyle, string, entities) {
+
+ var addPreferencesProvider = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ var convertToPreferencesProvider = function convertToPreferencesProvider(formValues)
+ {
+ var newProvider = {};
+
+ newProvider.name = dijit.byId("preferencesProvider.name").value;
+ newProvider.type = dijit.byId("preferencesProvider.type").value;
+ var id = dojo.byId("preferencesProvider.id").value;
+ if (id)
+ {
+ newProvider.id = id;
+ }
+ for(var propName in formValues)
+ {
+ if(formValues.hasOwnProperty(propName))
+ {
+ if(formValues[ propName ] !== "") {
+ newProvider[ propName ] = formValues[propName];
+ }
+
+ }
+ }
+ return newProvider;
+ }
+
+ var selectPreferencesProviderType = function(type) {
+ if(type && string.trim(type) != "")
+ {
+ require(["qpid/management/authenticationprovider/preferences/" + type.toLowerCase() + "/add"],
+ function(addType)
+ {
+ addType.show(dom.byId("preferencesProvider.fieldsContainer"), addPreferencesProvider.data)
+ });
+ }
+ }
+
+ xhr.get({url: "addPreferencesProvider.html",
+ sync: true,
+ load: function(data) {
+ node.innerHTML = data;
+ addPreferencesProvider.dialogNode = dom.byId("addPreferencesProvider");
+ parser.instantiate([addPreferencesProvider.dialogNode]);
+
+ var cancelButton = registry.byId("addPreferencesProvider.cancelButton");
+ cancelButton.on("click", function(){
+ registry.byId("addPreferencesProvider").hide();
+ });
+ var theForm = registry.byId("formAddPreferencesProvider");
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+ var newProvider = convertToPreferencesProvider(theForm.getValues());
+ var that = this;
+ var nameWidget = registry.byId("preferencesProvider.name")
+ xhr.put({url: "rest/preferencesprovider/" +encodeURIComponent(addPreferencesProvider.authenticationProviderName) + "/" + encodeURIComponent(nameWidget.value),
+ sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newProvider),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+ if(this.success === true)
+ {
+ registry.byId("addPreferencesProvider").hide();
+ }
+ else
+ {
+ alert("Error:" + this.failureReason);
+ }
+ return false;
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+ });
+ xhr.get({
+ sync: true,
+ url: "rest/helper?action=ListPreferencesProvidersTypes",
+ handleAs: "json"
+ }).then(
+ function(data) {
+ var preferencesProvidersTypes = data;
+ var storeData = [];
+ for (var i =0 ; i < preferencesProvidersTypes.length; i++)
+ {
+ storeData[i]= {id: preferencesProvidersTypes[i], name: preferencesProvidersTypes[i]};
+ }
+ var store = new Memory({ data: storeData });
+ var preferencesProviderTypesDiv = dom.byId("addPreferencesProvider.selectPreferencesProviderDiv");
+ var input = construct.create("input", {id: "preferencesProviderType", required: true}, preferencesProviderTypesDiv);
+ addPreferencesProvider.preferencesProviderTypeChooser = new FilteringSelect({ id: "preferencesProvider.type",
+ name: "type",
+ store: store,
+ searchAttr: "name",
+ required: true,
+ onChange: selectPreferencesProviderType }, input);
+ addPreferencesProvider.preferencesProviderTypeChooser.startup();
+ });
+ }});
+
+ addPreferencesProvider.show = function(authenticationProviderName, providerName) {
+ this.authenticationProviderName = authenticationProviderName;
+ this.data = null;
+ var that = this;
+ var theForm = registry.byId("formAddPreferencesProvider");
+ theForm.reset();
+ dojo.byId("preferencesProvider.id").value="";
+ var nameWidget = registry.byId("preferencesProvider.name");
+ nameWidget.set("disabled", false);
+ registry.byId("preferencesProvider.type").set("disabled", false);
+ if (this.preferencesProviderTypeChooser)
+ {
+ this.preferencesProviderTypeChooser.set("disabled", false);
+ this.preferencesProviderTypeChooser.set("value", null);
+ }
+ var dialog = registry.byId("addPreferencesProvider");
+ dialog.set("title", (providerName ? "Edit preference provider '" + entities.encode(String(providerName)) + "' " : "Add preferences provider ") + " for authentication provider '" + entities.encode(String(authenticationProviderName)) + "' ")
+ if (providerName)
+ {
+ xhr.get({
+ url: "rest/preferencesprovider/" +encodeURIComponent(authenticationProviderName) + "/" + encodeURIComponent(providerName),
+ sync: false,
+ handleAs: "json"
+ }).then(
+ function(data) {
+ var provider = data[0];
+ var providerType = provider.type;
+ that.data = provider;
+ nameWidget.set("value", entities.encode(String(provider.name)));
+ nameWidget.set("disabled", true);
+ that.preferencesProviderTypeChooser.set("value", providerType);
+ that.preferencesProviderTypeChooser.set("disabled", true);
+ dojo.byId("preferencesProvider.id").value=provider.id;
+ dialog.show();
+ });
+ }
+ else
+ {
+ dialog.show();
+ }
+ }
+
+ return addPreferencesProvider;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js
index 0a607c71d4..09433b196d 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js
@@ -30,7 +30,6 @@ define(["dojo/_base/xhr",
"dijit/registry",
"qpid/common/util",
"qpid/common/properties",
- "qpid/common/updater",
"qpid/common/UpdatableStore",
"dojox/grid/EnhancedGrid",
"dojox/grid/enhanced/plugins/Pagination",
@@ -43,8 +42,8 @@ define(["dojo/_base/xhr",
"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, authenticationManagerUpdater) {
+ function (xhr, dom, parser, query, construct, connect, win, event, json, registry, util, properties, UpdatableStore, EnhancedGrid) {
+ function DatabaseAuthManager(containerNode, authProviderObj, controller) {
var node = construct.create("div", null, containerNode, "last");
var that = this;
this.name = authProviderObj.name;
@@ -53,14 +52,7 @@ define(["dojo/_base/xhr",
load: function(data) {
node.innerHTML = data;
parser.parse(node);
-
-
- that.authDatabaseUpdater= new AuthProviderUpdater(node, authProviderObj, controller, authenticationManagerUpdater);
- updater.add( that.authDatabaseUpdater);
-
- that.authDatabaseUpdater.update();
-
-
+ that.init(node, authProviderObj, controller);
}});
}
@@ -72,19 +64,12 @@ define(["dojo/_base/xhr",
updater.remove( this.authDatabaseUpdater );
};
- function AuthProviderUpdater(node, authProviderObj, controller, authenticationManagerUpdater)
+ DatabaseAuthManager.prototype.init = function(node, authProviderObj, controller)
{
this.controller = controller;
- this.query = "rest/authenticationprovider?id="+encodeURIComponent(authProviderObj.id);
- this.name = authProviderObj.name;
- this.authenticationManagerUpdater = authenticationManagerUpdater;
var that = this;
- xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
- .then(function(data) {
- that.authProviderData = data[0];
- that.name = data[0].name
- util.flattenStatistics( that.authProviderData );
+ that.authProviderData = authProviderObj;
var userDiv = query(".users")[0];
@@ -131,10 +116,9 @@ define(["dojo/_base/xhr",
event.stop(evt);
that.deleteUsers();
});
- });
}
- AuthProviderUpdater.prototype.deleteUsers = function()
+ DatabaseAuthManager.prototype.deleteUsers = function()
{
var grid = this.usersGrid.grid;
var data = grid.selection.getSelected();
@@ -168,24 +152,11 @@ define(["dojo/_base/xhr",
}
};
- AuthProviderUpdater.prototype.update = function()
+ DatabaseAuthManager.prototype.update = function(data)
{
-
- var that = this;
-
- xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
- .then(function(data) {
- that.authProviderData = data[0];
- that.name = data[0].name
- util.flattenStatistics( that.authProviderData );
-
- that.usersGrid.update(that.authProviderData.users);
-
- that.authenticationManagerUpdater.authProviderData = data[0];
- that.authenticationManagerUpdater.updateHeader();
- });
-
-
+ this.authProviderData = data;
+ this.name = data.name
+ this.usersGrid.update(this.authProviderData.users);
};
var addUser = {};
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/store/memory/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/preferences/filesystempreferences/add.js
index 3a9b23274d..80b50fbbb8 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/store/memory/add.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/preferences/filesystempreferences/add.js
@@ -28,29 +28,22 @@ define(["dojo/_base/xhr",
"dojo/_base/event",
"dojo/_base/json",
"dojo/string",
- "dojo/store/Memory",
- "dijit/form/FilteringSelect",
+ "dojox/html/entities",
+ "dojo/text!../../../../../authenticationprovider/preferences/filesystempreferences/add.html",
"dojo/domReady!"],
- function (xhr, dom, construct, win, registry, parser, array, event, json, string, Memory, FilteringSelect) {
+ function (xhr, dom, domConstruct, win, registry, parser, array, event, json, string, entities, template) {
return {
- show: function() {
- var node = dom.byId("addVirtualHost.storeSpecificDiv");
- var that = this;
-
- array.forEach(registry.toArray(),
- function(item) {
- if(item.id.substr(0,33) == "formAddVirtualHost.specific.store") {
- item.destroyRecursive();
- }
- });
-
- xhr.get({url: "virtualhost/store/memory/add.html",
- sync: true,
- load: function(data) {
- node.innerHTML = data;
- parser.parse(node);
-
- }});
+ show: function(node, data) {
+ dojo.forEach(dijit.findWidgets(node), function(w) {
+ w.destroyRecursive();
+ });
+ node.innerHTML = template;
+ parser.parse(node);
+ var pathWidget = registry.byId("preferencesProvider.path")
+ if (data)
+ {
+ pathWidget.set("value", entities.encode(String(data["path"])));
+ }
}
};
});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/preferences/filesystempreferences/show.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/preferences/filesystempreferences/show.js
new file mode 100644
index 0000000000..7521f820b9
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/preferences/filesystempreferences/show.js
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/string",
+ "dojox/html/entities",
+ "dojo/query",
+ "dojo/domReady!"],
+ function (xhr, parser, json, entities, query) {
+
+ function FileSystemPreferences(containerNode) {
+ var that = this;
+ xhr.get({url: "authenticationprovider/preferences/filesystempreferences/show.html",
+ sync: true,
+ load: function(template) {
+ containerNode.innerHTML = template;
+ parser.parse(containerNode);
+ that.preferencesProviderPath=query(".fileSystemPreferencesProviderPath", containerNode)[0];
+ }});
+ }
+
+ FileSystemPreferences.prototype.update=function(data)
+ {
+ this.preferencesProviderPath.innerHTML = entities.encode(String(data["path"]));
+ };
+
+ return FileSystemPreferences;
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
index b7eddbbb77..e8d7bdd9cf 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
@@ -35,10 +35,12 @@ define(["dojo/dom",
"qpid/management/AccessControlProvider",
"qpid/management/Port",
"qpid/management/Plugin",
+ "qpid/management/logs/LogViewer",
+ "qpid/management/PreferencesProvider",
"dojo/ready",
"dojo/domReady!"],
function (dom, registry, ContentPane, entities, Broker, VirtualHost, Exchange, Queue, Connection, AuthProvider,
- GroupProvider, Group, KeyStore, TrustStore, AccessControlProvider, Port, Plugin, ready) {
+ GroupProvider, Group, KeyStore, TrustStore, AccessControlProvider, Port, Plugin, LogViewer, PreferencesProvider, ready) {
var controller = {};
var constructors = { broker: Broker, virtualhost: VirtualHost, exchange: Exchange,
@@ -46,7 +48,7 @@ define(["dojo/dom",
authenticationprovider: AuthProvider, groupprovider: GroupProvider,
group: Group, keystore: KeyStore, truststore: TrustStore,
accesscontrolprovider: AccessControlProvider, port: Port,
- plugin: Plugin};
+ plugin: Plugin, logViewer: LogViewer, preferencesprovider: PreferencesProvider};
var tabDiv = dom.byId("managedViews");
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js
new file mode 100644
index 0000000000..c25fd7c609
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js
@@ -0,0 +1,175 @@
+/*
+ *
+ * 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/declare",
+ "dojo/_base/event",
+ "dojo/_base/xhr",
+ "dojo/_base/connect",
+ "dojo/dom-construct",
+ "dojo/query",
+ "dojo/parser",
+ "dojo/store/Memory",
+ "dojo/data/ObjectStore",
+ "dojo/date/locale",
+ "dojo/number",
+ "dijit/registry",
+ "dijit/Dialog",
+ "dijit/form/Button",
+ "dojox/grid/EnhancedGrid",
+ "dojo/text!../../../logs/showLogFileDownloadDialog.html",
+ "dojo/domReady!"
+], function(declare, event, xhr, connect, domConstruct, query, parser, Memory, ObjectStore, locale, number,
+ registry, Dialog, Button, EnhancedGrid, template){
+
+
+return declare("qpid.management.logs.LogFileDownloadDialog", null, {
+
+ templateString: template,
+ containerNode: null,
+ widgetsInTemplate: true,
+ logFileDialog: null,
+ logFilesGrid: null,
+ downloadLogsButton: null,
+ closeButton: null,
+
+ constructor: function(args){
+ this.containerNode = domConstruct.create("div", {innerHTML: template});
+ parser.parse(this.containerNode);
+
+ this.logFileTreeDiv = query(".logFilesGrid", this.containerNode)[0];
+ this.downloadLogsButton = registry.byNode(query(".downloadLogsButton", this.containerNode)[0]);
+ this.closeButton = registry.byNode(query(".downloadLogsDialogCloseButton", this.containerNode)[0]);
+
+ var self = this;
+ this.closeButton.on("click", function(e){self._onCloseButtonClick(e);});
+ this.downloadLogsButton.on("click", function(e){self._onDownloadButtonClick(e);});
+ this.downloadLogsButton.set("disabled", true)
+
+ this.logFileDialog = new Dialog({
+ title:"Broker Log Files",
+ style: "width: 600px",
+ content: this.containerNode
+ });
+
+ var layout = [
+ { name: "Appender", field: "appenderName", width: "auto"},
+ { name: "Name", field: "name", width: "auto"},
+ { name: "Size", field: "size", width: "60px",
+ formatter: function(val){
+ return val > 1024 ? (val > 1048576? number.round(val/1048576) + "MB": number.round(val/1024) + "KB") : val + "bytes";
+ }
+ },
+ { name: "Last Modified", field: "lastModified", width: "250px",
+ formatter: function(val) {
+ var d = new Date(val);
+ return locale.format(d, {selector:"date", datePattern: "EEE, MMM d yy, HH:mm:ss z (ZZZZ)"});
+ }
+ }
+ ];
+
+ var gridProperties = {
+ store: new ObjectStore({objectStore: new Memory({data: [], idProperty: "id"}) }),
+ structure: layout,
+ autoHeight: true,
+ plugins: {
+ pagination: {
+ pageSizes: [10, 25, 50, 100],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ indirectSelection: {
+ headerSelector:true,
+ width:"20px",
+ styles:"text-align: center;"
+ }
+ }
+ };
+
+ this.logFilesGrid = new EnhancedGrid(gridProperties, this.logFileTreeDiv);
+ var self = this;
+ var downloadButtonToggler = function(rowIndex){
+ var data = self.logFilesGrid.selection.getSelected();
+ self.downloadLogsButton.set("disabled",!data.length );
+ };
+ connect.connect(this.logFilesGrid.selection, 'onSelected', downloadButtonToggler);
+ connect.connect(this.logFilesGrid.selection, 'onDeselected', downloadButtonToggler);
+ },
+
+ _onCloseButtonClick: function(evt){
+ event.stop(evt);
+ this.logFileDialog.hide();
+ },
+
+ _onDownloadButtonClick: function(evt){
+ event.stop(evt);
+ var data = this.logFilesGrid.selection.getSelected();
+ if (data.length)
+ {
+ var query = "";
+ for(var i = 0 ; i< data.length; i++)
+ {
+ if (i>0)
+ {
+ query+="&";
+ }
+ query+="l="+encodeURIComponent(data[i].appenderName +'/' + data[i].name);
+ }
+ window.location="rest/logfile?" + query;
+ this.logFileDialog.hide();
+ }
+ },
+
+ destroy: function(){
+ this.inherited(arguments);
+ if (this.logFileDialog)
+ {
+ this.logFileDialog.destroyRecursive();
+ this.logFileDialog = null;
+ }
+ },
+
+ showDialog: function(){
+ var self = this;
+ var requestArguments = {url: "rest/logfiles", sync: true, handleAs: "json"};
+ xhr.get(requestArguments).then(function(data){
+ try
+ {
+ self.logFilesGrid.store.objectStore.setData(data);
+ self.logFilesGrid.startup();
+ self.logFileDialog.startup();
+ self.logFileDialog.show();
+ self.logFilesGrid._refresh();
+
+ }
+ catch(e)
+ {
+ console.error(e);
+ }
+ });
+ }
+
+ });
+
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js
new file mode 100644
index 0000000000..56b37d0167
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js
@@ -0,0 +1,199 @@
+/*
+ *
+ * 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/date/locale",
+ "dijit/registry",
+ "qpid/common/grid/GridUpdater",
+ "qpid/common/grid/UpdatableGrid",
+ "qpid/management/logs/LogFileDownloadDialog",
+ "dojo/text!../../../logs/showLogViewer.html",
+ "dojo/domReady!"],
+ function (xhr, parser, query, locale, registry, GridUpdater, UpdatableGrid, LogFileDownloadDialog, markup) {
+
+ var defaulGridRowLimit = 4096;
+
+ function LogViewer(name, parent, controller) {
+ var self = this;
+
+ this.name = name;
+ this.lastLogId = 0;
+ this.contentPane = null;
+ this.downloadLogsButton = null;
+ this.downloadLogDialog = null;
+ }
+
+ LogViewer.prototype.getTitle = function() {
+ return "Log Viewer";
+ };
+
+ LogViewer.prototype.open = function(contentPane) {
+ var self = this;
+ this.contentPane = contentPane;
+ this.contentPane.containerNode.innerHTML = markup;
+
+ parser.parse(this.contentPane.containerNode);
+
+ this.downloadLogsButton = registry.byNode(query(".downloadLogs", contentPane.containerNode)[0]);
+ this.downloadLogDialog = new LogFileDownloadDialog();
+
+ this.downloadLogsButton.on("click", function(evt){
+ self.downloadLogDialog.showDialog();
+ });
+ this._buildGrid();
+ };
+
+ LogViewer.prototype._buildGrid = function() {
+ var self = this;
+
+ var gridStructure = [
+ {
+ hidden: true,
+ name: "ID",
+ field: "id",
+ width: "50px",
+ datatype: "number",
+ filterable: true
+ },
+ {
+ name: "Date", field: "timestamp", width: "100px", datatype: "date",
+ formatter: function(val) {
+ var d = new Date(0);
+ d.setUTCSeconds(val/1000);
+ return locale.format(d, {selector:"date", datePattern: "EEE, MMM d yy"});
+ },
+ dataTypeArgs: {
+ selector: "date",
+ datePattern: "EEE MMMM d yyy"
+ }
+ },
+ { name: "Time", field: "timestamp", width: "150px", datatype: "time",
+ formatter: function(val) {
+ var d = new Date(0);
+ d.setUTCSeconds(val/1000);
+ return locale.format(d, {selector:"time", timePattern: "HH:mm:ss z (ZZZZ)"});
+ },
+ dataTypeArgs: {
+ selector: "time",
+ timePattern: "HH:mm:ss ZZZZ"
+ }
+ },
+ { name: "Level", field: "level", width: "50px", datatype: "string", autoComplete: true, hidden: true},
+ { name: "Logger", field: "logger", width: "150px", datatype: "string", autoComplete: false, hidden: true},
+ { name: "Thread", field: "thread", width: "100px", datatype: "string", hidden: true},
+ { name: "Log Message", field: "message", width: "auto", datatype: "string"}
+ ];
+
+ var gridNode = query("#broker-logfile", this.contentPane.containerNode)[0];
+ try
+ {
+ var updater = new GridUpdater({
+ updatable: false,
+ serviceUrl: function()
+ {
+ return "rest/logrecords?lastLogId=" + self.lastLogId;
+ },
+ onUpdate: function(items)
+ {
+ if (items)
+ {
+ var maxId = -1;
+ for(var i in items)
+ {
+ var item = items[i];
+ if (item.id > maxId)
+ {
+ maxId = item.id
+ }
+ }
+ if (maxId != -1)
+ {
+ self.lastLogId = maxId
+ }
+ }
+ },
+ append: true,
+ appendLimit: defaulGridRowLimit
+ });
+ this.grid = new UpdatableGrid(updater.buildUpdatableGridArguments({
+ structure: gridStructure,
+ selectable: true,
+ selectionMode: "none",
+ sortInfo: -1,
+ sortFields: [{attribute: 'timestamp', descending: true}],
+ plugins:{
+ nestedSorting:true,
+ enhancedFilter:{defaulGridRowLimit: defaulGridRowLimit},
+ indirectSelection: false
+ }
+ }), gridNode);
+ var onStyleRow = function(row)
+ {
+ var item = self.grid.getItem(row.index);
+ if(item){
+ var level = self.grid.store.getValue(item, "level", null);
+ var changed = false;
+ if(level == "ERROR"){
+ row.customClasses += " redBackground";
+ changed = true;
+ } else if(level == "WARN"){
+ row.customClasses += " yellowBackground";
+ changed = true;
+ } else if(level == "DEBUG"){
+ row.customClasses += " grayBackground";
+ changed = true;
+ }
+ if (changed)
+ {
+ self.grid.focus.styleRow(row);
+ }
+ }
+ };
+ this.grid.on("styleRow", onStyleRow);
+ this.grid.startup();
+ }
+ catch(err)
+ {
+ console.error(err);
+ }
+ };
+
+ LogViewer.prototype.close = function() {
+ if (this.grid)
+ {
+ this.grid.destroy();
+ this.grid = null;
+ }
+ if (this.downloadLogDialog)
+ {
+ this.downloadLogDialog.destroy();
+ this.downloadLogDialog = null;
+ }
+ if (this.downloadLogsButton)
+ {
+ this.downloadLogsButton.destroy();
+ this.downloadLogsButton = null;
+ }
+ };
+
+ return LogViewer;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
index b1ccc0ca07..59822ec535 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
@@ -37,15 +37,10 @@ define(["dojo/_base/xhr",
return typeof val === 'string' ? entities.encode(val) : val;
}
+ var populatedFields = [];
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();
};
@@ -65,16 +60,22 @@ define(["dojo/_base/xhr",
showMessage.populateShowMessage = function(data) {
- this.populatedFields = [];
+ // clear fields set by previous invocation.
+ if(populatedFields) {
+ for(var i = 0 ; i < populatedFields.length; i++) {
+ populatedFields[i].innerHTML = "";
+ }
+ 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);
+ populatedFields.push(field);
var val = data[attrName];
- if(val) {
+ if(val != null) {
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) {
@@ -112,7 +113,7 @@ define(["dojo/_base/xhr",
+ "/" + encodeURIComponent(showMessage.messageNumber)
+ "\" target=\"_blank\">Download</a>";
}
- this.populatedFields.push(contentField);
+ populatedFields.push(contentField);
registry.byId("showMessage").show();
};
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
index 8dc336b347..8770509c27 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
@@ -284,6 +284,8 @@ define(["dojo/_base/xhr",
controller.show("accesscontrolprovider", details.accesscontrolprovider, {broker: {type:"broker", name:""}});
} else if (details.type == 'plugin') {
controller.show("plugin", details.plugin, {broker: {type:"broker", name:""}});
+ } else if (details.type == "preferencesprovider") {
+ controller.show("preferencesprovider", details.preferencesprovider, { type: "authenticationprovider", name: details.authenticationprovider, parent: {broker: {type:"broker", name:""}}});
}
};
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogFileDownloadDialog.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogFileDownloadDialog.html
new file mode 100644
index 0000000000..bc633d059a
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogFileDownloadDialog.html
@@ -0,0 +1,33 @@
+<!--
+ -
+ - 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>
+ <div class="contentArea" style="height:320px;overflow:auto">
+ <div><b>Select log files to download</b></div>
+ <div class="logFilesGrid" style='height:300px;width: 580px'></div>
+ </div>
+ <div class="dijitDialogPaneActionBar">
+ <button value="Download" data-dojo-type="dijit.form.Button"
+ class="downloadLogsButton"
+ data-dojo-props="iconClass: 'downloadLogsIcon', label: 'Download' "></button>
+ <button value="Close" data-dojo-type="dijit.form.Button" data-dojo-props="label: 'Close'"
+ class="downloadLogsDialogCloseButton"></button>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogViewer.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogViewer.html
new file mode 100644
index 0000000000..10ac09a406
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/logs/showLogViewer.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="logViewer">
+
+ <div id="broker-logfile"></div>
+ <br/>
+ <button data-dojo-type="dijit.form.Button" class="downloadLogs"
+ data-dojo-props="iconClass: 'downloadLogsIcon', title:'Download Log Files', name: 'downloadLogs'">Download</button>
+ <br/>
+</div>
+
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html
index 5e876fdc1f..aabaee1e9d 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html
@@ -27,4 +27,11 @@
<br/>
<button data-dojo-type="dijit.form.Button" class="editAuthenticationProviderButton">Edit</button>
<button data-dojo-type="dijit.form.Button" class="deleteAuthenticationProviderButton">Delete</button>
+ <br/>
+ <br/>
+ <div class="preferencesPanel" data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Preferences Provider', open: true">
+ <div class="preferencesProviderDetails"></div>
+ <button data-dojo-type="dijit.form.Button" class="addPreferencesProviderButton">Add</button>
+ </div>
+ <br/>
</div> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
index d9991452af..366ef27c8a 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
@@ -190,9 +190,7 @@
<button data-dojo-type="dijit.form.Button" class="deleteAccessControlProvider">Delete Access Control Provider</button>
</div>
<br/>
- <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Log File', open: false">
- <div class="broker-logfile"></div>
- </div>
- <br/>
+ <button data-dojo-type="dijit.form.Button" class="logViewer" data-dojo-props="iconClass: 'logViewerIcon'">Log Viewer</button>
+ <br/><br/>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html
index 0dea508c60..9a6ec55686 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showMessage.html
@@ -45,7 +45,7 @@
</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>
+ <td><span class="message-expirationTime 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>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferences.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferences.html
new file mode 100644
index 0000000000..ede111272a
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferences.html
@@ -0,0 +1,83 @@
+<!--
+ -
+ - 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 data-dojo-type="dijit/Dialog" data-dojo-props="title:'Preferences'" id="preferences.preferencesDialog">
+ <div data-dojo-type="dijit/layout/TabContainer" style="width: 600px; height: 400px">
+ <div data-dojo-type="dijit/layout/ContentPane" title="Own Preferences" data-dojo-props="selected:true" id="preferences.preferencesTab">
+ <form method="post" data-dojo-type="dijit/form/Form" id="preferences.preferencesForm">
+ <table cellpadding="0" cellspacing="2" style="overflow: auto; height: 300px;">
+ <tr>
+ <td><strong>Time zone: </strong></td>
+ <td>
+ <span id="preferences.timeZone" data-dojo-type="qpid/common/TimeZoneSelector" data-dojo-props="name: 'timeZone'"></span>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Update period:</strong></td>
+ <td><input id="preferences.updatePeriod" name="updatePeriod" data-dojo-type="dijit/form/NumberSpinner" data-dojo-props="
+ invalidMessage: 'Invalid value',
+ required: false,
+ smallDelta: 1,
+ value: 5,
+ constraints: {min:1,max:65535,places:0, pattern: '#####'},
+ "/>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Save tabs:</strong></td>
+ <td><input id="preferences.saveTabs" type="checkbox" data-dojo-type="dijit/form/CheckBox" name="saveTabs"/></td>
+ </tr>
+ </table>
+ <div class="dijitDialogPaneActionBar">
+ <input type="submit" value="Save Preferences" data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Save Preferences'" id="preferences.saveButton"/>
+ <button value="Cancel" data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Cancel'" id="preferences.cancelButton"></button>
+ </div>
+ </form>
+ </div>
+ <div data-dojo-type="dijit/layout/ContentPane" title="Users with Preferences" id="preferences.usersTab">
+ <table id="preferences.users" data-dojo-type="dojox/grid/EnhancedGrid" data-dojo-props="
+ label:'Trust Stores:',
+ plugins:{
+ indirectSelection: true,
+ pagination: {
+ pageSizes: [10, 25, 50, 100],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: 'bottom'
+ }
+ },
+ rowSelector:'0px'
+ " style="height: 300px;">
+ <thead>
+ <tr>
+ <th field="name" style="width:50%">User</th>
+ <th field="authenticationProvider" style="width:50%">Authentication Provider</th>
+ </tr>
+ </thead>
+ </table>
+ <div class="dijitDialogPaneActionBar">
+ <button id="preferences.deletePreeferencesButton" data-dojo-type="dijit/form/Button" data-dojo-props="label:'Delete Preferences', title:'Delete preferences for selected users'">Delete Preferences</button>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferencesProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferencesProvider.html
new file mode 100644
index 0000000000..a1885acddf
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPreferencesProvider.html
@@ -0,0 +1,40 @@
+<!--
+ -
+ - 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="preferencesProvider">
+ <div class="preferencesProviderAttributes">
+ <div style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 100px;">Type:</div>
+ <div class="preferencesProviderType" style="float:left;"></div>
+ </div>
+ <div style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 100px;">Name:</div>
+ <div class="preferencesProviderName" style="float:left;"></div>
+ </div>
+ <div style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 100px;">State:</div>
+ <div class="preferencesProviderState" style="float:left;"></div>
+ </div>
+ <div class="preferencesDetails"></div>
+ </div>
+ <br/>
+ <button data-dojo-type="dijit.form.Button" class="deletePreferencesProviderButton">Delete</button>
+ <button data-dojo-type="dijit.form.Button" class="editPreferencesProviderButton">Edit</button>
+</div> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/memory/add.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/memory/add.html
deleted file mode 100644
index e69de29bb2..0000000000
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/memory/add.html
+++ /dev/null
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/pool/none/add.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/pool/none/add.html
deleted file mode 100644
index e69de29bb2..0000000000
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/store/pool/none/add.html
+++ /dev/null
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementTest.java
index 18d774e341..d0a357fd28 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementTest.java
@@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.test.utils.QpidTestCase;
@@ -88,13 +89,13 @@ public class HttpManagementTest extends QpidTestCase
_management.isHttpBasicAuthenticationEnabled());
}
- public void testGetSubjectCreator()
+ public void testGetAuthenticationProvider()
{
SocketAddress localAddress = InetSocketAddress.createUnresolved("localhost", 8080);
- SubjectCreator subjectCreator = mock(SubjectCreator.class);
- when(_broker.getSubjectCreator(localAddress)).thenReturn(subjectCreator);
- SubjectCreator httpManagementSubjectCreator = _management.getSubjectCreator(localAddress);
- assertEquals("Unexpected subject creator", subjectCreator, httpManagementSubjectCreator);
+ AuthenticationProvider brokerAuthenticationProvider = mock(AuthenticationProvider.class);
+ when(_broker.getAuthenticationProvider(localAddress)).thenReturn(brokerAuthenticationProvider);
+ AuthenticationProvider authenticationProvider = _management.getAuthenticationProvider(localAddress);
+ assertEquals("Unexpected subject creator", brokerAuthenticationProvider, authenticationProvider);
}
}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/log/LogFileHelperTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/log/LogFileHelperTest.java
new file mode 100644
index 0000000000..608ef28f02
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/log/LogFileHelperTest.java
@@ -0,0 +1,339 @@
+/*
+ *
+ * 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.log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.DailyRollingFileAppender;
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.QpidCompositeRollingAppender;
+import org.apache.log4j.RollingFileAppender;
+import org.apache.log4j.varia.ExternallyRolledFileAppender;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.test.utils.TestFileUtils;
+import org.apache.qpid.util.FileUtils;
+
+public class LogFileHelperTest extends QpidTestCase
+{
+ private Map<String, List<File>> _appendersFiles;
+ private File _compositeRollingAppenderBackupFolder;
+ private List<Appender> _appenders;
+ private LogFileHelper _helper;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _appendersFiles = new HashMap<String, List<File>>();
+ _compositeRollingAppenderBackupFolder = new File(TMP_FOLDER, "_compositeRollingAppenderBackupFolder");
+ _compositeRollingAppenderBackupFolder.mkdirs();
+
+ _appendersFiles.put(FileAppender.class.getSimpleName(),
+ Collections.singletonList(TestFileUtils.createTempFile(this, ".log", "FileAppender")));
+ _appendersFiles.put(DailyRollingFileAppender.class.getSimpleName(),
+ Collections.singletonList(TestFileUtils.createTempFile(this, ".log", "DailyRollingFileAppender")));
+ _appendersFiles.put(RollingFileAppender.class.getSimpleName(),
+ Collections.singletonList(TestFileUtils.createTempFile(this, ".log", "RollingFileAppender")));
+ _appendersFiles.put(ExternallyRolledFileAppender.class.getSimpleName(),
+ Collections.singletonList(TestFileUtils.createTempFile(this, ".log", "ExternallyRolledFileAppender")));
+
+ File file = TestFileUtils.createTempFile(this, ".log", "QpidCompositeRollingAppender");
+ File backUpFile = File.createTempFile(file.getName() + ".", ".1." + LogFileHelper.GZIP_EXTENSION);
+ _appendersFiles.put(QpidCompositeRollingAppender.class.getSimpleName(), Arrays.asList(file, backUpFile));
+
+ FileAppender fileAppender = new FileAppender();
+ DailyRollingFileAppender dailyRollingFileAppender = new DailyRollingFileAppender();
+ RollingFileAppender rollingFileAppender = new RollingFileAppender();
+ ExternallyRolledFileAppender externallyRolledFileAppender = new ExternallyRolledFileAppender();
+ QpidCompositeRollingAppender qpidCompositeRollingAppender = new QpidCompositeRollingAppender();
+ qpidCompositeRollingAppender.setbackupFilesToPath(_compositeRollingAppenderBackupFolder.getPath());
+
+ _appenders = new ArrayList<Appender>();
+ _appenders.add(fileAppender);
+ _appenders.add(dailyRollingFileAppender);
+ _appenders.add(rollingFileAppender);
+ _appenders.add(externallyRolledFileAppender);
+ _appenders.add(qpidCompositeRollingAppender);
+
+ for (Appender appender : _appenders)
+ {
+ FileAppender fa = (FileAppender) appender;
+ fa.setName(fa.getClass().getSimpleName());
+ fa.setFile(_appendersFiles.get(fa.getClass().getSimpleName()).get(0).getPath());
+ }
+
+ _helper = new LogFileHelper(_appenders);
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ for (List<File> files : _appendersFiles.values())
+ {
+ for (File file : files)
+ {
+ try
+ {
+ FileUtils.delete(file, false);
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ }
+ }
+ FileUtils.delete(_compositeRollingAppenderBackupFolder, true);
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testGetLogFileDetailsWithLocations() throws Exception
+ {
+ List<LogFileDetails> details = _helper.getLogFileDetails(true);
+
+ assertLogFiles(details, true);
+ }
+
+ public void testGetLogFileDetailsWithoutLocations() throws Exception
+ {
+ List<LogFileDetails> details = _helper.getLogFileDetails(false);
+
+ assertLogFiles(details, false);
+ }
+
+ public void testWriteLogFilesForAllLogs() throws Exception
+ {
+ List<LogFileDetails> details = _helper.getLogFileDetails(true);
+ File f = TestFileUtils.createTempFile(this, ".zip");
+
+ FileOutputStream os = new FileOutputStream(f);
+ try
+ {
+ _helper.writeLogFiles(details, os);
+ }
+ finally
+ {
+ if (os != null)
+ {
+ os.close();
+ }
+ }
+
+ assertWrittenFile(f, details);
+ }
+
+ public void testWriteLogFile() throws Exception
+ {
+ File file = _appendersFiles.get(FileAppender.class.getSimpleName()).get(0);
+
+ File f = TestFileUtils.createTempFile(this, ".log");
+ FileOutputStream os = new FileOutputStream(f);
+ try
+ {
+ _helper.writeLogFile(file, os);
+ }
+ finally
+ {
+ if (os != null)
+ {
+ os.close();
+ }
+ }
+
+ assertEquals("Unexpected log content", FileAppender.class.getSimpleName(), FileUtils.readFileAsString(f));
+ }
+
+ public void testFindLogFileDetails()
+ {
+ String[] logFileDisplayedPaths = new String[6];
+ File[] files = new File[logFileDisplayedPaths.length];
+ int i = 0;
+ for (Map.Entry<String, List<File>> entry : _appendersFiles.entrySet())
+ {
+ String appenderName = entry.getKey();
+ List<File> appenderFiles = entry.getValue();
+ for (File logFile : appenderFiles)
+ {
+ logFileDisplayedPaths[i] = appenderName + "/" + logFile.getName();
+ files[i++] = logFile;
+ }
+ }
+
+ List<LogFileDetails> logFileDetails = _helper.findLogFileDetails(logFileDisplayedPaths);
+ assertEquals("Unexpected details size", logFileDisplayedPaths.length, logFileDetails.size());
+
+ boolean gzipFileFound = false;
+ for (int j = 0; j < logFileDisplayedPaths.length; j++)
+ {
+ String displayedPath = logFileDisplayedPaths[j];
+ String[] parts = displayedPath.split("/");
+ LogFileDetails d = logFileDetails.get(j);
+ assertEquals("Unexpected name", parts[1], d.getName());
+ assertEquals("Unexpected appender", parts[0], d.getAppenderName());
+ if (files[j].getName().endsWith(LogFileHelper.GZIP_EXTENSION))
+ {
+ assertEquals("Unexpected mime type for gz file", LogFileHelper.GZIP_MIME_TYPE, d.getMimeType());
+ gzipFileFound = true;
+ }
+ else
+ {
+ assertEquals("Unexpected mime type", LogFileHelper.TEXT_MIME_TYPE, d.getMimeType());
+ }
+ assertEquals("Unexpecte file location", files[j], d.getLocation());
+ assertEquals("Unexpecte file size", files[j].length(), d.getSize());
+ assertEquals("Unexpecte file last modified date", files[j].lastModified(), d.getLastModified());
+ }
+ assertTrue("Gzip log file is not found", gzipFileFound);
+ }
+
+ public void testFindLogFileDetailsForNotExistingAppender()
+ {
+ String[] logFileDisplayedPaths = { "NotExistingAppender/qpid.log" };
+ List<LogFileDetails> details = _helper.findLogFileDetails(logFileDisplayedPaths);
+ assertTrue("No details should be created for non-existing appender", details.isEmpty());
+ }
+
+ public void testFindLogFileDetailsForNotExistingFile()
+ {
+ String[] logFileDisplayedPaths = { "FileAppender/qpid-non-existing.log" };
+ List<LogFileDetails> details = _helper.findLogFileDetails(logFileDisplayedPaths);
+ assertTrue("No details should be created for non-existing file", details.isEmpty());
+ }
+
+ public void testFindLogFileDetailsForIncorectlySpecifiedLogFilePath()
+ {
+ String[] logFileDisplayedPaths = { "FileAppender\\" + _appendersFiles.get("FileAppender").get(0).getName() };
+ try
+ {
+ _helper.findLogFileDetails(logFileDisplayedPaths);
+ fail("Exception is expected for incorectly set path to log file");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // pass
+ }
+ }
+
+ private void assertLogFiles(List<LogFileDetails> details, boolean includeLocation)
+ {
+ for (Map.Entry<String, List<File>> appenderData : _appendersFiles.entrySet())
+ {
+ String appenderName = (String) appenderData.getKey();
+ List<File> files = appenderData.getValue();
+
+ for (File logFile : files)
+ {
+ String logFileName = logFile.getName();
+ LogFileDetails d = findLogFileDetails(logFileName, appenderName, details);
+ assertNotNull("Log file " + logFileName + " is not found for appender " + appenderName, d);
+ if (includeLocation)
+ {
+ assertEquals("Log file " + logFileName + " is different in appender " + appenderName, d.getLocation(),
+ logFile);
+ }
+ }
+ }
+ }
+
+ private LogFileDetails findLogFileDetails(String logFileName, String appenderName, List<LogFileDetails> logFileDetails)
+ {
+ LogFileDetails d = null;
+ for (LogFileDetails lfd : logFileDetails)
+ {
+ if (lfd.getName().equals(logFileName) && lfd.getAppenderName().equals(appenderName))
+ {
+ d = lfd;
+ break;
+ }
+ }
+ return d;
+ }
+
+ private void assertWrittenFile(File f, List<LogFileDetails> details) throws FileNotFoundException, IOException
+ {
+ FileInputStream fis = new FileInputStream(f);
+ try
+ {
+ ZipInputStream zis = new ZipInputStream(fis);
+ ZipEntry ze = zis.getNextEntry();
+
+ while (ze != null)
+ {
+ String entryName = ze.getName();
+ String[] parts = entryName.split("/");
+
+ String appenderName = parts[0];
+ String logFileName = parts[1];
+
+ LogFileDetails d = findLogFileDetails(logFileName, appenderName, details);
+
+ assertNotNull("Unexpected entry " + entryName, d);
+ details.remove(d);
+
+ File logFile = d.getLocation();
+ String logContent = FileUtils.readFileAsString(logFile);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int len;
+ while ((len = zis.read(buffer)) > 0)
+ {
+ baos.write(buffer, 0, len);
+ }
+ baos.close();
+
+ assertEquals("Unexpected log file content", logContent, baos.toString());
+
+ ze = zis.getNextEntry();
+ }
+
+ zis.closeEntry();
+ zis.close();
+
+ }
+ finally
+ {
+ if (fis != null)
+ {
+ fis.close();
+ }
+ }
+ assertEquals("Not all log files have been output", 0, details.size());
+ }
+
+}